是否可以命名 play evolution sql 脚本?

Posted

技术标签:

【中文标题】是否可以命名 play evolution sql 脚本?【英文标题】:Is it possible to name play evolution sql scripts? 【发布时间】:2017-03-29 12:23:59 【问题描述】:

进化sql脚本应该命名

1.sql, 2.sql, XXX.sql

根据文档。 https://www.playframework.com/documentation/2.5.x/Evolutions#Running-evolutions-using-compile-time-DI

是否有可能将命名约定更改为

1_create__customers.sql 2_create__orders.sql 3_alter__customers__add__home_address.sql

喜欢它 http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-standalone-migration

是的,我评估了https://github.com/flyway/flyway-play 我们可以切换到它。

现在我正在寻找默认播放功能。

【问题讨论】:

【参考方案1】:

是的,这是可能的。

在此路径创建一个新文件:your/modules/folder/EvolutionsModule.scala

然后,添加以下内容:

package your.modules.folder

import javax.inject._

import play.api.db.evolutions._
import play.api.inject. Module 
import play.api.libs.Collections
import play.api. Configuration, Environment 
import org.apache.commons.io.FileUtils

class EvolutionsModule extends Module 
  def bindings(environment: Environment, configuration: Configuration) = 
    Seq(
      bind[EvolutionsConfig].toProvider[DefaultEvolutionsConfigParser],
      bind[EvolutionsReader].to[YourEvolutionsReader],
      bind[EvolutionsApi].to[DefaultEvolutionsApi],
      bind[ApplicationEvolutions].toProvider[ApplicationEvolutionsProvider].eagerly
    )
  


@Singleton
class YourEvolutionsReader @Inject()(environment: Environment) extends EvolutionsReader 

  def evolutions(db: String): Seq[Evolution] = 

    val upsMarker = """^#.*!Ups.*$""".r
    val downsMarker = """^#.*!Downs.*$""".r

    val UPS = "UPS"
    val DOWNS = "DOWNS"
    val UNKNOWN = "UNKNOWN"

    val mapUpsAndDowns: PartialFunction[String, String] = 
      case upsMarker() => UPS
      case downsMarker() => DOWNS
      case _ => UNKNOWN
    

    val isMarker: PartialFunction[String, Boolean] = 
      case upsMarker() => true
      case downsMarker() => true
      case _ => false
    

    val folder = environment.getFile(Evolutions.directoryName(db))
    val sqlFiles = folder.listFiles()
      .filter(file => file.getName.indexOf(".sql") > -1)
      .sortBy(file => 
        val fileName = file.getName
        val nameAfterSqlNumber = fileName.split("\\.")(0).split("_").drop(1).mkString("") + ".sql"
        val sqlNumber = fileName.split("\\.")(0).split("_")(0).toInt
        val newPrefix = "%07d".format(sqlNumber)
        newPrefix + nameAfterSqlNumber
      )
      .toSeq
    sqlFiles.zip(1 to sqlFiles.size)
      .map 
        case (file, revision) => 
          val script = FileUtils.readFileToString(file)
          val parsed = Collections.unfoldLeft(("", script.split('\n').toList.map(_.trim))) 
            case (_, Nil) => None
            case (context, lines) => 
              val (some, next) = lines.span(l => !isMarker(l))
              Some((next.headOption.map(c => (mapUpsAndDowns(c), next.tail)).getOrElse("" -> Nil),
                context -> some.mkString("\n")))
            
          .reverse.drop(1).groupBy(i => i._1).mapValues  _.map(_._2).mkString("\n").trim 
          Evolution(
            revision,
            parsed.getOrElse(UPS, ""),
            parsed.getOrElse(DOWNS, "")
          )
        
      
  

转到您的applications.conf,然后添加这些行。这是为了用我们自己的替换默认的EvolutionsModule

play.modules 
    enabled += "your.modules.folder.EvolutionsModule"
    disabled += "play.api.db.evolutions.EvolutionsModule"

第一段文字说明:

根据源代码,进化仅基于单个类和方法添加 - EvolutionsReader 和方法 evolutions。 运行evolutions 方法后,evolutions 模块将依赖生成的数据库条目。所以,我们只需要用我们自己的方法覆盖这个方法。 尽管代码块很大,但实际上只是对源代码进行了少量编辑。我用 Evolutions sql 文件夹中的文件列表替换了 loadResource 函数的功能。其余部分是EvolutionsApi.scalaevolutions 方法的直接副本

引用by this answer 的源代码很可能是实用函数——Evolutions 模块实际上并不依赖它。我找不到fileNameresourceName 用于运行evolutions 的任何重要用法。相反,它们都引用了play_evolutions 表。

参考:https://github.com/playframework/playframework/issues/6919

【讨论】:

@Sergey 没关系。 IMO,完全放弃进化并切换是正确的决定(也放弃光滑,但这是另一回事)。但我不能,因为我正在继承一个项目。尽管如此,我还是希望这个问题能够为我和其他代码维护人员提供正确的答案,以供将来参考,尤其是因为我将长期使用 Scala。【参考方案2】:

不,不可能,源码:

def fileName(db: String, revision: Int): String = s"$directoryName(db)/$revision.sql"

https://github.com/playframework/playframework/blob/2.5.x/framework/src/play-jdbc-evolutions/src/main/scala/play/api/db/evolutions/Evolutions.scala#L103

def resourceName(db: String, revision: Int): String = s"evolutions/$db/$revision.sql"

https://github.com/playframework/playframework/blob/2.5.x/framework/src/play-jdbc-evolutions/src/main/scala/play/api/db/evolutions/Evolutions.scala#L108

@Singleton
class EnvironmentEvolutionsReader @Inject() (environment: Environment) extends ResourceEvolutionsReader 

  def loadResource(db: String, revision: Int) = 
    environment.getExistingFile(Evolutions.fileName(db, revision)).map(new FileInputStream(_)).orElse 
      environment.resourceAsStream(Evolutions.resourceName(db, revision))
    
  

https://github.com/playframework/playframework/blob/2.5.x/framework/src/play-jdbc-evolutions/src/main/scala/play/api/db/evolutions/EvolutionsApi.scala#L471-L479

因此,正如文档中所述,您只能使用号码revision.sql

【讨论】:

以上是关于是否可以命名 play evolution sql 脚本?的主要内容,如果未能解决你的问题,请参考以下文章

Play!:Slick 的 DDL 会取代 Evolutions 吗?

未找到表“play_evolutions”

Play / Slick / Evolution 未应用

在多个数据库上排序 Play Evolution

如何使用Slick和Play在测试中应用手动演变! 2.4

目前使用 Django “Evolution”,“South”是不是更好,值得切换?