5

I'm trying to generate the Scala code for the database tables and views in my schema using Slick 3.0.3. Taking this blog as example I have the following file build.sbt. However, this will generate code for my database tables and will not include the database views. How can I get the views generated as well?

According to slick issue 1022 I see it is possible to do but the API doesn't look alike and slick.codegen.SourceCodeGenerator doesn't have a getTables or defaultTables to include view names.

name := "slickCodeGen"

version := "1.0"

scalaVersion := "2.11.6"

scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")

libraryDependencies ++= Seq(
  "com.typesafe.slick" %% "slick" % "3.0.3",
  "com.typesafe.slick" %% "slick-codegen" % "3.0.3",
  "org.postgresql" %  "postgresql" % "9.4-1201-jdbc41",
  "com.zaxxer" % "HikariCP" % "2.3.2",
  "org.scalatest" %% "scalatest" % "2.2.4" % "test"
)

slick <<= slickCodeGenTask

sourceGenerators in Compile <+= slickCodeGenTask

lazy val slick = TaskKey[Seq[File]]("gen-tables")
lazy val slickCodeGenTask = (sourceManaged, dependencyClasspath in Compile, runner in Compile, streams) map { (dir, cp, r, s) =>
  val outputDir = (dir / "main/slick").getPath
  val username = "postgres"
  val password = "xxx"
  val url = "jdbc:postgresql://localhost:5555/testdb?searchpath=public"
  val jdbcDriver = "com.postgresql.jdbc.Driver"
  val slickDriver = "slick.driver.PostgresDriver"
  val pkg = "folder1.folder2"
  toError(r.run("slick.codegen.SourceCodeGenerator", cp.files, Array(slickDriver, jdbcDriver, url, outputDir, pkg, username, password), s.log))
  val fname = outputDir + "/folder1/folder2/" + "Tables.scala"
  Seq(file(fname))
}
SkyWalker
  • 13,729
  • 18
  • 91
  • 187
  • Honestly - I haven't had much success with Slick-driven DDL that would include views. I ended up specifying views in raw SQL and just mapping them onto classes. I'm anxious to see if you're going to get any replies. – Patryk Ćwiek Sep 24 '15 at 08:24

1 Answers1

7

After a lot of trial and error due to the many changes in the Slick generator API the following standalone application Generator.scala tested will generate the code for both tables and views under Slick 3.0.3:

import java.util.concurrent.TimeUnit

import slick.driver.PostgresDriver
import slick.jdbc.meta.MTable
import slick.codegen.SourceCodeGenerator
import slick.driver.PostgresDriver.simple._
import play.api.libs.concurrent.Execution.Implicits._

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}

object Generator extends App {
  val slickDriver = "slick.driver.PostgresDriver"
  val jdbcDriver = "org.postgresql.Driver"
  val url = "jdbc:postgresql://localhost:5555/testdb?searchpath=public"
  val outputDir = "/tmp/"
  val pkg = "folder1.folder2"
  val username = "postgres"
  val password = "xxx"

  val db = Database.forURL(url, user, password)
  val dbio = PostgresDriver.createModel(Some(MTable.getTables(None, None, None, Some(Seq("TABLE", "VIEW")))))
  val model = db.run(dbio)
  val future : Future[SourceCodeGenerator] = model.map(model => new SourceCodeGenerator(model))
  val codegen : SourceCodeGenerator = Await.result(future, Duration.create(5, TimeUnit.MINUTES))
  codegen.writeToFile(slickDriver, outputDir, pkg, "Tables", "Tables.scala")
}

Integrating this code into a build.sbt is not that easy because requires defining an external custom code generator file and then compiling and running it from the build.sbt before the actual project is compiled. A very outdated example of this can be found in the github project slick-codegen-customization-example but note that they don't have a build.sbt but a more advanced Build.scala

SkyWalker
  • 13,729
  • 18
  • 91
  • 187
  • 2
    I had managed to get pretty far on my own, but when I had seen other usages of MTable I was sure that `Seq("TABLE","VIEW")` was just a placeholder for the actual names of tables and views you wanted to include, but no it's meta-data. There's an hour I won't get back. – Ahmad Ragab Feb 06 '16 at 21:42