【问题标题】:Playframework evolutions files compatible with both postgres and h2Playframework Evolutions 文件与 postgres 和 h2 兼容
【发布时间】:2023-03-21 14:20:01
【问题描述】:

我一直在使用 H2 作为后端的 Play 框架 (scala) 开发一个网站。测试很好地集成在一起,尤其是能够针对内存中的 H2 db 运行测试。

现在,出于各种方便的原因,我想将我的数据存储区移至 Postgres。这给我留下了一个问题:如何继续测试并为每次测试运行保留新数据库的简单性?我在网上看到有些人设法针对 postgres 实时运行并针对 H2 进行测试。然而,两者在 SQL 级别上并不完全兼容(即使在 Postgres 兼容模式下与 H2 兼容)。例如 H2 不支持 SERIAL、BIGSERIAL 和 BYTEA。

我可以通过使用两种方言的受限兼容交集来做到这一点,还是我缺少另一种技术?

感谢您的帮助。

亚历克斯

【问题讨论】:

    标签: postgresql playframework h2


    【解决方案1】:

    我知道这是一篇较旧的帖子,但看起来几年后仍然没有明显的解决方案。作为短期修复,在 play 2.4.x-2.5.x 中(目前仅在那里测试),您可以通过创建自定义进化阅读器来更改在测试期间应用进化的方式:

    package support
    
    import play.api.db.evolutions.{ClassLoaderEvolutionsReader, Evolutions, ResourceEvolutionsReader}
    
    import java.io.{ByteArrayInputStream, InputStream}
    import java.nio.charset.StandardCharsets
    import scala.io.Source
    import scala.util.Try
    
    class EvolutionTransformingReader(
        classLoader: ClassLoader = classOf[ClassLoaderEvolutionsReader].getClassLoader,
        prefix: String = "")
      extends ResourceEvolutionsReader {
    
      def loadResource(db: String, revision: Int): Option[InputStream] =
        for {
          stream <- Option(classLoader.getResourceAsStream(prefix + Evolutions.resourceName(db, revision)))
          lines <- Try(Source.fromInputStream(stream).getLines).toOption
          updated = lines map convertPostgresLinesToH2
        } yield convertLinesToInputStream(updated)
    
      private val ColumnRename = """(?i)\s*ALTER TABLE (\w+) RENAME COLUMN (\w+) TO (\w+);""".r
    
      private def convertPostgresLinesToH2(line: String): String =
        line match {
          case ColumnRename(tableName, oldColumn, newColumn) =>
            s"""ALTER TABLE $tableName ALTER COLUMN $oldColumn RENAME TO $newColumn;"""
          case _ => line
        }
    
      private def convertLinesToInputStream(lines: Iterator[String]): InputStream =
        new ByteArrayInputStream(lines.mkString("\n").getBytes(StandardCharsets.UTF_8))
    }
    

    然后将其传递到您在测试期间应用进化的地方:

    Evolutions.applyEvolutions(registry.database, new EvolutionTransformingReader())
    

    请注意,读者仍然处于相当愚蠢的状态(它假设 SQL 语句是单行的,这不能保证),但这应该足以让任何人开始。

    【讨论】:

    • 很高兴知道至少有办法解决这个问题。我们仍在 Play 2.3 上,似乎没有办法只重命名列名。这就是为什么标准是好的,前提是所有供应商都遵循它......
    【解决方案2】:

    由于进化文件直接使用 SQL,除非您将自己限制为通用的跨数据库兼容的 SQL 子集,否则您可能会遇到问题。

    对此没有真正的解决方案,但您仍然可以使用新的数据库进行测试。只需设置以下内容:

    %test.jpa.ddl=create-drop
    %test.db.driver=org.postgresql.Driver
    %test.db=<jdbc url>
    //etc
    

    这应该为测试创建一个新的 postgres 连接,从头开始创建数据库,运行演进,进行测试并在完成后删除所有数据。

    【讨论】:

      猜你喜欢
      • 2019-06-10
      • 2014-07-19
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 2013-12-11
      • 2019-11-04
      • 1970-01-01
      • 2014-07-28
      相关资源
      最近更新 更多