I am trying to write a generic CRUD trait for Slick 2.0. The trait should a) provide generic methods to read/update/delete entities as well as b) abstract from the database. Following this slick example (database abstraction) and this article (CRUD trait) I came up with the following (shortened) code snippet:
trait Profile {
val profile: JdbcProfile
}
trait Crud[T <: AbstractTable[A], A] { this: Profile =>
import profile.simple._
val qry: TableQuery[T]
def countAll()(implicit session: Session): Int = {
qry.length.run
}
def getAll()(implicit session: Session): List[A] = {
qry.list // <-- type mismatch; found: List[T#TableElementType] required: List[A]
}
}
The code is invalid due to a type mismatch. The return type of the 2nd function seems to be of type List[T#TableElementType]
but needs to be List[A]. Any ideas on how to solve the issue. Additional references to further readings on generic Slick 2.0 operations are welcome too.
type TableElementType
is abstract inside ofclass AbstractTable[A]
. Scala doesn't know about any relationship betweenA
andTableElementType
.class Table
on the other hand definesfinal type TableElementType = A
, which tells Scala about this relationship (and apparently Scala is smart enough to use thefinal
annotation to know that the relationanship even holds for a subtypeT <: Table[A]
eventhoughTable[A]
is not co-variant inA
).So you need to use
T <: Table[A]
instead ofT <: AbstractTable[A]
. And becauseTable
is inside the Slick driver cake (as in cake pattern), you need to move your Crud into your cake as well. Cakes are viral.