【问题标题】:Slick code generation for only a single schema仅针对单个架构的流畅代码生成
【发布时间】:2015-02-02 19:20:08
【问题描述】:

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

【问题讨论】:

  • 试试这个。您可以提及架构名称以生成代码。github.com/tminglei/slick-pg
  • @SKarthik 我看不出这与模式生成有什么关系?我实际上知道那个项目并且确实使用它。

标签: postgresql scala slick


【解决方案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

  }
}

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我发现了这个问题。 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))
    

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

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

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

    【讨论】:

    • @Bart 所做的只为单个模式生成的更新版本可以在this gist中找到
    猜你喜欢
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 2010-09-09
    • 2017-07-21
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多