Scala compiler does not report anything for general arguments

I'm trying something I saw in different forms in different contexts before: scala extension of query extensions with filterById(id: Id)

Here is what I tried:

 trait TableWithId { self: Profile => import profile.simple._ trait HasId[Id] { self: Table[_] => def id: Column[Id] } implicit class HasIdQueryExt[Id: BaseColumnType, U] (query: Query[Table[U] with HasId[Id], U]) { def filterById(id: Id)(implicit s: Session) = query.filter(_.id === id) def insertReturnId(m: U)(implicit s: Session): Id = query.returning(query.map(_.id)) += m } } 

It works great, there is no real magic. But since there is no type restriction in the table type, any query to which I apply filterById loses its specificity (now this is a common Table with HasId[Id] ), and I can no longer use it (except _.id of the course).

I do not know how to introduce this implicit conversion to prevent this. Is it possible? The following naive solution does not work, because scala does not write anything for type Id now:

 implicit class HasIdQueryExt[Id: BaseColumnType, U, T <: Table[U] with HasId[Id]] (query: Query[T, U]) { ... } 

It seems strange to me that suddenly the type Id is inferred as Nothing. How can I hint to the compiler where to look for this type of identifier?

+5
source share
1 answer

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] /** * generic methods */ 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]) } } /** * generic queries for any table which has id:Option[UUID] */ 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 } } 
0
source

Source: https://habr.com/ru/post/1203039/


All Articles