underscoreio/slickless

Support for extensible records

rfuerst87 opened this issue · 3 comments

I've been playing around with slickless for the past few days. I'm particularly interested in getting extensible records to work with slick. A "record projection" would be a nice feature IMHO. Either by providing a RecordShape or by a MappedProjection.

class Users(tag: Tag) extends Table[Long :: String :: HNil](tag, "users") {
  def id    = column[Long]( "id", O.PrimaryKey, O.AutoInc )
  def email = column[String]("email")

  def * = ('id ->> id) :: ('email ->> email) :: HNil    // support by RecordShape
  // or
  def * = (id :: email :: HNil).mappedWithRecord('id :: 'email :: HNil)  // support by MappedProjection
}

As I just started my journey with shapeless, I could not get any of these two approaches to work. The closest I could come up with is a non working MappedProjection:

def mappedWithRecord[R <: HList : ClassTag, U <: HList, K <: HList](keys: K)
  (implicit
    shape: Shape[_ <: FlatShapeLevel, T, U, _]) =
  new MappedProjection[R, U](
    shape.toNode(hlist),
    MappedScalaType.Mapper(
      ((f: HList) => f.zipWithKeys(keys)).asInstanceOf[Any => Any], // compiler error: could not find implicit value for parameter withKeys: shapeless.ops.hlist.ZipWithKeys[K,shapeless.HList]

      ((g: HList) => ???).asInstanceOf[Any => Any],
      None
    ),
    implicitly[ClassTag[R]]
  )
}

So basically my two questions are:

  1. Would it even be possible to provide a RecordShape? Unfortunately I could not even figure out where to start...
  2. Why can't the compile find the implicit parameter withKeys in the code above? What am I missing?
d6y commented

Hello @rfuerst87 - just wanted to let you know that Dave, Miles, and I are mostly going to be tied up on work and conference preparation for a while. So just wanted to say hi 👋 and let you know we'll try to look into this, but it may be quiet for at least a couple of weeks.

Hi @d6y, no worries. I'd be super happy if you could look into this once you have some spare time. Meanwhile I'll post my progress here (if there is any).

d6y commented

I've been (manually) seeing what a simple record might look like with slickless in a branch. Nothing much to see: https://github.com/underscoreio/slickless/compare/feature/18-records-experiments (but everything is in RecordShapeSpec.scala)

From what I recall the mappedWith code uses existing case class mapping to do the work. I guess that could be an option for records too. I think it depends on what we want the T to be in a Slick Table[T]: a record? a case class? I've been assuming working in terms of records is the way forward, but that might be a false assumption.