Search code examples
scalaslicktypesafe-activatorcode-generation

run slick-codegen-example with current versions


I am currently making my first steps with Slick. I am particularly interested in codegen. To get started I installed Typesafe Activator (activator-dist-1.3.7), started the Activator ui, created a new project from template "Using Slicks default code generator" (slick-codegen-example) and started it.

That went quite well and indeed generated source code. Opening Build.scala I noticed that the referenced versions are terribly outdated (e.g. using Scala 2.10.3 from 2013) . So I checked which are the current versions and replaced

      scalaVersion := "2.10.3",
  libraryDependencies ++= List(
    "com.typesafe.slick" %% "slick" % "2.1.0",
    "com.typesafe.slick" %% "slick-codegen" % "2.1.0-RC3",
    "org.slf4j" % "slf4j-nop" % "1.6.4",
    "com.h2database" % "h2" % "1.3.170"
  ),

in Build.scala with

      scalaVersion := "2.11.7",
  libraryDependencies ++= List(
    "com.typesafe.slick" %% "slick" % "3.1.1",
    "com.typesafe.slick" %% "slick-codegen" % "3.1.1",
    "org.slf4j" % "slf4j-nop" % "1.7.13",
    "com.h2database" % "h2" % "1.4.190"
  ),

Then I also updated the package names (Alex: thanks for the hint!) to make this build. I also added "if now exists" to the create tables sql code, because for some unknown reason, the db complained that the tables did already exist.

So the Tables.scala was finally created :) However, running the Example.scala with an example query does not output anything. After some research, I understood that this is because Slick 3 now works asynchronously. In some other example if have seen that db.run was wrapped inside an Await.result. So I tried this, which lead to a compile error:

value groupBy is not a member of (String, String)

What went wrong? How can I fix it? The query code now looks like this:

  val q = Companies.join(Computers).on(_.id === _.manufacturerId).map {
   case (co,cp) => (co.name, cp.name) }

  Await.result(db.run(q.result), Duration.Inf).foreach { result =>
    println(result.groupBy{ case (co,cp) => co }
            .mapValues(_.map{ case (co,cp) => cp })
            .mkString("\n")
          )
  }

Solution

  • Got this running :) Apart from changing the version numbers (see above) I had to:

    • remove the "scala." prefix from slick package names in Build.scala (thanks again, Alex)
    • change all "create table" to "create table if not exists" in create.sql
    • rewrite Example.scala:

      object Example extends App {
        // connection info for a pre-populated throw-away, in-memory db for this demo, which is freshly initialized on every run
        val url = "jdbc:h2:mem:test;INIT=runscript from 'src/main/sql/create.sql'"
        val db = Database.forURL(url, driver = "org.h2.Driver")
      
        // Using generated code. Our Build.sbt makes sure they are generated before compilation.
        val query = Companies.join(Computers).on(_.id === _.manufacturerId).map{ case (co,cp) => (co.name, cp.name) }
        val future = db.run(query.result)
      
        future onSuccess {  
          case result => println(result.groupBy{ case (co,cp) => co }
                                       .mapValues(_.map{ case (co,cp) => cp })
                                       .mkString("\n")
                                )
        }
        future onFailure {
          case t => println("Got an error: " + t.getMessage)
        }
        Thread.sleep(1000)    
      }