仅为单个模式生成光滑的代码

时间:2015-02-02 19:20:08

标签: postgresql scala slick

有没有办法让Slick的代码生成只为单个模式生成代码?公开说?我有扩展,创建了大量的表(例如postgis,pg_jobman),使得光滑的代码生成巨大的。

2 个答案:

答案 0 :(得分:1)

将此代码与适当的值和架构名称一起使用

object CodeGenerator {

  def outputDir :String =""
  def pkg:String =""
  def schemaList:String = "schema1, schema2"
  def url:String  = "dburl"
  def fileName:String =""
  val user = "dbUsername"
  val password = "dbPassword"
  val slickDriver="scala.slick.driver.PostgresDriver"
  val JdbcDriver = "org.postgresql.Driver"
  val container = "Tables"


  def generate() = {    

    val driver: JdbcProfile = buildJdbcProfile

    val schemas = createSchemaList

    var model = createModel(driver,schemas)

    val codegen = new SourceCodeGenerator(model){
      // customize Scala table name (table class, table values, ...)
      override def tableName = dbTableName => dbTableName match {
        case _ => dbTableName+"Table"
      }
      override def code = {
        //imports is copied right out of
        //scala.slick.model.codegen.AbstractSourceCodeGenerator
        val 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" //+ tables.map(t => s"implicit val ${t.model.name.table}Format = Json.format[${t.model.name.table}]").mkString("\n")+"\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 joins =   tables.flatMap( _.foreignKeys.map{  foreignKey  =>
        import foreignKey._
        val fkt =   referencingTable.TableClass.name
        val pkt =   referencedTable.TableClass.name
        val columns =   referencingColumns.map(_.name)  zip
          referencedColumns.map(_.name)
        s"implicit def autojoin${fkt + name.toString} = (left:${fkt} ,right:${pkt}) =>  "   +
          columns.map{
            case    (lcol,rcol) =>
              "left."+lcol  +   "   === "   +   "right."+rcol
          }.mkString("  &&  ")
      })

      override def entityName = dbTableName => dbTableName match {
        case _ => dbTableName
      }

      override def Table = new Table(_) {
        table =>
        // customize table value (TableQuery) name (uses tableName as a basis)
        override def TableValue = new TableValue {
          override def rawName = super.rawName.uncapitalize
        }
        // override generator responsible for columns
        override def Column = new Column(_){
          // customize Scala column names
          override def rawName = (table.model.name.table,this.model.name) match {

            case _ => super.rawName
          }
        }
      }

    }

    println(outputDir+"\\"+fileName)
    (new File(outputDir)).mkdirs()
    val fw = new FileWriter(outputDir+File.separator+fileName)
    fw.write(codegen.packageCode(slickDriver, pkg, container))
    fw.close()

  }

  def createModel(driver: JdbcProfile, schemas:Set[Option[String]]): Model = {
    driver.simple.Database
      .forURL(url, user = user, password = password, driver = JdbcDriver)
      .withSession { implicit session =>
      val filteredTables = driver.defaultTables.filter(
        (t: MTable) => schemas.contains(t.name.schema)
      )
      PostgresDriver.createModel(Some(filteredTables))
    }
  }

  def createSchemaList: Set[Option[String]] = {
    schemaList.split(",").map({
      case "" => None
      case (name: String) => Some(name)
    }).toSet
  }

  def buildJdbcProfile: JdbcProfile = {

    val module = currentMirror.staticModule(slickDriver)
    val reflectedModule = currentMirror.reflectModule(module)
    val driver = reflectedModule.instance.asInstanceOf[JdbcProfile]
    driver

  }
}

答案 1 :(得分:1)

我遇到了同样的问题,我发现了这个问题。 S.Karthik的回答让我朝着正确的方向前进。但是,答案中的代码稍微过时了。我觉得有点过于复杂。所以我制定了自己的解决方案:

import slick.codegen.SourceCodeGenerator
import slick.driver.JdbcProfile
import slick.model.Model

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

val slickDriver = "slick.driver.PostgresDriver"
val jdbcDriver = "org.postgresql.Driver"
val url = "jdbc:postgresql://localhost:5432/mydb"
val outputFolder = "/path/to/src/test/scala"
val pkg = "com.mycompany"
val user = "user"
val password = "password"


object MySourceCodeGenerator {

  def run(slickDriver: String, jdbcDriver: String, url: String, outputDir: String,
          pkg: String, user: Option[String], password: Option[String]): Unit = {

    val driver: JdbcProfile =
      Class.forName(slickDriver + "$").getField("MODULE$").get(null).asInstanceOf[JdbcProfile]
    val dbFactory = driver.api.Database
    val db = dbFactory.forURL(url, driver = jdbcDriver, user = user.orNull,
                              password = password.orNull, keepAliveConnection = true)
    try {
      // **1**
      val allSchemas = Await.result(db.run(
        driver.createModel(None, ignoreInvalidDefaults = false)(ExecutionContext.global).withPinnedSession), Duration.Inf)
      // **2**
      val publicSchema = new Model(allSchemas.tables.filter(_.name.schema.isEmpty), allSchemas.options)
      // **3**
      new SourceCodeGenerator(publicSchema).writeToFile(slickDriver, outputDir, pkg)
    } finally db.close
  }
}

MySourceCodeGenerator.run(slickDriver, jdbcDriver, url, outputFolder, pkg, Some(user), Some(password))

我将解释这里发生了什么:

  • 我从run库中的SourceCodeGenerator类复制了slick-codegen函数。 (我使用的是版本slick-codegen_2.10-3.1.1。)
  • // **1**:在origninal代码中,生成的Model在名为val的{​​{1}}中被引用。我将其重命名为m
  • allSchemas:我使用原始模型中的// **2**创建了一个新的ModelpublicSchema),并使用options的过滤版本从原始模型设置。事实证明,tables模式中的表格不会在模型中获得模式名称。因此public。如果您需要来自一个或多个其他模式的表,则可以轻松创建不同的过滤器表达式。
  • isEmpty:我使用创建的// **3**模型创建了SourceCodeGenerator

当然,如果Slick代码生成器可以包含一个选项来选择一个或多个模式,那就更好了。

相关问题