Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Shapeless: derive JDBC Results for arbitrary case classes
import shapeless._ // requires.shapeless
import cats._, implicits._, data.Kleisli // requires.cats
import cats.sequence._ //requires kittens
import cats.effect.IO //requires cats-effect
// ofc, uses "-Ypartial-unification" and kind-projector
case class Result() // replace with the JDBC equivalent
case class DB(val r: Result) {
def nextInt: IO[Int] = ??? //IO(g.nextInt)
def nextDouble: IO[Double] = ???
def nextFloat: IO[Float] = ???
}
trait Results[I] {
type Out
def value: Out
}
object Results {
def of[T](implicit ev: Results[T]): ev.Out = ev.value
type Aux[I, O] = Results[I] { type Out = O }
def instance[I, O](v: O): Results.Aux[I, O] = new Results[I] {
type Out = O
def value = v
}
implicit def ints: Results.Aux[Int, Kleisli[IO, DB, Int]] =
instance(Kleisli(r => r.nextInt))
implicit def doubles: Results.Aux[Double, Kleisli[IO, DB, Double]] =
instance(Kleisli(r => r.nextDouble))
implicit def floats: Results.Aux[Float, Kleisli[IO, DB, Float]] =
instance(Kleisli(r => r.nextFloat))
implicit def hnil: Results.Aux[HNil, HNil] = instance(HNil)
implicit def hcons[H, T <: HList, R <: HList, O](
implicit g: Lazy[Results.Aux[H, O]],
n: Results.Aux[T, R]): Results.Aux[H :: T, O :: R] =
instance(g.value.value :: n.value)
implicit def gen[T, L <: HList, O <: HList](
implicit gen: Generic.Aux[T, L],
v: Lazy[Results.Aux[L, O]],
ev: Sequencer.Aux[O, Kleisli[IO, DB, ?], L]): Results.Aux[T, Kleisli[IO, DB, T]] =
instance(v.value.value.sequence.map(gen.from))
}
object Test {
case class Foo(a: Int, b: Double)
def db: DB = ???
val d: IO[Foo] = Results.of[Foo].run(db)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment