We'll be adding a feature to Bootzooka, a skeleton Scala microservice/web application project.
This will involve using doobie, monix, tapir, http4s, circe and compile-time dependency injection.
If you'd like to follow along:
def insertPerson(p: Person): ConnectionIO[Int] = | |
sql"INSERT INTO persons(name, age) VALUES(${p.name}, ${p.age})".update.run | |
def countPersons: ConnectionIO[Int] = | |
sql"SELECT COUNT(*) FROM persons".query[Int].unique | |
val insertAndCount = | |
insertPerson(Person("Pedro", 81)).flatMap(_ => countPersons) |
val transactor: Transactor[IO] = ??? | |
val result: IO[List[Person]] = personsQuery.transact(transactor) | |
val persons: List[Person] = result.unsafeRunSync() |
// details on creating a transactor are omitted | |
val transactor: Transactor[IO] = ??? | |
val result: IO[List[Person]] = personsQuery.transact(transactor) |
import doobie._ | |
import doobie.implicits._ | |
case class Person(name: String, age: Int) | |
val personsQuery: ConnectionIO[List[Person]] = | |
sql"SELECT p.name, p.age FROM persons p".query[Person].to[List] |
We'll be adding a feature to Bootzooka, a skeleton Scala microservice/web application project.
This will involve using doobie, monix, tapir, http4s, circe and compile-time dependency injection.
If you'd like to follow along:
val TestConfig: Config = DefaultConfig | |
.modify(_.email.emailSendInterval) | |
.setTo(100.milliseconds) |
def changePassword(userId: Id @@ User, | |
currentPassword: String, | |
newPassword: String): ConnectionIO[Unit] = | |
for { | |
user <- userOrNotFound(UserModel.findById(userId)) | |
_ <- verifyPassword(user, currentPassword) | |
_ = logger.debug(s"Changing password for user: $userId") | |
_ <- UserModel.updatePassword(userId, User.hashPassword(newPassword)) | |
} yield () |
object UserModel { | |
def findById(id: Id @@ User): ConnectionIO[Option[User]] = { | |
findBy(fr"id = $id") | |
} | |
def findByEmail(email: String @@ LowerCased): ConnectionIO[Option[User]] = { | |
findBy(fr"email_lowercase = $email") | |
} | |
private def findBy(by: Fragment): ConnectionIO[Option[User]] = { |
import io.circe.Decoder | |
import com.softwaremill.bootzooka.infrastructure.Json._ | |
case class Register_IN(login: String, email: String, password: String) | |
implicitly[Decoder[Register_IN]] |
import com.softwaremill.tagging.@@ | |
import io.circe.generic.AutoDerivation | |
import io.circe.java8.time.{JavaTimeDecoders, JavaTimeEncoders} | |
import io.circe.{Decoder, Encoder, Printer} | |
object Json extends AutoDerivation with JavaTimeDecoders with JavaTimeEncoders { | |
val noNullsPrinter: Printer = Printer.noSpaces.copy(dropNullValues = true) | |
implicit def taggedStringEncoder[U]: Encoder[String @@ U] = | |
Encoder.encodeString.asInstanceOf[Encoder[String @@ U]] |