AugustNagro / magnum

A 'new look' for database access in Scala
Apache License 2.0
152 stars 10 forks source link

Could DbCodec be extendable? #5

Closed lbialy closed 1 year ago

lbialy commented 1 year ago

I think it would be massively helpful to have a capability to extend DbCodec built-in so that one can provide an isomorphism between a type for which a DbCodec instance already exists (e.g. DbCodec[String]) and a type that hasn't have an instance. As always - code is better than words so let me present the current workaround:

extension [E](codec: DbCodec[E])
  def bimap[E2](r: E => E2, w: E2 => E): DbCodec[E2] =
    new DbCodec[E2]:
      override def queryRepr: String = codec.queryRepr
      override def cols: IArray[Int] = codec.cols
      override def readSingle(resultSet: ResultSet, pos: Int): E2 = r(codec.readSingle(resultSet, pos))
      override def writeSingle(entity: E2, ps: PreparedStatement, pos: Int): Unit =
        val e2 = w(entity)
        codec.writeSingle(e2, ps, pos)

object opaques:
  opaque type TestOpaque = String
  object TestOpaque:
    def apply(value: String): TestOpaque             = value
    extension (opaque: TestOpaque) def value: String = opaque

given DbCodec[opaques.TestOpaque] = summon[DbCodec[String]].bimap(opaques.TestOpaque(_), _.value)

The instance for TestOpaque can be easily created by just calling bimap on existing instance and providing functions from String to TestOpaque and vice versa.

AugustNagro commented 1 year ago

That's a good idea, I would accept a PR to add biMap to DbCodec.