aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStewart Stewart <stewinsalot@gmail.com>2016-11-22 13:49:22 -0500
committerStewart Stewart <stewinsalot@gmail.com>2016-11-22 13:49:22 -0500
commitf917786aee0b55e2a9cf7c1ecb7b5b3f25160ab9 (patch)
treeb3c160fd3b9b81fec386b2ffca6a95ace13d7de0 /src
parent484948d3aee517091eb513fd459201ed96211fc5 (diff)
downloadslick-codegen-plugin-f917786aee0b55e2a9cf7c1ecb7b5b3f25160ab9.tar.gz
slick-codegen-plugin-f917786aee0b55e2a9cf7c1ecb7b5b3f25160ab9.tar.bz2
slick-codegen-plugin-f917786aee0b55e2a9cf7c1ecb7b5b3f25160ab9.zip
add sbt-settings and lint/format
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/CodegenPlugin.scala30
-rw-r--r--src/main/scala/NamespacedCodegen.scala196
2 files changed, 149 insertions, 77 deletions
diff --git a/src/main/scala/CodegenPlugin.scala b/src/main/scala/CodegenPlugin.scala
index 98d832c..f9351c1 100644
--- a/src/main/scala/CodegenPlugin.scala
+++ b/src/main/scala/CodegenPlugin.scala
@@ -7,14 +7,26 @@ object CodegenPlugin extends AutoPlugin {
type TableColumn = (String, String)
object autoImport {
- lazy val codegenURI = SettingKey[String]("codegen-uri", "uri for the database configuration")
- lazy val codegenPackage = SettingKey[String]("codegen-package", "package in which to place generated code")
- lazy val codegenOutputPath = SettingKey[String]("codegen-output-path", "directory to with the generated code will be written")
- lazy val codegenSchemaWhitelist = SettingKey[List[String]]("codegen-schema-whitelist", "schemas and tables to process")
- lazy val codegenForeignKeys = SettingKey[Map[TableColumn, TableColumn]]("codegen-foreign-keys", "foreign key references to data models add manually")
- lazy val codegenSchemaBaseClassParts = SettingKey[List[String]]("codegen-schema-base-class-parts", "parts inherited by each generated schema object")
-
- lazy val slickCodeGenTask = TaskKey[Unit]("gen-tables", "generate the table definitions")
+ lazy val codegenURI =
+ SettingKey[String]("codegen-uri", "uri for the database configuration")
+ lazy val codegenPackage = SettingKey[String](
+ "codegen-package",
+ "package in which to place generated code")
+ lazy val codegenOutputPath = SettingKey[String](
+ "codegen-output-path",
+ "directory to with the generated code will be written")
+ lazy val codegenSchemaWhitelist = SettingKey[List[String]](
+ "codegen-schema-whitelist",
+ "schemas and tables to process")
+ lazy val codegenForeignKeys = SettingKey[Map[TableColumn, TableColumn]](
+ "codegen-foreign-keys",
+ "foreign key references to data models add manually")
+ lazy val codegenSchemaBaseClassParts = SettingKey[List[String]](
+ "codegen-schema-base-class-parts",
+ "parts inherited by each generated schema object")
+
+ lazy val slickCodeGenTask =
+ TaskKey[Unit]("gen-tables", "generate the table definitions")
}
@@ -39,8 +51,6 @@ object CodegenPlugin extends AutoPlugin {
)
}
}.value
-
)
-
}
diff --git a/src/main/scala/NamespacedCodegen.scala b/src/main/scala/NamespacedCodegen.scala
index 41905f0..dd2567f 100644
--- a/src/main/scala/NamespacedCodegen.scala
+++ b/src/main/scala/NamespacedCodegen.scala
@@ -1,12 +1,15 @@
import java.net.URI
-import java.io.{BufferedWriter, File, FileWriter}
import java.nio.file.Paths
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import slick.backend.DatabaseConfig
-import slick.codegen.{OutputHelpers, SourceCodeGenerator, StringGeneratorHelpers}
+import slick.codegen.{
+ OutputHelpers,
+ SourceCodeGenerator,
+ StringGeneratorHelpers
+}
import slick.dbio.DBIO
import slick.driver.JdbcProfile
import slick.jdbc.meta.MTable
@@ -15,20 +18,36 @@ import slick.model.{Column, Model, Table}
object Generator {
-
- def run(uri: URI, pkg: String, schemaNames: Option[List[String]], outputPath: String, manualForeignKeys: Map[(String, String), (String, String)], schemaBaseClass: String) = {
- val dc: DatabaseConfig[JdbcProfile] = DatabaseConfig.forURI[JdbcProfile](uri)
- val parsedSchemasOpt: Option[Map[String, List[String]]] = schemaNames.map(SchemaParser.parse)
- val dbModel: Model = Await.result(dc.db.run(SchemaParser.createModel(dc.driver, parsedSchemasOpt)), Duration.Inf)
-
- val generator = new Generator(uri, pkg, dbModel, outputPath, manualForeignKeys, schemaBaseClass)
- val generatedCode = generator.code
- parsedSchemasOpt.getOrElse(Map()).keys.map(schemaName => FileHelpers.schemaOutputPath(outputPath, schemaName))
+ def run(uri: URI,
+ pkg: String,
+ schemaNames: Option[List[String]],
+ outputPath: String,
+ manualForeignKeys: Map[(String, String), (String, String)],
+ schemaBaseClass: String) = {
+ val dc: DatabaseConfig[JdbcProfile] =
+ DatabaseConfig.forURI[JdbcProfile](uri)
+ val parsedSchemasOpt: Option[Map[String, List[String]]] =
+ schemaNames.map(SchemaParser.parse)
+ val dbModel: Model = Await.result(
+ dc.db.run(SchemaParser.createModel(dc.driver, parsedSchemasOpt)),
+ Duration.Inf)
+
+ val generator = new Generator(uri,
+ pkg,
+ dbModel,
+ outputPath,
+ manualForeignKeys,
+ schemaBaseClass)
+ parsedSchemasOpt
+ .getOrElse(Map())
+ .keys
+ .map(schemaName => FileHelpers.schemaOutputPath(outputPath, schemaName))
}
}
-class PackageNameGenerator(pkg: String, dbModel: Model) extends SourceCodeGenerator(dbModel) {
+class PackageNameGenerator(pkg: String, dbModel: Model)
+ extends SourceCodeGenerator(dbModel) {
override def code: String =
s"""
|// format: OFF
@@ -38,7 +57,6 @@ class PackageNameGenerator(pkg: String, dbModel: Model) extends SourceCodeGenera
|""".stripMargin
}
-
class ImportGenerator(dbModel: Model) extends SourceCodeGenerator(dbModel) {
val baseImports: String =
s"""
@@ -64,10 +82,18 @@ class ImportGenerator(dbModel: Model) extends SourceCodeGenerator(dbModel) {
|""".stripMargin
else ""
- override def code: String = baseImports + hlistImports + plainSqlMapperImports
+ override def code: String =
+ baseImports + hlistImports + plainSqlMapperImports
}
-class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manualForeignKeys: Map[(String, String), (String, String)], schemaBaseClass: String) extends SourceCodeGenerator(dbModel) with OutputHelpers {
+class Generator(uri: URI,
+ pkg: String,
+ dbModel: Model,
+ outputPath: String,
+ manualForeignKeys: Map[(String, String), (String, String)],
+ schemaBaseClass: String)
+ extends SourceCodeGenerator(dbModel)
+ with OutputHelpers {
val packageName = new PackageNameGenerator(pkg, dbModel).code
val allImports: String = new ImportGenerator(dbModel).code
@@ -76,15 +102,19 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
val sortedSchemaTables: List[(String, Seq[TableDef])] = tables
.groupBy(t => t.model.name.schema.getOrElse("`public`"))
- .toList.sortBy(_._1)
-
+ .toList
+ .sortBy(_._1)
val schemata: String = sortedSchemaTables.map {
case (schemaName, tableDefs) =>
- val tableCode = tableDefs.sortBy(_.model.name.table).map(_.code.mkString("\n")) .mkString("\n\n")
+ val tableCode = tableDefs
+ .sortBy(_.model.name.table)
+ .map(_.code.mkString("\n"))
+ .mkString("\n\n")
val generatedSchema = s"""
|object ${schemaName} extends $schemaBaseClass {
- | override val database = xyz.driver.core.database.Database.fromConfig("${uri.getFragment()}")
+ | override val database = xyz.driver.core.database.Database.fromConfig("${uri
+ .getFragment()}")
| import database.profile.api._
| ${tableCode}
|
@@ -104,11 +134,11 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
allImports + schemata
}
-
override def Table = new Table(_) { table =>
// need this in order to use our own TableClass generator
- override def definitions = Seq[Def]( EntityTypeRef, PlainSqlMapper, TableClassRef, TableValue )
+ override def definitions =
+ Seq[Def](EntityTypeRef, PlainSqlMapper, TableClassRef, TableValue)
def TableClassRef = new TableClass() {
// We disable the option mapping, as it is a bit more complex to support and we don't appear to need it
@@ -122,37 +152,44 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
override def mappingEnabled: Boolean = true
// create case class from colums
- override def factory: String =
- if(!hlistEnabled) super.factory
- else {
- val args = columns.zipWithIndex.map("a"+_._2)
- val hlist = args.mkString("::") + ":: HNil"
- val hlistType = columns.map(_.actualType).mkString("::") + ":: HNil.type"
- s"((h : $hlistType) => h match {case $hlist => ${TableClass.elementType}(${args.mkString(",")})})"
- }
+ override def factory: String =
+ if (!hlistEnabled) super.factory
+ else {
+ val args = columns.zipWithIndex.map("a" + _._2)
+ val hlist = args.mkString("::") + ":: HNil"
+ val hlistType = columns
+ .map(_.actualType)
+ .mkString("::") + ":: HNil.type"
+ s"((h : $hlistType) => h match {case $hlist => ${TableClass.elementType}(${args.mkString(",")})})"
+ }
// from case class create columns
override def extractor: String =
- if(!hlistEnabled) super.extractor
- else s"(a : ${TableClass.elementType}) => Some(" + columns.map("a."+_.name ).mkString("::") + ":: HNil)"
-
+ if (!hlistEnabled) super.extractor
+ else
+ s"(a : ${TableClass.elementType}) => Some(" + columns
+ .map("a." + _.name)
+ .mkString("::") + ":: HNil)"
def EntityTypeRef = new EntityTypeDef {
- override def code: String = (if (classEnabled) "final " else "") + super.code
+ override def code: String =
+ (if (classEnabled) "final " else "") + super.code
}
- override def Column = new Column(_) {
- column =>
+ override def Column = new Column(_) { column =>
- val manualReferences = SchemaParser.references(dbModel, manualForeignKeys)
+ val manualReferences =
+ SchemaParser.references(dbModel, manualForeignKeys)
// work out the destination of the foreign key
- def derefColumn(table: sModel.Table, column: sModel.Column): (sModel.Table, sModel.Column) = {
- val referencedColumn: Seq[(sModel.Table, sModel.Column)] = table.foreignKeys
- .filter(tableFk => tableFk.referencingColumns.forall(_ == column))
- .filter(columnFk => columnFk.referencedColumns.length == 1)
- .flatMap(_.referencedColumns
- .map(c => (dbModel.tablesByName(c.table), c)))
+ def derefColumn(table: sModel.Table,
+ column: sModel.Column): (sModel.Table, sModel.Column) = {
+ val referencedColumn: Seq[(sModel.Table, sModel.Column)] =
+ table.foreignKeys
+ .filter(tableFk => tableFk.referencingColumns.forall(_ == column))
+ .filter(columnFk => columnFk.referencedColumns.length == 1)
+ .flatMap(_.referencedColumns.map(c =>
+ (dbModel.tablesByName(c.table), c)))
assert(referencedColumn.distinct.length <= 1, referencedColumn)
referencedColumn.headOption
@@ -164,13 +201,15 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
// re-write ids, and time types
override def rawType: String = {
val (t, c) = derefColumn(table.model, column.model)
- if (c.options.contains(slick.ast.ColumnOption.PrimaryKey)) TypeGenerator.idType(pkg, t)
- else model.tpe match {
- // TODO: There should be a way to add adhoc custom time mappings
- case "java.sql.Time" => "xyz.driver.core.time.Time"
- case "java.sql.Timestamp" => "xyz.driver.core.time.Time"
- case _ => super.rawType
- }
+ if (c.options.contains(slick.ast.ColumnOption.PrimaryKey))
+ TypeGenerator.idType(pkg, t)
+ else
+ model.tpe match {
+ // TODO: There should be a way to add adhoc custom time mappings
+ case "java.sql.Time" => "xyz.driver.core.time.Time"
+ case "java.sql.Timestamp" => "xyz.driver.core.time.Time"
+ case _ => super.rawType
+ }
}
}
@@ -178,12 +217,22 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
override def code = {
val fkColumns = compoundValue(referencingColumns.map(_.name))
val qualifier =
- if (referencedTable.model.name.schema == referencingTable.model.name.schema) ""
- else referencedTable.model.name.schema.fold("")(sname => s"$pkg.$sname.")
+ if (referencedTable.model.name.schema == referencingTable.model.name.schema)
+ ""
+ else
+ referencedTable.model.name.schema.fold("")(sname =>
+ s"$pkg.$sname.")
val qualifiedName = qualifier + referencedTable.TableValue.name
- val pkColumns = compoundValue(referencedColumns.map(c => s"r.${c.name}${if (!c.model.nullable && referencingColumns.forall(_.model.nullable)) ".?" else ""}"))
- val fkName = referencingColumns.map(_.name).flatMap(_.split("_")).map(_.capitalize).mkString.uncapitalize + "Fk"
+ val pkColumns = compoundValue(referencedColumns.map(c =>
+ s"r.${c.name}${if (!c.model.nullable && referencingColumns.forall(_.model.nullable)) ".?"
+ else ""}"))
+ val fkName = referencingColumns
+ .map(_.name)
+ .flatMap(_.split("_"))
+ .map(_.capitalize)
+ .mkString
+ .uncapitalize + "Fk"
s"""lazy val $fkName = foreignKey("$dbName", $fkColumns, $qualifiedName)(r => $pkColumns, onUpdate=$onUpdate, onDelete=$onDelete)"""
}
}
@@ -193,32 +242,46 @@ class Generator(uri: URI, pkg: String, dbModel: Model, outputPath: String, manua
}
object SchemaParser {
- def references(dbModel: Model, tcMappings: Map[(String, String), (String, String)]): Map[(String, String), (Table, Column)] = {
- def getTableColumn(tc: (String, String)) : (Table, Column) = {
+ def references(dbModel: Model,
+ tcMappings: Map[(String, String), (String, String)])
+ : Map[(String, String), (Table, Column)] = {
+ def getTableColumn(tc: (String, String)): (Table, Column) = {
val (tableName, columnName) = tc
- val table = dbModel.tables.find(_.name.asString == tableName)
+ val table = dbModel.tables
+ .find(_.name.asString == tableName)
.getOrElse(throw new RuntimeException("No table " + tableName))
- val column = table.columns.find(_.name == columnName)
- .getOrElse(throw new RuntimeException("No column " + columnName + " in table " + tableName))
+ val column = table.columns
+ .find(_.name == columnName)
+ .getOrElse(throw new RuntimeException(
+ "No column " + columnName + " in table " + tableName))
(table, column)
}
- tcMappings.map{case (from, to) => ({getTableColumn(from); from}, getTableColumn(to))}
+ tcMappings.map {
+ case (from, to) => ({ getTableColumn(from); from }, getTableColumn(to))
+ }
}
def parse(schemaTableNames: List[String]): Map[String, List[String]] =
- schemaTableNames.map(_.split('.'))
+ schemaTableNames
+ .map(_.split('.'))
.groupBy(_.head)
.mapValues(_.flatMap(_.tail))
- def createModel(jdbcProfile: JdbcProfile, mappedSchemasOpt: Option[Map[String, List[String]]]): DBIO[Model] = {
+ def createModel(
+ jdbcProfile: JdbcProfile,
+ mappedSchemasOpt: Option[Map[String, List[String]]]): DBIO[Model] = {
val allTables: DBIO[Vector[MTable]] = MTable.getTables
- val filteredTables = mappedSchemasOpt.map(mappedSchemas =>
- allTables.map(
- (tables: Vector[MTable]) => tables.filter(table =>
- table.name.schema.flatMap(mappedSchemas.get).exists(ts =>
- ts.isEmpty || ts.contains(table.name.name)))))
+ val filteredTables = mappedSchemasOpt.map(
+ mappedSchemas =>
+ allTables.map(
+ (tables: Vector[MTable]) =>
+ tables.filter(
+ table =>
+ table.name.schema
+ .flatMap(mappedSchemas.get)
+ .exists(ts => ts.isEmpty || ts.contains(table.name.name)))))
jdbcProfile.createModel(filteredTables orElse Some(allTables))
}
@@ -236,7 +299,6 @@ object TypeGenerator extends StringGeneratorHelpers {
}
}
-
object FileHelpers {
def schemaOutputPath(path: String, schemaName: String): String =
Paths.get(path, s"${schemaName}.scala").toAbsolutePath().toString()