Databases

Interpolated values become prepared-statement parameters (SQL-injection safe).

43.1 Doobie (JDBC, Cats Effect)

Interpolated values become prepared-statement parameters (SQL-injection safe). check queries against the schema in tests.

import doobie.*, doobie.implicits.*, cats.effect.IO

val xa = Transactor.fromDriverManager[IO](
  driver = "org.postgresql.Driver", url = "jdbc:postgresql:world", user = "postgres", password = "pw", logHandler = None)

case class Country(code: String, name: String, population: Long)

def bigCountries(min: Long): IO[List[Country]] =
  sql"SELECT code, name, population FROM country WHERE population > $min"
    .query[Country].to[List].transact(xa)

def insert(c: Country): ConnectionIO[Int] =
  sql"INSERT INTO country (code, name, population) VALUES (${c.code}, ${c.name}, ${c.population})".update.run

43.2 Skunk (pure Postgres protocol, no JDBC)

val q: Query[String, String] = sql"SELECT name FROM country WHERE code = $varchar".query(varchar)
session.prepare(q).flatMap(_.unique("NOR"))

43.3 Slick (Lightbend) — functional relational mapping

class Users(tag: Tag) extends Table[(Int, String)](tag, "users"):
  def id = column[Int]("id", O.PrimaryKey)
  def name = column[String]("name")
  def * = (id, name)
val users = TableQuery[Users]
db.run(users.filter(_.name like "A%").result)

43.4 Quill, Magnum, ScalikeJDBC

Quill / ProtoQuill — compile-time generated SQL from Scala collection-like queries.

Magnum — simple, fast, Scala 3-first JDBC library.

ScalikeJDBC — SQL-centric, mature.

NoSQL: ReactiveMongo, mongo-scala-driver, phantom (Cassandra), redis4cats, elastic4s.

43.5 Migrations

Flyway or Liquibase (Java libraries), invoked at startup or via sbt plugins.