Alejandro Trujillo Caballero Alejandro Trujillo Caballero - 2 months ago 36
Scala Question

Generic table with slick

I'm trying to create a generic table abstract class that I can use to represent collections and reduce boilerplate.

This is my first try:

abstract class StringCollectionTable[A](tag: Tag,
name1: String, name2: String,
table: TableQuery[A], idMapper: A => Rep[Long])
extends Table[(Long, String)](tag, name1+"_"+name2) {

def id = column[Long]("ID_"+name1)
def item = column[String](name2)

def pk = primaryKey("pk_"+name1+"_"+name2, (id, item))

def idFK = foreignKey(name1 + "_FK", id, table)(idMapper, onUpdate=ForeignKeyAction.Restrict, onDelete=ForeignKeyAction.Cascade)

override def * : ProvenShape[(Long, String)] = (id, item)
}


And it is suposed to be used like:

case class Foo(...)
class FooTable(tag: Tag) extends Table[Foo](tag, "FOO") {...}
val foos = TableQuery[FooTable]
val mapToId = (t: TableQuery[FooTable]) => t.id


class FooBarTable(tag: Tag)
extends StringCollectionTable(tag, "FOO", "BAR", foos, mapToId)


So with this I can store a collection of bar-values related with one foo.

In IntellJ IDEA this code seems ok. But when I run the app I get the error:

inferred type arguments [slick.lifted.Rep[Long],Nothing,A,Nothing] do not conform to method foreignKey's type parameter bounds [P,PU,TT <: slick.lifted.AbstractTable[_],U]


In line:

def idFK = foreignKey(name1 + "_FK", id, table)(idMapper, onUpdate=ForeignKeyAction.Restrict, onDelete=ForeignKeyAction.Cascade)


I've been doing some search and I can't find the problem. It's my first Slick project and I'm a bit lost.

Someone can tell my the correct way of doing this?

Thanks!

Answer

type Parameter A should be subtype of Table implies A <: Table[_]

Declare your StringCollectionTable like this

abstract class StringCollectionTable[A <: Table[_]](tag: Tag, ...) extends ... {
  ...
  override def * = (id, item)
}
Comments