LiquibaseDatabase生成jooq时如何使用postgres数据库

How to use postgres database when generate jooq by LiquibaseDatabase

有很好的攻略how to use code generation from liquibase 但是默认情况下,它使用 h2 数据库从迁移创建模式,然后生成记录。如何为 liquibase 迁移指定另一个数据库(例如,postgres)?

我的解决方案(build.gradle.kts):

plugins {
    java
    id("nu.studer.jooq") version "7.1.1"
    id("org.liquibase.gradle") version "2.1.1"
}

java {
    sourceCompatibility = JavaVersion.VERSION_18
    targetCompatibility = JavaVersion.VERSION_18
}

dependencies {
    jooqGenerator("org.postgresql:postgresql:42.3.2")
    jooqGenerator("org.slf4j:slf4j-jdk14:1.7.30")
    jooqGenerator("org.testcontainers:postgresql:1.17.1")

    liquibaseRuntime(files("src/main/resources"))
    liquibaseRuntime("org.testcontainers:postgresql:1.17.1")
    liquibaseRuntime("org.postgresql:postgresql:42.3.2")
    liquibaseRuntime("org.liquibase:liquibase-core")
    liquibaseRuntime("info.picocli:picocli:4.6.1")
    liquibaseRuntime("ch.qos.logback:logback-core:1.2.3")
    liquibaseRuntime(sourceSets.getByName("main").compileClasspath)
    liquibaseRuntime(sourceSets.getByName("main").output)
}

liquibase {
    activities.register("main") {
        this.arguments = mapOf(
            "logLevel" to "info",
            "changeLogFile" to "db/migration/changelog-master.xml",
            "url" to "jdbc:tc:postgresql:9.6.8:///postgres?TC_DAEMON=true",
            "username" to "user",
            "password" to "password",
            "driver" to "org.testcontainers.jdbc.ContainerDatabaseDriver"
        )
    }
    runList = "main"
}

tasks.withType<JooqGenerate> {
    dependsOn(tasks.named("update"))
}

jooq {
    version.set("3.16.6")
    edition.set(nu.studer.gradle.jooq.JooqEdition.OSS)

    configurations {
        create("main") {
            generateSchemaSourceOnCompilation.set(true)

            jooqConfiguration.apply {
                logging = org.jooq.meta.jaxb.Logging.WARN
                jdbc.apply {
                    driver = "org.testcontainers.jdbc.ContainerDatabaseDriver"
                    url = "jdbc:tc:postgresql:9.6.8:///postgres?TC_DAEMON=true"
                    user = "user"
                    password = "password"
                }
                generator.apply {
                    name = "org.jooq.codegen.DefaultGenerator"
                    database.apply {
                        name = "org.jooq.meta.postgres.PostgresDatabase"
                        inputSchema = "public"
                    }
                    generate.apply {
                        isDeprecated = false
                        isRecords = true
                        isImmutablePojos = true
                        isFluentSetters = true
                    }
                    target.apply {
                        packageName = "com.example"
                        directory = "build/generated-src/jooq/main"
                    }
                    strategy.name = "org.jooq.codegen.DefaultGeneratorStrategy"
                }
            }
        }
    }
}

tasks.named<nu.studer.gradle.jooq.JooqGenerate>("generateJooq") {
    (launcher::set)(javaToolchains.launcherFor {
        languageVersion.set(JavaLanguageVersion.of(18))
    })
}
期望:
在 运行 code gen ./gradlew generateJooq 首先启动 postgres testcontainer 和 liquibase 应用迁移之后,然后启动 jooq 代码生成
现实:
在 运行 code gen 启动 postgres testcontainer 和 liquibase 应用迁移然后启动新的 testcontainer 和 jooq 尝试生成记录之后

是否有任何解决方案可以为迁移和代码生成指定一个 postgres 容器?

在官方 jOOQ 博客上,他们为 Using Testcontainers to Generate jOOQ Code

