This Question is a consequence of the Question How to define an abstract copyable superclass for any case class but one can leave that context alone and focus on this:
NOTE: The whole compiling code base (with Scala 2.11.8) can be accessed in github play-authenticate-usage-scala
I have a trait that use shapeless and is defined as (note the implicit mkLens
):
import shapeless._, tag.@@
import shapeless._
import tag.$at$at
trait AutoIncEntity[PK, E <: AutoIncEntity[PK, E]] extends Entity[PK] { self: E =>
def copyWithNewId(id : PK)(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.`"id"`.T, PK]) : E = {
(lens[E] >> 'id).set(self)(id)
}
}
All the complexity is basically to say: Any case class (like those Rows auto-generated by Slick) by extending this trait, offer a base reusable implementation of copyWithNewId(id)
. This method simply delegates to the copy(id = id)
method which is case class compiler generated and can not be abstracted away or "pulled up". For example, UserRow
by extending AutoIncEntity
can be used as part of a framework that builds on top of AutoIncEntity
:
case class UserRow(id: Long, firstName: Option[String] = None,
middleName: Option[String] = None, lastName: Option[String] = None)
extends AutoIncEntity[Long, UserRow]
Now I use AutoIncEntity
to build a generic Dao that inserts a new record and at the same time fetches the user entity from the database including the new auto generated id
:
abstract class GenericDaoAutoIncImpl[T <: Table[E] with IdentifyableTable[PK], E <: AutoIncEntity[PK, E], PK: BaseColumnType]
(dbConfigProvider: DatabaseConfigProvider, tableQuery: TableQuery[T]) extends GenericDaoImpl[T, E, PK](dbConfigProvider, tableQuery)
with GenericDaoAutoInc[T, E, PK] {
override def createAndFetch(entity: E)(implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.`"id"`.T, PK]): Future[Option[E]] = {
val insertQuery = tableQuery returning tableQuery.map(_.id) into ((row, id) => row.copyWithNewId(id))
db.run((insertQuery += entity).flatMap(row => findById(row.id)))
}
}
Now the question is how can I modify this solution to avoid propagating/copy-pasting the "voodoo" implicit parameter (implicit mkLens: MkFieldLens.Aux[E, Symbol @@ Witness.
"id".T, PK])
? and the corresponding needed "voodoo" imports?