From 25f023ebe5b270bd876128a68568c97fa7db1c88 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 14 Jun 2023 15:52:43 +0200 Subject: [PATCH] [jOOQ/jOOQ#9506] Various improvements This includes: - Commits::add should return this - Add Settings.migrationHistorySchema - Add some DEBUG logging - Add a jOOQ-migrations-maven module draft - Cache AbstractNode.root to avoid excessive recursive root() lookups - [jOOQ/jOOQ#15201] Rename changelog to history - [jOOQ/jOOQ#15201] Removal of Commits.commit(String) --- jOOQ-migrations-maven/.gitignore | 3 + jOOQ-migrations-maven/LICENSE.txt | 19 ++ jOOQ-migrations-maven/NOTICE.txt | 10 + jOOQ-migrations-maven/pom.xml | 109 +++++++++ .../codegen/maven/AbstractMigrationsMojo.java | 219 ++++++++++++++++++ .../java/org/jooq/codegen/maven/Jdbc.java | 46 ++++ .../org/jooq/codegen/maven/MigrateMojo.java | 98 ++++++++ .../src/main/resources/META-INF/LICENSE.txt | 19 ++ .../src/main/resources/META-INF/README.txt | 2 + jOOQ/src/main/java/org/jooq/Commits.java | 14 +- jOOQ/src/main/java/org/jooq/Migrations.java | 10 - .../src/main/java/org/jooq/conf/Settings.java | 37 +++ .../main/java/org/jooq/impl/AbstractNode.java | 17 +- .../main/java/org/jooq/impl/Changelog.java | 157 ------------- .../main/java/org/jooq/impl/CommitImpl.java | 22 +- .../main/java/org/jooq/impl/CommitsImpl.java | 34 ++- jOOQ/src/main/java/org/jooq/impl/History.java | 157 +++++++++++++ ...hangelogRecord.java => HistoryRecord.java} | 86 +++---- .../java/org/jooq/impl/MigrationImpl.java | 103 +++++--- .../java/org/jooq/impl/MigrationsImpl.java | 9 +- .../main/java/org/jooq/impl/VersionImpl.java | 28 +-- .../resources/org/jooq/migrations/v1-init.sql | 26 +-- .../org/jooq/xsd/jooq-runtime-3.19.0.xsd | 4 + pom.xml | 12 +- 24 files changed, 927 insertions(+), 314 deletions(-) create mode 100644 jOOQ-migrations-maven/.gitignore create mode 100644 jOOQ-migrations-maven/LICENSE.txt create mode 100644 jOOQ-migrations-maven/NOTICE.txt create mode 100644 jOOQ-migrations-maven/pom.xml create mode 100644 jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/AbstractMigrationsMojo.java create mode 100644 jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/Jdbc.java create mode 100644 jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/MigrateMojo.java create mode 100644 jOOQ-migrations-maven/src/main/resources/META-INF/LICENSE.txt create mode 100644 jOOQ-migrations-maven/src/main/resources/META-INF/README.txt delete mode 100644 jOOQ/src/main/java/org/jooq/impl/Changelog.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/History.java rename jOOQ/src/main/java/org/jooq/impl/{ChangelogRecord.java => HistoryRecord.java} (50%) diff --git a/jOOQ-migrations-maven/.gitignore b/jOOQ-migrations-maven/.gitignore new file mode 100644 index 0000000000..e8e5bad2d2 --- /dev/null +++ b/jOOQ-migrations-maven/.gitignore @@ -0,0 +1,3 @@ +/target +/.idea +/*.iml \ No newline at end of file diff --git a/jOOQ-migrations-maven/LICENSE.txt b/jOOQ-migrations-maven/LICENSE.txt new file mode 100644 index 0000000000..84f48a6df9 --- /dev/null +++ b/jOOQ-migrations-maven/LICENSE.txt @@ -0,0 +1,19 @@ +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Other licenses: +----------------------------------------------------------------------------- +Commercial licenses for this work are available. These replace the above +ASL 2.0 and offer limited warranties, support, maintenance, and commercial +database integrations. + +For more information, please visit: https://www.jooq.org/legal/licensing \ No newline at end of file diff --git a/jOOQ-migrations-maven/NOTICE.txt b/jOOQ-migrations-maven/NOTICE.txt new file mode 100644 index 0000000000..698edf47ee --- /dev/null +++ b/jOOQ-migrations-maven/NOTICE.txt @@ -0,0 +1,10 @@ +Third party NOTICE.txt contents +=============================== + +Contents of https://github.com/apache/commons-lang/blob/master/NOTICE.txt +------------------------------------------------------------------------- +Apache Commons Lang +Copyright 2001-2019 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file diff --git a/jOOQ-migrations-maven/pom.xml b/jOOQ-migrations-maven/pom.xml new file mode 100644 index 0000000000..416a8b48dc --- /dev/null +++ b/jOOQ-migrations-maven/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + + org.jooq + jooq-parent + 3.19.0-SNAPSHOT + + + jooq-migrations-maven + jOOQ Migrations Maven + maven-plugin + + + + Apache License, Version 2.0 + http://www.jooq.org/inc/LICENSE.txt + repo + + + + + + + + + + + + + + org.owasp + dependency-check-maven + + + + + commons-io:commons-io:jar:2.6 + com.google.guava:guava:jar:25.1-android + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + + + mojo-descriptor + + descriptor + + + + + + help-goal + + helpmojo + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.jooq.migrations.maven + + + + + + + + + + org.jooq + jooq + + + + org.apache.maven + maven-plugin-api + provided + + + org.apache.maven + maven-core + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + provided + + + diff --git a/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/AbstractMigrationsMojo.java b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/AbstractMigrationsMojo.java new file mode 100644 index 0000000000..aa94472fe9 --- /dev/null +++ b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/AbstractMigrationsMojo.java @@ -0,0 +1,219 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.codegen.maven; + +import static org.jooq.tools.StringUtils.defaultIfNull; +import static org.jooq.tools.StringUtils.isBlank; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; + +import org.jooq.CloseableDSLContext; +import org.jooq.Configuration; +import org.jooq.conf.MigrationSchema; +import org.jooq.impl.DSL; +import org.jooq.tools.StringUtils; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +/** + * A base class for migration mojos. + * + * @author Lukas Eder + */ +abstract class AbstractMigrationsMojo extends AbstractMojo { + + /** + * The Maven project. + */ + @Parameter( + property = "project", + required = true, + readonly = true + ) + MavenProject project; + + /** + * Whether to skip the execution of the Maven Plugin for this module. + */ + @Parameter(property = "jooq.migrate.skip") + boolean skip; + + /** + * The JDBC URL to connect to. + */ + @Parameter(property = "jooq.migrate.jdbc") + Jdbc jdbc; + + /** + * The migration script directory. + */ + @Parameter(property = "jooq.migrate.directory") + String directory; + + /** + * The script to run before the migration. + */ + @Parameter(property = "jooq.migrate.setupScript") + String setupScript; + + /** + * The script to run after the migration. + */ + @Parameter(property = "jooq.migrate.cleanupScript") + String cleanupScript; + + /** + * The schemata that are migrated. + */ + @Parameter(property = "jooq.migrate.schemata") + List schemata; + + /** + * The default catalog among the migrated schemata. + */ + @Parameter(property = "jooq.migrate.defaultCatalog") + String defaultCatalog; + + /** + * The default schema among the migrated schemata. + */ + @Parameter(property = "jooq.migrate.defaultSchema") + String defaultSchema; + + /** + * The catalog where the history tables are located. + */ + @Parameter(property = "jooq.migrate.historyCatalog") + String historyCatalog; + + /** + * The schema where the history tables are located. + */ + @Parameter(property = "jooq.migrate.historySchema") + String historySchema; + + @Override + public void execute() throws MojoExecutionException { + if (skip) { + getLog().info("Skipping jOOQ migrations"); + return; + } + + ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); + URLClassLoader pluginClassLoader = getClassLoader(); + + try { + + // [#2886] Add the surrounding project's dependencies to the current classloader + Thread.currentThread().setContextClassLoader(pluginClassLoader); + + if (jdbc == null || jdbc.url == null) + throw new MojoExecutionException("JDBC URL is required"); + + try (CloseableDSLContext ctx = DSL.using(jdbc.url, defaultIfNull(jdbc.user, jdbc.username), jdbc.password)) { + + // Initialise Settings + List s = ctx.settings().getMigrationSchemata(); + s.addAll(schemata); + + if (defaultCatalog != null || defaultSchema != null) + s.add(new MigrationSchema().withCatalog(defaultIfNull(defaultCatalog, "")).withSchema(defaultIfNull(defaultSchema, ""))); + + if (historyCatalog != null || historySchema != null) + ctx.settings().setMigrationHistorySchema(new MigrationSchema().withCatalog(defaultIfNull(historyCatalog, "")).withSchema(defaultIfNull(historySchema, ""))); + + // Initialise connection + if (!isBlank(defaultCatalog)) + ctx.setCatalog(defaultCatalog).execute(); + + if (!isBlank(defaultSchema)) + ctx.setSchema(defaultSchema).execute(); + + // Run migration + if (setupScript != null) + ctx.execute(setupScript); + + execute0(ctx.configuration()); + + if (cleanupScript != null) + ctx.execute(cleanupScript); + } + } + catch (Exception ex) { + throw new MojoExecutionException("Error running jOOQ code generation tool", ex); + } + finally { + + // [#2886] Restore old class loader + Thread.currentThread().setContextClassLoader(oldCL); + + // [#7630] Close URLClassLoader to help free resources + try { + pluginClassLoader.close(); + } + + // Catch all possible errors to avoid suppressing the original exception + catch (Throwable e) { + getLog().error("Couldn't close the classloader.", e); + } + } + } + + abstract void execute0(Configuration configuration) throws Exception; + + private URLClassLoader getClassLoader() throws MojoExecutionException { + try { + List classpathElements = project.getRuntimeClasspathElements(); + URL urls[] = new URL[classpathElements.size()]; + + for (int i = 0; i < urls.length; i++) + urls[i] = new File(classpathElements.get(i)).toURI().toURL(); + + return new URLClassLoader(urls, getClass().getClassLoader()); + } + catch (Exception e) { + throw new MojoExecutionException("Couldn't create a classloader.", e); + } + } +} diff --git a/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/Jdbc.java b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/Jdbc.java new file mode 100644 index 0000000000..f3af72ed8d --- /dev/null +++ b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/Jdbc.java @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.codegen.maven; + +public class Jdbc { + + public String url; + public String user; + public String username; + public String password; +} diff --git a/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/MigrateMojo.java b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/MigrateMojo.java new file mode 100644 index 0000000000..8e6ee7622f --- /dev/null +++ b/jOOQ-migrations-maven/src/main/java/org/jooq/codegen/maven/MigrateMojo.java @@ -0,0 +1,98 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.codegen.maven; + +import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_SOURCES; +import static org.apache.maven.plugins.annotations.ResolutionScope.TEST; + +import java.io.File; + +import org.jooq.Commits; +import org.jooq.Configuration; +import org.jooq.Migration; +import org.jooq.Migrations; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; + +/** + * The jOOQ Migrations migrate mojo + * + * @author Lukas Eder + */ +@Mojo( + name = "migrate", + defaultPhase = GENERATE_SOURCES, + requiresDependencyResolution = TEST, + threadSafe = true +) +public class MigrateMojo extends AbstractMigrationsMojo { + + @Override + public void execute0(Configuration configuration) throws Exception { + if (directory == null) + throw new MojoExecutionException("Directory was not provided"); + + Migrations migrations = configuration.dsl().migrations(); + Commits commits = migrations.commits(); + + // [#9506] TODO: Support loading directories recursively + // [#9506] TODO: Support loading **/*.sql style paths + // [#9506] TODO: Support relative paths, absolute paths, etc. + commits.load(file(directory)); + Migration migration = migrations.migrateTo(commits.latest()); + + if (getLog().isInfoEnabled()) { + getLog().info("Migration from version: " + migration.from()); + getLog().info("Migration to version : " + migration.to()); + getLog().info("Migration queries : " + migration.queries().queries().length); + } + + migration.execute(); + } + + private File file(String file) { + getLog().info("Reading migrations directory: " + file); + File f = new File(file); + + if (!f.isAbsolute()) + f = new File(project.getBasedir(), file); + + return f; + } +} diff --git a/jOOQ-migrations-maven/src/main/resources/META-INF/LICENSE.txt b/jOOQ-migrations-maven/src/main/resources/META-INF/LICENSE.txt new file mode 100644 index 0000000000..84f48a6df9 --- /dev/null +++ b/jOOQ-migrations-maven/src/main/resources/META-INF/LICENSE.txt @@ -0,0 +1,19 @@ +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Other licenses: +----------------------------------------------------------------------------- +Commercial licenses for this work are available. These replace the above +ASL 2.0 and offer limited warranties, support, maintenance, and commercial +database integrations. + +For more information, please visit: https://www.jooq.org/legal/licensing \ No newline at end of file diff --git a/jOOQ-migrations-maven/src/main/resources/META-INF/README.txt b/jOOQ-migrations-maven/src/main/resources/META-INF/README.txt new file mode 100644 index 0000000000..3e6e227e05 --- /dev/null +++ b/jOOQ-migrations-maven/src/main/resources/META-INF/README.txt @@ -0,0 +1,2 @@ +Thanks for downloading jOOQ. +Please visit http://www.jooq.org for more information. \ No newline at end of file diff --git a/jOOQ/src/main/java/org/jooq/Commits.java b/jOOQ/src/main/java/org/jooq/Commits.java index bcea0d5919..67bca2d037 100644 --- a/jOOQ/src/main/java/org/jooq/Commits.java +++ b/jOOQ/src/main/java/org/jooq/Commits.java @@ -102,22 +102,29 @@ public interface Commits extends Iterable { /** * Add a commit to the graph. + * + * @return The same instance. */ - void add(Commit commit); + Commits add(Commit commit); /** * Add all commits to the graph. + * + * @return The same instance. */ - void addAll(Commit... commits); + Commits addAll(Commit... commits); /** * Add all commits to the graph. + * + * @return The same instance. */ - void addAll(Collection commits); + Commits addAll(Collection commits); /** * Load directory content into this commits graph. * + * @return The same instance. * @throws IOException If anything goes wrong reading the directory * contents. * @throws DataMigrationValidationException If the migration doesn't @@ -129,6 +136,7 @@ public interface Commits extends Iterable { /** * Load XML content into this commits graph. * + * @return The same instance. * @throws DataMigrationValidationException If the migration doesn't * validate. */ diff --git a/jOOQ/src/main/java/org/jooq/Migrations.java b/jOOQ/src/main/java/org/jooq/Migrations.java index 01e0f43c20..049aaad4e1 100644 --- a/jOOQ/src/main/java/org/jooq/Migrations.java +++ b/jOOQ/src/main/java/org/jooq/Migrations.java @@ -80,16 +80,6 @@ public interface Migrations { @NotNull Versions versions(); - /** - * Initialise a {@link Version}. - *

- * This is EXPERIMENTAL functionality and subject to change in future jOOQ - * versions. - */ - @Experimental - @NotNull - Commit commit(String id); - /** * Initialise an empty {@link Commits} graph. *

diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 66c36be4db..a6e54b38d1 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -451,6 +451,7 @@ public class Settings protected Boolean metaIncludeSystemIndexes = false; @XmlElement(defaultValue = "false") protected Boolean metaIncludeSystemSequences = false; + protected MigrationSchema migrationHistorySchema; @XmlElement(defaultValue = "false") protected Boolean migrationAllowsUndo = false; @XmlElement(defaultValue = "false") @@ -5268,6 +5269,22 @@ public class Settings this.metaIncludeSystemSequences = value; } + /** + * The database schema where the migration history is located. + * + */ + public MigrationSchema getMigrationHistorySchema() { + return migrationHistorySchema; + } + + /** + * The database schema where the migration history is located. + * + */ + public void setMigrationHistorySchema(MigrationSchema value) { + this.migrationHistorySchema = value; + } + /** * Whether migrations are allowed to be executed in inverse order.

This is a potentially destructive feature, which should not be turned on in production. It is useful mostly to quickly switch between branches in a development environment. This feature is available only in commercial distributions. * @@ -7151,6 +7168,15 @@ public class Settings return this; } + /** + * The database schema where the migration history is located. + * + */ + public Settings withMigrationHistorySchema(MigrationSchema value) { + setMigrationHistorySchema(value); + return this; + } + public Settings withMigrationAllowsUndo(Boolean value) { setMigrationAllowsUndo(value); return this; @@ -7624,6 +7650,7 @@ public class Settings builder.append("interpreterDelayForeignKeyDeclarations", interpreterDelayForeignKeyDeclarations); builder.append("metaIncludeSystemIndexes", metaIncludeSystemIndexes); builder.append("metaIncludeSystemSequences", metaIncludeSystemSequences); + builder.append("migrationHistorySchema", migrationHistorySchema); builder.append("migrationAllowsUndo", migrationAllowsUndo); builder.append("migrationRevertUntracked", migrationRevertUntracked); builder.append("migrationAutoBaseline", migrationAutoBaseline); @@ -9341,6 +9368,15 @@ public class Settings return false; } } + if (migrationHistorySchema == null) { + if (other.migrationHistorySchema!= null) { + return false; + } + } else { + if (!migrationHistorySchema.equals(other.migrationHistorySchema)) { + return false; + } + } if (migrationAllowsUndo == null) { if (other.migrationAllowsUndo!= null) { return false; @@ -9812,6 +9848,7 @@ public class Settings result = ((prime*result)+((interpreterDelayForeignKeyDeclarations == null)? 0 :interpreterDelayForeignKeyDeclarations.hashCode())); result = ((prime*result)+((metaIncludeSystemIndexes == null)? 0 :metaIncludeSystemIndexes.hashCode())); result = ((prime*result)+((metaIncludeSystemSequences == null)? 0 :metaIncludeSystemSequences.hashCode())); + result = ((prime*result)+((migrationHistorySchema == null)? 0 :migrationHistorySchema.hashCode())); result = ((prime*result)+((migrationAllowsUndo == null)? 0 :migrationAllowsUndo.hashCode())); result = ((prime*result)+((migrationRevertUntracked == null)? 0 :migrationRevertUntracked.hashCode())); result = ((prime*result)+((migrationAutoBaseline == null)? 0 :migrationAutoBaseline.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractNode.java b/jOOQ/src/main/java/org/jooq/impl/AbstractNode.java index bf194e1940..31605dc51a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractNode.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractNode.java @@ -51,10 +51,13 @@ import org.jooq.exception.DataDefinitionException; */ abstract class AbstractNode> implements Node { - private final String id; - private final String message; + final N root; + final String id; + final String message; - AbstractNode(String id, String message) { + @SuppressWarnings("unchecked") + AbstractNode(String id, String message, N root) { + this.root = root != null ? root : (N) this; this.id = id; this.message = defaultIfNull(message, ""); } @@ -70,14 +73,8 @@ abstract class AbstractNode> implements Node { } @Override - @SuppressWarnings("unchecked") public final N root() { - N node = (N) this; - - while (!node.parents().isEmpty()) - node = node.parents().get(0); - - return node; + return root; } @SuppressWarnings("unchecked") diff --git a/jOOQ/src/main/java/org/jooq/impl/Changelog.java b/jOOQ/src/main/java/org/jooq/impl/Changelog.java deleted file mode 100644 index fb19e8c010..0000000000 --- a/jOOQ/src/main/java/org/jooq/impl/Changelog.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This file is generated by jOOQ. - */ -package org.jooq.impl; - - -import java.sql.Timestamp; -import java.util.Arrays; -import java.util.List; - -import org.jooq.Check; -import org.jooq.Condition; -import org.jooq.Field; -import org.jooq.Identity; -import org.jooq.Name; -import org.jooq.Table; -import org.jooq.TableField; -import org.jooq.TableOptions; -import org.jooq.UniqueKey; -import org.jooq.impl.MigrationImpl.Status; - - -/** - * The migration log of jOOQ Migrations. - */ -@SuppressWarnings({ "all", "unchecked", "rawtypes" }) -class Changelog extends TableImpl { - - private static final long serialVersionUID = 1L; - - /** - * The reference instance of JOOQ_MIGRATIONS_CHANGELOG - */ - static final Changelog CHANGELOG = new Changelog(); - - /** - * The class holding records for this type - */ - @Override - public Class getRecordType() { - return ChangelogRecord.class; - } - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.ID. The database - * version ID. - */ - final TableField ID = createField(DSL.name("ID"), SQLDataType.INTEGER.nullable(false).identity(true), this, "The database version ID."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The - * previous database version ID. - */ - final TableField MIGRATED_FROM = createField(DSL.name("MIGRATED_FROM"), SQLDataType.VARCHAR(255).nullable(false), this, "The previous database version ID."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO. - */ - final TableField MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), SQLDataType.VARCHAR(255).nullable(false), this, ""); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The - * date/time when the database version was migrated to. - */ - final TableField MIGRATED_AT = createField(DSL.name("MIGRATED_AT"), SQLDataType.TIMESTAMP(6).nullable(false), this, "The date/time when the database version was migrated to."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The - * time in milliseconds it took to migrate to this database version. - */ - final TableField MIGRATION_TIME = createField(DSL.name("MIGRATION_TIME"), SQLDataType.BIGINT, this, "The time in milliseconds it took to migrate to this database version."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ - * version used to migrate to this database version. - */ - final TableField JOOQ_VERSION = createField(DSL.name("JOOQ_VERSION"), SQLDataType.VARCHAR(50).nullable(false), this, "The jOOQ version used to migrate to this database version."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.SQL. The SQL statements - * that were run to install this database version. - */ - final TableField SQL = createField(DSL.name("SQL"), SQLDataType.CLOB, this, "The SQL statements that were run to install this database version."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.SQL_COUNT. The number - * of SQL statements that were run to install this database version. - */ - final TableField SQL_COUNT = createField(DSL.name("SQL_COUNT"), SQLDataType.INTEGER.nullable(false), this, "The number of SQL statements that were run to install this database version."); - - /** - * The column JOOQ_MIGRATIONS_CHANGELOG.STATUS. The database - * version installation status. - */ - final TableField STATUS = createField(DSL.name("STATUS"), SQLDataType.VARCHAR(10).nullable(false), this, "The database version installation status.", new EnumConverter(String.class, Status.class)); - - private Changelog(Name alias, Table aliased) { - this(alias, aliased, (Field[]) null, null); - } - - private Changelog(Name alias, Table aliased, Field[] parameters, Condition where) { - super(alias, null, aliased, parameters, DSL.comment("The migration log of jOOQ Migrations."), TableOptions.table(), where); - } - - /** - * Create an aliased JOOQ_MIGRATIONS_CHANGELOG table reference - */ - Changelog(String alias) { - this(DSL.name(alias), CHANGELOG); - } - - /** - * Create an aliased JOOQ_MIGRATIONS_CHANGELOG table reference - */ - Changelog(Name alias) { - this(alias, CHANGELOG); - } - - /** - * Create a JOOQ_MIGRATIONS_CHANGELOG table reference - */ - Changelog() { - this(DSL.name("JOOQ_MIGRATIONS_CHANGELOG"), null); - } - - @Override - public Identity getIdentity() { - return (Identity) super.getIdentity(); - } - - @Override - public UniqueKey getPrimaryKey() { - return Internal.createUniqueKey(Changelog.CHANGELOG, DSL.name("JOOQ_MIGR_PK"), new TableField[] { Changelog.CHANGELOG.ID }, true); - } - - @Override - public List> getChecks() { - return Arrays.asList( - Internal.createCheck(this, DSL.name("JOOQ_MIGR_CHK1"), "\"STATUS\" IN('STARTING', 'REVERTING', 'MIGRATING', 'SUCCESS', 'FAILURE')", true) - ); - } - - @Override - public Changelog as(String alias) { - return new Changelog(DSL.name(alias), this); - } - - @Override - public Changelog as(Name alias) { - return new Changelog(alias, this); - } - - @Override - public Changelog as(Table alias) { - return new Changelog(alias.getQualifiedName(), this); - } -} diff --git a/jOOQ/src/main/java/org/jooq/impl/CommitImpl.java b/jOOQ/src/main/java/org/jooq/impl/CommitImpl.java index 5a8d2167f7..ef66141fa6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CommitImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CommitImpl.java @@ -75,15 +75,15 @@ import org.jooq.tools.StringUtils; */ final class CommitImpl extends AbstractNode implements Commit { - private final Configuration configuration; - private final DSLContext ctx; - private final List parents; - private final List tags; - private final Map delta; - private final Map files; + final Configuration configuration; + final DSLContext ctx; + final List parents; + final List tags; + final Map delta; + final Map files; - CommitImpl(Configuration configuration, String id, String message, List parents, Collection delta) { - super(id, message); + CommitImpl(Configuration configuration, String id, String message, Commit root, List parents, Collection delta) { + super(id, message, root); this.configuration = configuration; this.ctx = configuration.dsl(); @@ -94,7 +94,7 @@ final class CommitImpl extends AbstractNode implements Commit { } private CommitImpl(CommitImpl copy) { - super(copy.id(), copy.message()); + super(copy.id(), copy.message(), copy.root); this.configuration = copy.configuration; this.ctx = copy.ctx; @@ -192,7 +192,7 @@ final class CommitImpl extends AbstractNode implements Commit { @Override public final Commit commit(String newId, String newMessage, Collection newFiles) { - return new CommitImpl(configuration, newId, newMessage, Arrays.asList(this), newFiles); + return new CommitImpl(configuration, newId, newMessage, root, Arrays.asList(this), newFiles); } @Override @@ -212,7 +212,7 @@ final class CommitImpl extends AbstractNode implements Commit { @Override public final Commit merge(String newId, String newMessage, Commit with, Collection newFiles) { - return new CommitImpl(configuration, newId, newMessage, Arrays.asList(this, with), newFiles); + return new CommitImpl(configuration, newId, newMessage, root, Arrays.asList(this, with), newFiles); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/CommitsImpl.java b/jOOQ/src/main/java/org/jooq/impl/CommitsImpl.java index aeaf3ca211..33c86016ce 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CommitsImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CommitsImpl.java @@ -69,17 +69,19 @@ import org.jooq.migrations.xml.jaxb.FileType; import org.jooq.migrations.xml.jaxb.MigrationsType; import org.jooq.migrations.xml.jaxb.ParentType; import org.jooq.migrations.xml.jaxb.TagType; +import org.jooq.tools.JooqLogger; /** * @author Lukas Eder */ final class CommitsImpl implements Commits { - final Configuration configuration; - final Migrations migrations; - final Commit root; - final Map commitsById; - final Map commitsByTag; + private static final JooqLogger log = JooqLogger.getLogger(CommitsImpl.class); + final Configuration configuration; + final Migrations migrations; + final Commit root; + final Map commitsById; + final Map commitsByTag; CommitsImpl(Configuration configuration, Commit root) { this.configuration = configuration; @@ -92,7 +94,7 @@ final class CommitsImpl implements Commits { } @Override - public void add(Commit commit) { + public final Commits add(Commit commit) { if (root != commit.root()) throw new DataMigrationValidationException("A Commits graph must contain a single graph whose commits all share the same root."); @@ -109,17 +111,24 @@ final class CommitsImpl implements Commits { for (Tag tag : commit.tags()) commitsByTag.put(tag.id(), commit); + + if (log.isDebugEnabled()) + log.debug("Commit added", commit); + + return this; } @Override - public void addAll(Commit... c) { - addAll(asList(c)); + public final Commits addAll(Commit... c) { + return addAll(asList(c)); } @Override - public void addAll(Collection c) { + public final Commits addAll(Collection c) { for (Commit commit : c) add(commit); + + return this; } @Override @@ -206,9 +215,10 @@ final class CommitsImpl implements Commits { java.io.File[] files = directory.listFiles(f -> f.getName().endsWith(".sql")); if (files != null) { - List list = Stream.of(files).map(x -> { - return new FileData(x); - }).collect(toList()); + List list = Stream.of(files).map(FileData::new).collect(toList()); + + if (log.isDebugEnabled()) + list.forEach(f -> log.debug("Reading file", f.basename)); /* * An example: diff --git a/jOOQ/src/main/java/org/jooq/impl/History.java b/jOOQ/src/main/java/org/jooq/impl/History.java new file mode 100644 index 0000000000..993b2ed634 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/History.java @@ -0,0 +1,157 @@ +/* + * This file is generated by jOOQ. + */ +package org.jooq.impl; + + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.List; + +import org.jooq.Check; +import org.jooq.Condition; +import org.jooq.Field; +import org.jooq.Identity; +import org.jooq.Name; +import org.jooq.Table; +import org.jooq.TableField; +import org.jooq.TableOptions; +import org.jooq.UniqueKey; +import org.jooq.impl.MigrationImpl.Status; + + +/** + * The migration history of jOOQ Migrations. + */ +@SuppressWarnings({ "all", "unchecked", "rawtypes" }) +class History extends TableImpl { + + private static final long serialVersionUID = 1L; + + /** + * The reference instance of JOOQ_MIGRATION_HISTORY + */ + static final History HISTORY = new History(); + + /** + * The class holding records for this type + */ + @Override + public Class getRecordType() { + return HistoryRecord.class; + } + + /** + * The column JOOQ_MIGRATION_HISTORY.ID. The database version + * ID. + */ + final TableField ID = createField(DSL.name("ID"), SQLDataType.INTEGER.nullable(false).identity(true), this, "The database version ID."); + + /** + * The column JOOQ_MIGRATION_HISTORY.MIGRATED_FROM. The + * previous database version ID. + */ + final TableField MIGRATED_FROM = createField(DSL.name("MIGRATED_FROM"), SQLDataType.VARCHAR(255).nullable(false), this, "The previous database version ID."); + + /** + * The column JOOQ_MIGRATION_HISTORY.MIGRATED_TO. + */ + final TableField MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), SQLDataType.VARCHAR(255).nullable(false), this, ""); + + /** + * The column JOOQ_MIGRATION_HISTORY.MIGRATED_AT. The date/time + * when the database version was migrated to. + */ + final TableField MIGRATED_AT = createField(DSL.name("MIGRATED_AT"), SQLDataType.TIMESTAMP(6).nullable(false), this, "The date/time when the database version was migrated to."); + + /** + * The column JOOQ_MIGRATION_HISTORY.MIGRATION_TIME. The time + * in milliseconds it took to migrate to this database version. + */ + final TableField MIGRATION_TIME = createField(DSL.name("MIGRATION_TIME"), SQLDataType.BIGINT, this, "The time in milliseconds it took to migrate to this database version."); + + /** + * The column JOOQ_MIGRATION_HISTORY.JOOQ_VERSION. The jOOQ + * version used to migrate to this database version. + */ + final TableField JOOQ_VERSION = createField(DSL.name("JOOQ_VERSION"), SQLDataType.VARCHAR(50).nullable(false), this, "The jOOQ version used to migrate to this database version."); + + /** + * The column JOOQ_MIGRATION_HISTORY.SQL. The SQL statements + * that were run to install this database version. + */ + final TableField SQL = createField(DSL.name("SQL"), SQLDataType.CLOB, this, "The SQL statements that were run to install this database version."); + + /** + * The column JOOQ_MIGRATION_HISTORY.SQL_COUNT. The number of + * SQL statements that were run to install this database version. + */ + final TableField SQL_COUNT = createField(DSL.name("SQL_COUNT"), SQLDataType.INTEGER.nullable(false), this, "The number of SQL statements that were run to install this database version."); + + /** + * The column JOOQ_MIGRATION_HISTORY.STATUS. The database + * version installation status. + */ + final TableField STATUS = createField(DSL.name("STATUS"), SQLDataType.VARCHAR(10).nullable(false), this, "The database version installation status.", new EnumConverter(String.class, Status.class)); + + private History(Name alias, Table aliased) { + this(alias, aliased, (Field[]) null, null); + } + + private History(Name alias, Table aliased, Field[] parameters, Condition where) { + super(alias, null, aliased, parameters, DSL.comment("The migration history of jOOQ Migrations."), TableOptions.table(), where); + } + + /** + * Create an aliased JOOQ_MIGRATION_HISTORY table reference + */ + History(String alias) { + this(DSL.name(alias), HISTORY); + } + + /** + * Create an aliased JOOQ_MIGRATION_HISTORY table reference + */ + History(Name alias) { + this(alias, HISTORY); + } + + /** + * Create a JOOQ_MIGRATION_HISTORY table reference + */ + History() { + this(DSL.name("JOOQ_MIGRATION_HISTORY"), null); + } + + @Override + public Identity getIdentity() { + return (Identity) super.getIdentity(); + } + + @Override + public UniqueKey getPrimaryKey() { + return Internal.createUniqueKey(History.HISTORY, DSL.name("JOOQ_MIGR_HIST_PK"), new TableField[] { History.HISTORY.ID }, true); + } + + @Override + public List> getChecks() { + return Arrays.asList( + Internal.createCheck(this, DSL.name("JOOQ_MIGR_HIST_CHK1"), "\"STATUS\" IN('STARTING', 'REVERTING', 'MIGRATING', 'SUCCESS', 'FAILURE')", true) + ); + } + + @Override + public History as(String alias) { + return new History(DSL.name(alias), this); + } + + @Override + public History as(Name alias) { + return new History(alias, this); + } + + @Override + public History as(Table alias) { + return new History(alias.getQualifiedName(), this); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/ChangelogRecord.java b/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java similarity index 50% rename from jOOQ/src/main/java/org/jooq/impl/ChangelogRecord.java rename to jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java index 65884dc301..038c673e3a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ChangelogRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/HistoryRecord.java @@ -11,41 +11,41 @@ import org.jooq.impl.MigrationImpl.Status; /** - * The migration log of jOOQ Migrations. + * The migration history of jOOQ Migrations. */ @SuppressWarnings({ "all", "unchecked", "rawtypes" }) -class ChangelogRecord extends UpdatableRecordImpl { +class HistoryRecord extends UpdatableRecordImpl { private static final long serialVersionUID = 1L; /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.ID. The database - * version ID. + * Setter for JOOQ_MIGRATION_HISTORY.ID. The database version + * ID. */ - ChangelogRecord setId(Integer value) { + HistoryRecord setId(Integer value) { set(0, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.ID. The database - * version ID. + * Getter for JOOQ_MIGRATION_HISTORY.ID. The database version + * ID. */ Integer getId() { return (Integer) get(0); } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The + * Setter for JOOQ_MIGRATION_HISTORY.MIGRATED_FROM. The * previous database version ID. */ - ChangelogRecord setMigratedFrom(String value) { + HistoryRecord setMigratedFrom(String value) { set(1, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_FROM. The + * Getter for JOOQ_MIGRATION_HISTORY.MIGRATED_FROM. The * previous database version ID. */ String getMigratedFrom() { @@ -53,65 +53,65 @@ class ChangelogRecord extends UpdatableRecordImpl { } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO. + * Setter for JOOQ_MIGRATION_HISTORY.MIGRATED_TO. */ - ChangelogRecord setMigratedTo(String value) { + HistoryRecord setMigratedTo(String value) { set(2, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_TO. + * Getter for JOOQ_MIGRATION_HISTORY.MIGRATED_TO. */ String getMigratedTo() { return (String) get(2); } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The - * date/time when the database version was migrated to. + * Setter for JOOQ_MIGRATION_HISTORY.MIGRATED_AT. The date/time + * when the database version was migrated to. */ - ChangelogRecord setMigratedAt(Timestamp value) { + HistoryRecord setMigratedAt(Timestamp value) { set(3, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATED_AT. The - * date/time when the database version was migrated to. + * Getter for JOOQ_MIGRATION_HISTORY.MIGRATED_AT. The date/time + * when the database version was migrated to. */ Timestamp getMigratedAt() { return (Timestamp) get(3); } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The - * time in milliseconds it took to migrate to this database version. + * Setter for JOOQ_MIGRATION_HISTORY.MIGRATION_TIME. The time + * in milliseconds it took to migrate to this database version. */ - ChangelogRecord setMigrationTime(Long value) { + HistoryRecord setMigrationTime(Long value) { set(4, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.MIGRATION_TIME. The - * time in milliseconds it took to migrate to this database version. + * Getter for JOOQ_MIGRATION_HISTORY.MIGRATION_TIME. The time + * in milliseconds it took to migrate to this database version. */ Long getMigrationTime() { return (Long) get(4); } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ + * Setter for JOOQ_MIGRATION_HISTORY.JOOQ_VERSION. The jOOQ * version used to migrate to this database version. */ - ChangelogRecord setJooqVersion(String value) { + HistoryRecord setJooqVersion(String value) { set(5, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.JOOQ_VERSION. The jOOQ + * Getter for JOOQ_MIGRATION_HISTORY.JOOQ_VERSION. The jOOQ * version used to migrate to this database version. */ String getJooqVersion() { @@ -119,16 +119,16 @@ class ChangelogRecord extends UpdatableRecordImpl { } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.SQL. The SQL statements + * Setter for JOOQ_MIGRATION_HISTORY.SQL. The SQL statements * that were run to install this database version. */ - ChangelogRecord setSql(String value) { + HistoryRecord setSql(String value) { set(6, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.SQL. The SQL statements + * Getter for JOOQ_MIGRATION_HISTORY.SQL. The SQL statements * that were run to install this database version. */ String getSql() { @@ -136,33 +136,33 @@ class ChangelogRecord extends UpdatableRecordImpl { } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.SQL_COUNT. The number - * of SQL statements that were run to install this database version. + * Setter for JOOQ_MIGRATION_HISTORY.SQL_COUNT. The number of + * SQL statements that were run to install this database version. */ - ChangelogRecord setSqlCount(Integer value) { + HistoryRecord setSqlCount(Integer value) { set(7, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.SQL_COUNT. The number - * of SQL statements that were run to install this database version. + * Getter for JOOQ_MIGRATION_HISTORY.SQL_COUNT. The number of + * SQL statements that were run to install this database version. */ Integer getSqlCount() { return (Integer) get(7); } /** - * Setter for JOOQ_MIGRATIONS_CHANGELOG.STATUS. The database + * Setter for JOOQ_MIGRATION_HISTORY.STATUS. The database * version installation status. */ - ChangelogRecord setStatus(Status value) { + HistoryRecord setStatus(Status value) { set(8, value); return this; } /** - * Getter for JOOQ_MIGRATIONS_CHANGELOG.STATUS. The database + * Getter for JOOQ_MIGRATION_HISTORY.STATUS. The database * version installation status. */ Status getStatus() { @@ -183,17 +183,17 @@ class ChangelogRecord extends UpdatableRecordImpl { // ------------------------------------------------------------------------- /** - * Create a detached ChangelogRecord + * Create a detached HistoryRecord */ - ChangelogRecord() { - super(Changelog.CHANGELOG); + HistoryRecord() { + super(History.HISTORY); } /** - * Create a detached, initialised ChangelogRecord + * Create a detached, initialised HistoryRecord */ - ChangelogRecord(Integer id, String migratedFrom, String migratedTo, Timestamp migratedAt, Long migrationTime, String jooqVersion, String sql, Integer sqlCount, Status status) { - super(Changelog.CHANGELOG); + HistoryRecord(Integer id, String migratedFrom, String migratedTo, Timestamp migratedAt, Long migrationTime, String jooqVersion, String sql, Integer sqlCount, Status status) { + super(History.HISTORY); setId(id); setMigratedFrom(migratedFrom); diff --git a/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java index e9a7429f82..d51cdc1f96 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MigrationImpl.java @@ -40,18 +40,19 @@ package org.jooq.impl; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static java.util.Arrays.asList; -import static org.jooq.impl.Changelog.CHANGELOG; import static org.jooq.impl.DSL.createSchemaIfNotExists; import static org.jooq.impl.DSL.dropSchemaIfExists; import static org.jooq.impl.DSL.dropTableIfExists; import static org.jooq.impl.DSL.inline; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.schema; +import static org.jooq.impl.History.HISTORY; import static org.jooq.impl.MigrationImpl.Status.FAILURE; import static org.jooq.impl.MigrationImpl.Status.MIGRATING; import static org.jooq.impl.MigrationImpl.Status.REVERTING; import static org.jooq.impl.MigrationImpl.Status.STARTING; import static org.jooq.impl.MigrationImpl.Status.SUCCESS; +import static org.jooq.tools.StringUtils.isBlank; import java.sql.Timestamp; import java.util.Collection; @@ -65,6 +66,7 @@ import org.jooq.Commits; import org.jooq.Configuration; import org.jooq.Constants; import org.jooq.ContextTransactionalRunnable; +import org.jooq.DSLContext; import org.jooq.Files; import org.jooq.Meta; import org.jooq.Migration; @@ -73,7 +75,10 @@ import org.jooq.Queries; import org.jooq.Query; import org.jooq.Schema; import org.jooq.conf.InterpreterSearchSchema; +import org.jooq.conf.MappedCatalog; +import org.jooq.conf.MappedSchema; import org.jooq.conf.MigrationSchema; +import org.jooq.conf.RenderMapping; import org.jooq.exception.DataAccessException; import org.jooq.exception.DataMigrationException; import org.jooq.exception.DataMigrationValidationException; @@ -85,16 +90,51 @@ import org.jooq.tools.StopWatch; */ final class MigrationImpl extends AbstractScope implements Migration { - private static final JooqLogger log = JooqLogger.getLogger(Migration.class); - private final Commit to; - private Commit from; - private Queries queries; - private Commits commits; + static final JooqLogger log = JooqLogger.getLogger(Migration.class); + final DSLContext historyCtx; + final Commit to; + Commit from; + Queries queries; + Commits commits; MigrationImpl(Configuration configuration, Commit to) { super(configuration.derive(new ThreadLocalTransactionProvider(configuration.systemConnectionProvider()))); this.to = to; + this.historyCtx = initHistoryCtx(configuration()); + } + + private static final DSLContext initHistoryCtx(Configuration configuration) { + MigrationSchema m = configuration.settings().getMigrationHistorySchema(); + + if (m != null) { + DSLContext result = configuration.derive().dsl(); + + if (!isBlank(m.getCatalog())) { + result.settings().withRenderMapping(new RenderMapping() + .withCatalogs(new MappedCatalog() + .withInput("") + .withOutput(m.getCatalog()) + .withSchemata(new MappedSchema() + .withInput("") + .withOutput(m.getSchema()) + ) + ) + ); + } + else if (!isBlank(m.getSchema())) { + result.settings().withRenderMapping(new RenderMapping() + .withSchemata(new MappedSchema() + .withInput("") + .withOutput(m.getSchema()) + ) + ); + } + + return result; + } + else + return configuration.dsl(); } @Override @@ -135,7 +175,7 @@ final class MigrationImpl extends AbstractScope implements Migration { } private final void validate0(DefaultMigrationContext ctx) { - ChangelogRecord currentRecord = currentChangelogRecord(); + HistoryRecord currentRecord = currentHistoryRecord(); if (currentRecord != null) { Commit currentCommit = commits().get(currentRecord.getMigratedTo()); @@ -194,7 +234,7 @@ final class MigrationImpl extends AbstractScope implements Migration { continue schemaLoop; // TODO Why is this qualification necessary? - existingMeta = existingMeta.apply(dropTableIfExists(schema.getQualifiedName().append(CHANGELOG.getUnqualifiedName())).cascade()); + existingMeta = existingMeta.apply(dropTableIfExists(schema.getQualifiedName().append(HISTORY.getUnqualifiedName())).cascade()); if (!expectedSchemas.contains(schema)) existingMeta = existingMeta.apply(dropSchemaIfExists(schema).cascade()); @@ -205,7 +245,7 @@ final class MigrationImpl extends AbstractScope implements Migration { return existingMeta.migrateTo(currentMeta); } - private final void revertUntracked(DefaultMigrationContext ctx, MigrationListener listener, ChangelogRecord currentRecord) { + private final void revertUntracked(DefaultMigrationContext ctx, MigrationListener listener, HistoryRecord currentRecord) { if (ctx.revertUntrackedQueries.queries().length > 0) if (!TRUE.equals(dsl().settings().isMigrationRevertUntracked())) throw new DataMigrationValidationException( @@ -264,11 +304,11 @@ final class MigrationImpl extends AbstractScope implements Migration { // TODO: Implement a listener with a variety of pro / oss features // TODO: Implement additional out-of-the-box sanity checks // TODO: Allow undo migrations only if enabled explicitly - // TODO: Add some migration settings, e.g. whether CHANGELOG.SQL should be filled - // TODO: Migrate the CHANGELOG table with the Migration API - // TODO: Create an Enum for CHANGELOG.STATUS - // TODO: Add CHANGELOG.USERNAME and HOSTNAME columns - // TODO: Add CHANGELOG.COMMENTS column + // TODO: Add some migration settings, e.g. whether HISTORY.SQL should be filled + // TODO: Migrate the HISTORY table with the Migration API + // TODO: Create an Enum for HISTORY.STATUS + // TODO: Add HISTORY.USERNAME and HOSTNAME columns + // TODO: Add HISTORY.COMMENTS column // TODO: Replace (MIGRATED_AT, MIGRATION_TIME) by (MIGRATION_START, MIGRATION_END) log.info("jOOQ Migrations", "Version " + from().id() + " is migrated to " + to().id()); @@ -280,7 +320,7 @@ final class MigrationImpl extends AbstractScope implements Migration { for (Query query : queries()) log.debug("jOOQ Migrations", dsl().renderInlined(query)); - ChangelogRecord record = createRecord(STARTING); + HistoryRecord record = createRecord(STARTING); try { log(watch, record, REVERTING); @@ -302,8 +342,8 @@ final class MigrationImpl extends AbstractScope implements Migration { } } - private final ChangelogRecord createRecord(Status status) { - ChangelogRecord record = dsl().newRecord(CHANGELOG); + private final HistoryRecord createRecord(Status status) { + HistoryRecord record = historyCtx.newRecord(HISTORY); record .setJooqVersion(Constants.VERSION) @@ -319,7 +359,7 @@ final class MigrationImpl extends AbstractScope implements Migration { return record; } - private final void log(StopWatch watch, ChangelogRecord record, Status status) { + private final void log(StopWatch watch, HistoryRecord record, Status status) { record.setMigrationTime(watch.split() / 1000000L) .setStatus(status) .update(); @@ -346,22 +386,27 @@ final class MigrationImpl extends AbstractScope implements Migration { /** * Initialise the underlying {@link Configuration} with the jOOQ Migrations - * Changelog. + * History. */ public final void init() { // TODO: What to do when initialising jOOQ-migrations on an existing database? // - Should there be init() commands that can be run explicitly by the user? // - Will we reverse engineer the production Meta snapshot first? - if (!existsChangelog()) - dsl().meta(CHANGELOG).ddl().executeBatch(); + if (!existsHistory()) { + // TODO: [#15225] This CREATE SCHEMA statement should never be necessary. + if (historyCtx.settings().getMigrationHistorySchema() != null) + historyCtx.createSchemaIfNotExists("").execute(); + + historyCtx.meta(HISTORY).ddl().executeBatch(); + } } - private final boolean existsChangelog() { + private final boolean existsHistory() { // [#8301] Find a better way to test if our table already exists try { - dsl().fetchExists(CHANGELOG); + historyCtx.fetchExists(HISTORY); return true; } catch (DataAccessException ignore) {} @@ -369,20 +414,20 @@ final class MigrationImpl extends AbstractScope implements Migration { return false; } - private final ChangelogRecord currentChangelogRecord() { - return existsChangelog() - ? dsl().selectFrom(CHANGELOG) + private final HistoryRecord currentHistoryRecord() { + return existsHistory() + ? historyCtx.selectFrom(HISTORY) // TODO: How to recover from failure? - .where(CHANGELOG.STATUS.eq(inline(SUCCESS))) - .orderBy(CHANGELOG.MIGRATED_AT.desc(), CHANGELOG.ID.desc()) + .where(HISTORY.STATUS.eq(inline(SUCCESS))) + .orderBy(HISTORY.MIGRATED_AT.desc(), HISTORY.ID.desc()) .limit(1) .fetchOne() : null; } final Commit currentCommit() { - ChangelogRecord currentRecord = currentChangelogRecord(); + HistoryRecord currentRecord = currentHistoryRecord(); if (currentRecord == null) { Commit result = TRUE.equals(settings().isMigrationAutoBaseline()) ? to() : to().root(); diff --git a/jOOQ/src/main/java/org/jooq/impl/MigrationsImpl.java b/jOOQ/src/main/java/org/jooq/impl/MigrationsImpl.java index 6482c704fa..9223c245fd 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MigrationsImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MigrationsImpl.java @@ -67,7 +67,7 @@ final class MigrationsImpl implements Migrations { @Override public final Version version(String id) { - return new VersionImpl(ctx, id, null, new Version[0]); + return new VersionImpl(ctx, id, null, null, new Version[0]); } @Override @@ -75,14 +75,9 @@ final class MigrationsImpl implements Migrations { return new VersionsImpl(version("init")); } - @Override - public final Commit commit(String id) { - return new CommitImpl(ctx.configuration(), id, null, emptyList(), emptyList()); - } - @Override public final Commits commits() { - return new CommitsImpl(ctx.configuration(), commit("init")); + return new CommitsImpl(ctx.configuration(), new CommitImpl(ctx.configuration(), "init", null, null, emptyList(), emptyList())); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java index 9e9d0e0aaa..307bb35add 100644 --- a/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/VersionImpl.java @@ -70,12 +70,12 @@ import org.jooq.exception.DataDefinitionException; */ final class VersionImpl extends AbstractNode implements Version { - private final DSLContext ctx; - private final Meta meta; - private final List parents; + final DSLContext ctx; + final Meta meta; + final List parents; - private VersionImpl(DSLContext ctx, String id, Meta meta, List parents) { - super(id, null); + private VersionImpl(DSLContext ctx, String id, Meta meta, Version root, List parents) { + super(id, null, root); this.ctx = ctx; this.meta = meta != null ? meta : init(ctx); @@ -95,12 +95,12 @@ final class VersionImpl extends AbstractNode implements Version { return result; } - VersionImpl(DSLContext ctx, String id, Meta meta, Version parent, Queries queries) { - this(ctx, id, meta, Arrays.asList(new Parent((VersionImpl) parent, queries))); + VersionImpl(DSLContext ctx, String id, Meta meta, Version root, Version parent, Queries queries) { + this(ctx, id, meta, root, Arrays.asList(new Parent((VersionImpl) parent, queries))); } - VersionImpl(DSLContext ctx, String id, Meta meta, Version[] parents) { - this(ctx, id, meta, wrap(parents)); + VersionImpl(DSLContext ctx, String id, Meta meta, Version root, Version[] parents) { + this(ctx, id, meta, root, wrap(parents)); } private static List wrap(Version[] parents) { @@ -144,7 +144,7 @@ final class VersionImpl extends AbstractNode implements Version { @Override public final Version apply(String newId, Queries migration) { - return new VersionImpl(ctx, newId, meta().apply(migration), this, migration); + return new VersionImpl(ctx, newId, meta().apply(migration), root, this, migration); } @Override @@ -173,7 +173,7 @@ final class VersionImpl extends AbstractNode implements Version { if (list == null) list = new ArrayList<>(); - list.add(new Parent(new VersionImpl(ctx, parent.version.id(), parent.version.meta, emptyList()), parent.queries)); + list.add(new Parent(new VersionImpl(ctx, parent.version.id(), parent.version.meta, root, emptyList()), parent.queries)); } else { VersionImpl p = parent.version.subgraphTo(ancestor); @@ -187,7 +187,7 @@ final class VersionImpl extends AbstractNode implements Version { } } - return list == null ? null : new VersionImpl(ctx, id(), meta, list); + return list == null ? null : new VersionImpl(ctx, id(), meta, root, list); } private final Queries migrateTo(VersionImpl target, Queries result) { @@ -222,13 +222,13 @@ final class VersionImpl extends AbstractNode implements Version { @Override public final Version commit(String newId, Meta newMeta) { - return new VersionImpl(ctx, newId, newMeta, new Version[] { this }); + return new VersionImpl(ctx, newId, newMeta, root, new Version[] { this }); } @Override public final Version merge(String newId, Version with) { Meta m = commonAncestor(with).meta(); - return new VersionImpl(ctx, newId, m.apply(m.migrateTo(meta()).concat(m.migrateTo(with.meta()))), new Version[] { this, with }); + return new VersionImpl(ctx, newId, m.apply(m.migrateTo(meta()).concat(m.migrateTo(with.meta()))), root, new Version[] { this, with }); } @Override diff --git a/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql b/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql index cffd019176..85a6ed9546 100644 --- a/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql +++ b/jOOQ/src/main/resources/org/jooq/migrations/v1-init.sql @@ -1,4 +1,4 @@ -CREATE TABLE jooq_migrations_changelog ( +CREATE TABLE jooq_migration_history ( id BIGINT NOT NULL IDENTITY, migrated_from VARCHAR(255) NOT NULL, migrated_to VARCHAR(255) NOT NULL, @@ -9,18 +9,18 @@ CREATE TABLE jooq_migrations_changelog ( sql_count INT NOT NULL, status VARCHAR(10) NOT NULL, - CONSTRAINT jooq_migr_pk PRIMARY KEY (id), - CONSTRAINT jooq_migr_chk1 CHECK (status IN ('STARTING', 'REVERTING', 'MIGRATING', 'SUCCESS', 'FAILURE')) + CONSTRAINT jooq_migr_hist_pk PRIMARY KEY (id), + CONSTRAINT jooq_migr_hist_chk1 CHECK (status IN ('STARTING', 'REVERTING', 'MIGRATING', 'SUCCESS', 'FAILURE')) ); -CREATE INDEX jooq_migr_i1 ON jooq_migrations_changelog (migrated_at); +CREATE INDEX jooq_migr_hist_i1 ON jooq_migration_history (migrated_at); -COMMENT ON TABLE jooq_migrations_changelog IS 'The migration log of jOOQ Migrations.'; -COMMENT ON COLUMN jooq_migrations_changelog.id IS 'The database version ID.'; -COMMENT ON COLUMN jooq_migrations_changelog.migrated_from IS 'The previous database version ID.'; -COMMENT ON COLUMN jooq_migrations_changelog.migrated_at IS 'The date/time when the database version was migrated to.'; -COMMENT ON COLUMN jooq_migrations_changelog.migration_time IS 'The time in milliseconds it took to migrate to this database version.'; -COMMENT ON COLUMN jooq_migrations_changelog.jooq_version IS 'The jOOQ version used to migrate to this database version.'; -COMMENT ON COLUMN jooq_migrations_changelog.sql_count IS 'The number of SQL statements that were run to install this database version.'; -COMMENT ON COLUMN jooq_migrations_changelog.sql IS 'The SQL statements that were run to install this database version.'; -COMMENT ON COLUMN jooq_migrations_changelog.status IS 'The database version installation status.'; +COMMENT ON TABLE jooq_migration_history IS 'The migration history of jOOQ Migrations.'; +COMMENT ON COLUMN jooq_migration_history.id IS 'The database version ID.'; +COMMENT ON COLUMN jooq_migration_history.migrated_from IS 'The previous database version ID.'; +COMMENT ON COLUMN jooq_migration_history.migrated_at IS 'The date/time when the database version was migrated to.'; +COMMENT ON COLUMN jooq_migration_history.migration_time IS 'The time in milliseconds it took to migrate to this database version.'; +COMMENT ON COLUMN jooq_migration_history.jooq_version IS 'The jOOQ version used to migrate to this database version.'; +COMMENT ON COLUMN jooq_migration_history.sql_count IS 'The number of SQL statements that were run to install this database version.'; +COMMENT ON COLUMN jooq_migration_history.sql IS 'The SQL statements that were run to install this database version.'; +COMMENT ON COLUMN jooq_migration_history.status IS 'The database version installation status.'; diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd index e859f15932..f59dca0556 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd @@ -1445,6 +1445,10 @@ deployed on an RDBMS that does not.]]> + + + + diff --git a/pom.xml b/pom.xml index 94740eefde..a67ef9be34 100644 --- a/pom.xml +++ b/pom.xml @@ -131,6 +131,11 @@ jooq-codegen-maven ${project.version} + + org.jooq + jooq-migrations-maven + ${project.version} + org.jooq jooq-meta @@ -882,10 +887,7 @@ - jOOQ-checker - - jOOQ-jackson-extensions jOOQ-postgres-extensions @@ -895,10 +897,9 @@ jOOQ-meta-extensions-liquibase jOOQ-codegen jOOQ-codegen-maven - + jOOQ-migrations-maven jOOQ-migrations - jOOQ-kotlin jOOQ-kotlin-coroutines jOOQ-scala_2.13 @@ -921,6 +922,7 @@ +