1

I'm running into problems when trying to populate a DB with tables (using Slick 2.0.0):

import scala.slick.driver.JdbcDriver
import scala.slick.lifted.TableQuery

case class DemoInit(slickDriver:JdbcDriver, tables:Seq[TableQuery[_]]) {
  lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

  import slickDriver.simple.{tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}

  def init() {
    db withSession { implicit session =>
      tables.map(_.ddl).reduce(_ ++ _).create
    }
  }
}

Attempting to compile the code above leads to the following two errors:

value ddl is not a member of scala.slick.lifted.TableQuery[_$1]

value create is not a member of scala.slick.lifted.TableQuery[_$1]

I'm guessing that the type parameters aren't being inferred correctly. What am I doing wrong?

Andrey
  • 8,882
  • 10
  • 58
  • 82

2 Answers2

3

You need to add the right constraint for the table type:

tables: Seq[TableQuery[_ <: Table[_]]]

In such cases where an implicit conversion that you expect is not taken, it helps to add an explicit call to this conversion. This will give you a better error message that explains why the conversion is not applicable.

Then you'll run into the next issue that you're using reduce wrong. You'll want to use something like tables.map(_.ddl).reduce(_ ++ _) instead.

Since Table is path-dependent you cannot use it with your setup that tries to pass everything to a class as parameters. While you are allowed to refer to path-dependent types from a previous argument list in a later argument list of a def, this is not possible in a class. You'll have to structure your code differently to get the path-dependent types right, e.g.:

  import scala.slick.driver.JdbcProfile

  class DemoDAO(val slickDriver: JdbcProfile) {
    import slickDriver.simple._
    lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

    def init(tables: Seq[TableQuery[_ <: Table[_]]]) {
      db withSession { implicit session =>
        tables.map(_.ddl).reduce(_ ++ _).create
      }
    }
  }
}
szeiger
  • 1,406
  • 9
  • 11
  • what is the full classname of `Table` ? – Andrey Jan 22 '14 at 15:20
  • thank you for catching the misuse of `reduce` (i updated my question). i've been wrestling with trying to get the types right for a while now. from what i can see, the `Table` type comes out of `RelationalProfile#SimpleQL#Table` but i still can't get it to work with the example i provided in the question. – Andrey Jan 23 '14 at 02:52
2

What I ended up doing was creating a new trait:

import scala.slick.driver.JdbcProfile

trait TablesSupplier {
  def tables(profile:JdbcProfile):Seq[JdbcProfile#SimpleQL#TableQuery[_ <: JdbcProfile#SimpleQL#Table[_]]]
}

I'm using Slick to generate the source code for table objects, so I have a Tables trait, which I use in the implementation of TablesSupplier:

import scala.slick.driver.JdbcProfile

object DemoTablesSupplier extends TablesSupplier {
  def tables(profile:JdbcProfile) = {
    val _profile = profile
    val demoTables = new Tables { val profile = _profile }
    import demoTables._
    Seq(Table1, Table2, Table3)
  }
}

So, my DemoInit now looks like this:

import scala.slick.driver.JdbcDriver

case class DemoInit(slickDriver:JdbcDriver, tables:Seq[TableQuery[_]]) {
  lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

  import slickDriver.simple.{tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}

  def init() {
    db withSession { implicit session =>
      val profile = slickDriver.profile
      //import the type of Table and TableQuery that are expected as well as two implicit methods that are necessary in order to use 'ddl' and 'create' methods
      import profile.simple.{Table, TableQuery, tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}
      //using asInstanceOf is very ugly but I couldn't figure out a better way
      val tables = tablesCreator.tables(profile).asInstanceOf[Seq[TableQuery[_ <: Table[_]]]]
      tables.map(_.ddl).reduce(_ ++ _).create
    }
  }
}
Andrey
  • 8,882
  • 10
  • 58
  • 82