写了一个指南

Pointing the jOOQ code generator towards a live database used to be a bit of a challenge, which is why jOOQ offers alternative, connection-free code generation modes, including:

  • The JPADatabase, if you have a pre-existing JPA entity based meta model.
  • The XMLDatabase, if you have some form of XML version of your schema, which you can XSL transform to jOOQ’s format
  • The LiquibaseDatabase, which simulates a Liquibase database migration and uses the simulated database output as a source for meta information of the code generator

But all of the above have the same limitation. You can’t really use many vendor-specific features, such as advanced stored procedures, data types, etc.

文章继续,并描述了 how you can use jOOQ as a Modern Approach Using Testcontainers,这可能有助于理解使用 jOOQ 的 LiquibaseDatabase 命令的正确过程。

这是一些额外的文档:

解决方案:
(build.gradle.kts)

plugins {
    java
    idea
    id("nu.studer.jooq")
    id("org.liquibase.gradle")
}

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.testcontainers:postgresql:1.17.1")
    }
}

dependencies {
    jooqGenerator("org.jooq:jooq-meta-extensions-liquibase")
    jooqGenerator("org.postgresql:postgresql:42.3.2")
    jooqGenerator("org.slf4j:slf4j-jdk14:1.7.30")
    jooqGenerator("org.testcontainers:postgresql:1.17.1")
    jooqGenerator(files("src/main/resources"))

    liquibaseRuntime(files("src/main/resources"))
    liquibaseRuntime(sourceSets.getByName("main").compileClasspath)
    liquibaseRuntime(sourceSets.getByName("main").output)
    liquibaseRuntime("org.liquibase:liquibase-core")
    liquibaseRuntime("org.postgresql:postgresql")
    liquibaseRuntime("info.picocli:picocli:4.6.1")
    liquibaseRuntime("ch.qos.logback:logback-core:1.2.3")
}

// starting container
var postgres: JdbcDatabaseContainer<*> = PostgreSQLContainerProvider().newInstance("14-alpine")
postgres.start()

val containerStop by tasks.registering {
    if (postgres.isRunning) {
        println("STOPPING DATABASE CONTAINER")
        postgres.stop()
    }
}

tasks.named("update") {
    doLast {
        tasks.named("generateJooq").get()
    }
}

tasks.withType<JooqGenerate> {
    doLast {
        containerStop.get()
    }
}

liquibase {
    activities.register("main") {
        this.arguments = mapOf(
            "logLevel" to "info",
            "classpath" to "${projectDir}/",
            "changeLogFile" to "db/migration/changelog-master.xml",
            "url" to postgres.jdbcUrl,
            "username" to postgres.username,
            "password" to postgres.password,
            "driver" to "org.postgresql.Driver"
        )
    }
    runList = "main"
}

jooq {
    version.set(jooqVersion)
    edition.set(JooqEdition.OSS)

    configurations {
        create("main") {
            generateSchemaSourceOnCompilation.set(true)

            jooqConfiguration.apply {
                logging = Logging.WARN
                jdbc.apply {
                    driver = "org.postgresql.Driver"
                    url = postgres.jdbcUrl
                    user = postgres.username
                    password = postgres.password
                }
                generator.apply {
                    name = "org.jooq.codegen.DefaultGenerator"
                    database.apply {
                        name = "org.jooq.meta.postgres.PostgresDatabase"
                        inputSchema = "public"
                        excludes = "databasechangelog|databasechangeloglock"
                    }
                    generate.apply {
                        isDeprecated = false
                        isRecords = true
                        isImmutablePojos = true
                        isFluentSetters = true
                    }
                    target.apply {
                        packageName = "my.package.jooq"
                        directory = "build/generated-src/jooq/main"
                    }
                    strategy.name = "org.jooq.codegen.DefaultGeneratorStrategy"
                }
            }
        }
    }
}

./gradlew clean update build