Type Support

Saferis provides built-in support for common Scala and Java types.

java.time Types

All java.time types are supported with automatic SQL type mapping:

Scala TypePostgreSQL TypeJDBC Type
java.time.InstanttimestamptzTIMESTAMP_WITH_TIMEZONE
java.time.LocalDateTimetimestampTIMESTAMP
java.time.LocalDatedateDATE
java.time.LocalTimetimeTIME
java.time.ZonedDateTimetimestamptzTIMESTAMP_WITH_TIMEZONE
java.time.OffsetDateTimetimestamptzTIMESTAMP_WITH_TIMEZONE
xa
  .run(for
    _ <- ddl.createTable[Event](ifNotExists = true)
    _ <- dml.insert(
      Event(-1, "Conference", Instant.now(), Some(LocalDateTime.now().plusDays(7)), LocalDate.now())
    )
    _   <- dml.insert(Event(-1, "Meeting", Instant.now(), None, LocalDate.now().plusDays(1)))
    all <- sql"SELECT * FROM $events ORDER BY ${events.name}".query[Event]
    names = all.map(_.name) // project to names: stable output across runs
  yield names)
  .either
Right(Chunk(Conference,Meeting))

UUID Support

UUIDs can be used as primary keys:

xa
  .run(for
    _ <- ddl.createTable[Entity](ifNotExists = true)
    id1 = UUID.randomUUID()
    id2 = UUID.randomUUID()
    _     <- dml.insert(Entity(id1, "First Entity"))
    _     <- dml.insert(Entity(id2, "Second Entity"))
    found <- sql"SELECT * FROM $entities WHERE ${entities.id} = $id1".queryOne[Entity]
  yield found.map(_.name))
  .either
Right(Some(First Entity))

Other Supported Types

Scala TypePostgreSQL Type
Stringvarchar(255)
Intinteger
Longbigint
Doubledouble precision
Floatreal
Booleanboolean
BigDecimalnumeric
Option[T]Same as T, nullable

JSON/JSONB Support

Saferis provides Json[A] for storing arbitrary types as JSON in the database. This maps to JSONB in PostgreSQL and JSON in MySQL.

// Define a type to store as JSON - needs JsonCodec
case class Metadata(tags: List[String], version: Int) derives JsonCodec

// Use Json[A] wrapper in your table definition
@tableName("type_support_json_events")
case class JsonEvent(
  @generated @key id: Int,
  name: String,
  metadata: Json[Metadata]  // Stored as JSONB in PostgreSQL
) derives Table
xa
  .run(for
    _   <- ddl.createTable[JsonEvent](ifNotExists = true)
    _   <- dml.insert(JsonEvent(-1, "Deploy", Json(Metadata(List("prod", "release"), 1))))
    _   <- dml.insert(JsonEvent(-1, "Rollback", Json(Metadata(List("prod", "hotfix"), 2))))
    all <- sql"SELECT * FROM $jsonEvents ORDER BY ${jsonEvents.name}".query[JsonEvent]
  yield all)
  .either
Right(Chunk(JsonEvent(1,Deploy,Metadata(List(prod, release),1)),JsonEvent(2,Rollback,Metadata(List(prod, hotfix),2))))

The Json[A] wrapper:

  • Requires a zio.json.JsonCodec[A] instance for the wrapped type

  • Uses Types.OTHER JDBC type which maps to jsonb in PostgreSQL

  • Provides .value extension to unwrap: event.metadata.value returns Metadata