This is my solution for a similar problem. I used a specific type for id though:
trait GenericComponent { this: Profile => import profile.simple._ abstract class TableWithId[A](tag:Tag, name:String) extends Table[A](tag:Tag, name) { def id = column[Option[UUID]]("id", O.PrimaryKey) } abstract class genericTable[T <: Table[A] , A] { val table: TableQuery[T] def insert(entry: A)(implicit session:Session): A = session.withTransaction { table += entry entry } def insertAll(entries: List[A])(implicit session:Session) = session.withTransaction { table.insertAll(entries:_*) } def all: List[A] = database.withSession { implicit session => table.list.map(_.asInstanceOf[A]) } } abstract class genericTableWithId[T <: TableWithId[A], A <:ObjectWithId ] extends genericTable[T, A] { def forIds(ids:List[UUID]): List[A] = database.withSession { implicit session => ids match { case Nil => Nil case x::xs =>table.filter(_.id inSet(ids)).list.map(_.asInstanceOf[A]) } } def forId(id:UUID):Option[A] = database.withSession { implicit session =>table.filter(_.id === id).firstOption } } }
and then for your specific component:
case class SomeObjectRecord( override val id:Option[UUID] = None, name:String) extends ObjectWithId(id){ // your function definitions there } trait SomeObjectComponent extends GenericComponent { this: Profile => import profile.simple._ class SomeObjects(tag: Tag) extends TableWithId[SomeObjectRecord](tag, "some_objects") { def name = column[String]("name", O.NotNull) def * = (id, name) <> (SomeObjectRecord.tupled, SomeObjectRecord.unapply) def nameIdx = index("u_name", (name), unique = true) } object someobjects extends genericTableWithId[SomeObjects, SomeObjectRecord] { val table = TableQuery[Units] // your additional methods there; you get insert and insertAll from the parent } }
source share