1

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?

Community
  • 1
  • 1
SkyWalker
  • 13,729
  • 18
  • 91
  • 187
  • As I demonstrated in your previous question, you can "clean up" the voodoo and imports with a custom typeclass. As to how you can avoid copying that implicit parameter I don't know. – Jasper-M Dec 08 '16 at 16:20
  • 2
    I am not sure if you can in scala 2, however the dotty team is addressing it Read http://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html – Qingwei Dec 08 '16 at 17:17
  • @Jasper-M thank you for commenting, yes you provided a solution but it doesn't match the OP e.g. `def copyWithId[ID, A](a: A, elem: ID)` is not the function signature I require for `AutoIncEntity` and so on. There are too many differences and I can't work out how to go from what you wrote to my OP. If you can really look at this OP signatures, names etc and provide an solution that match the OP and works then I will accept – SkyWalker Dec 08 '16 at 19:56

0 Answers0