Last active
January 3, 2016 16:09
-
-
Save skinner/8487618 to your computer and use it in GitHub Desktop.
custom code generator for Slick 2.0.0-RC1 that puts tables in schemas into separate objects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package codegen | |
import scala.reflect.runtime.currentMirror | |
import scala.slick.driver.JdbcProfile | |
import scala.slick.jdbc.meta.{MTable, createModel} | |
import scala.slick.model.codegen.SourceCodeGenerator | |
import scala.slick.model.{Model, Table} | |
import java.io.File | |
import java.io.FileWriter | |
// NamespacedCodegen handles tables within schemas by namespacing them | |
// within objects here | |
// (e.g., table a.foo and table b.foo can co-exist, because this code | |
// generator places the relevant generated classes into separate | |
// objects--a "a" object, and a "b" object) | |
object NamespacedCodegen { | |
def main(args: Array[String]) = { | |
args.toList match { | |
case List(slickDriver, jdbcDriver, url, outputDir, pkg, schemaList, fname) => { | |
val driver: JdbcProfile = { | |
val module = currentMirror.staticModule(slickDriver) | |
val reflectedModule = currentMirror.reflectModule(module) | |
val driver = reflectedModule.instance.asInstanceOf[JdbcProfile] | |
driver | |
} | |
val schemas = schemaList.split(",").map({ | |
case "" => None | |
case (name: String) => Some(name) | |
}).toSet | |
var model = driver.simple.Database | |
.forURL(url, driver = jdbcDriver) | |
.withSession { implicit session => | |
val filteredTables = driver.getTables.list.filter( | |
(t: MTable) => schemas.contains(t.name.schema) | |
) | |
createModel(filteredTables, driver) | |
} | |
val codegen = new scala.slick.model.codegen.SourceCodeGenerator(model){ | |
override def code = { | |
//imports is copied right out of | |
//scala.slick.model.codegen.AbstractSourceCodeGenerator | |
var imports = | |
"import scala.slick.model.ForeignKeyAction\n" + | |
( if(tables.exists(_.hlistEnabled)){ | |
"import scala.slick.collection.heterogenous._\n"+ | |
"import scala.slick.collection.heterogenous.syntax._\n" | |
} else "" | |
) + | |
( if(tables.exists(_.PlainSqlMapper.enabled)){ | |
"import scala.slick.jdbc.{GetResult => GR}\n"+ | |
"// NOTE: GetResult mappers for plain SQL are only generated for tables where Slick knows how to map the types of all columns.\n" | |
} else "" | |
) + "\n\n" | |
val bySchema = tables.groupBy(t => { | |
t.model.name.schema | |
}) | |
val schemaFor = (schema: Option[String]) => { | |
bySchema(schema).sortBy(_.model.name.table).map( | |
_.code.mkString("\n") | |
).mkString("\n\n") | |
} | |
val schemata = schemas.toArray.sorted.map( | |
schema => schema match { | |
case Some(schemaName) => { | |
indent( | |
"object " + schemaName + " {\n" + schemaFor(schema) | |
) + "\n}\n" | |
} | |
case None => { | |
schemaFor(schema) | |
} | |
} | |
).mkString("\n\n") | |
imports + schemata | |
} | |
override def Table = new Table(_) { | |
table => | |
// customize foreign keys | |
override def ForeignKey = new ForeignKey(_) { | |
override def code = { | |
val fkColumns = compound(referencingColumns.map(_.name)) | |
// Add the schema name to qualify the referenced table name if: | |
// 1. it's in a different schema from referencingTable, and | |
// 2. it's not None | |
val qualifier = if (referencedTable.model.name.schema | |
!= referencingTable.model.name.schema) { | |
referencedTable.model.name.schema match { | |
case Some(schema) => schema + "." | |
case None => "" | |
} | |
} else { | |
"" | |
} | |
val qualifiedName = qualifier + referencedTable.TableValue.name | |
val pkColumns = compound(referencedColumns.map(c => s"r.${c.name}")) | |
s"""val $name = foreignKey("$dbName", $fkColumns, $qualifiedName)(r => $pkColumns, onUpdate=${onUpdate}, onDelete=${onDelete})""" | |
} | |
} | |
} | |
} | |
(new File(outputDir)).mkdirs() | |
val fw = new FileWriter(fname) | |
fw.write(codegen.packageCode(slickDriver, pkg)) | |
fw.close() | |
} | |
case _ => { | |
println(""" | |
Usage: NamespacedCodegen.main(Array( slickDriver, jdbcDriver, url, outputFolder, pkg, schemaList, fileName )) | |
slickDriver: Fully qualified name of Slick driver class, e.g. 'scala.slick.driver.PostgresDriver' | |
jdbcDriver: Fully qualified name of jdbc driver class, e.g. 'org.postgresql.Driver' | |
url: jdbc url, e.g. 'jdbc:postgresql://localhost/test' | |
outputFolder: Place where the package folder structure should be put | |
pkg: Scala package the generated code should be placed in | |
schemaList: string with comma-separated list of schemas to include | |
fName: name of output file | |
""".trim) | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment