* This does not run the migration or ddl scripts but just generates them. *
@@ -186,4 +186,15 @@ public interface DbMigration { * @return the version of the generated migration or null */ String generateMigration() throws IOException; + + /** + * Generate an "init" migration which has all changes. + *+ * An "init" migration can only be executed and used on a database that has had no + * prior migrations run on it. + *
+ * @return the version of the generated migration + */ + String generateInitMigration() throws IOException; + } diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index a85e3f651..bf92237dc 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -271,6 +271,15 @@ public class DefaultDbMigration implements DbMigration { */ @Override public String generateMigration() throws IOException { + return generateMigrationFor(false); + } + + @Override + public String generateInitMigration() throws IOException { + return generateMigrationFor(true); + } + + private String generateMigrationFor(boolean dbinitMigration) throws IOException { // use this flag to stop other plugins like full DDL generation if (!online) { @@ -286,14 +295,17 @@ public class DefaultDbMigration implements DbMigration { configurePlatforms(); } try { - Request request = createRequest(); - if (platforms.isEmpty()) { - generateExtraDdl(request.migrationDir, databasePlatform, request.isTablePartitioning()); - } else { - for (Pair pair : platforms) { - PlatformDdlWriter platformWriter = createDdlWriter(pair.platform); - File subPath = platformWriter.subPath(request.migrationDir, pair.prefix); - generateExtraDdl(subPath, pair.platform, request.isTablePartitioning()); + Request request = createRequest(dbinitMigration); + if (!dbinitMigration) { + // repeatable migrations + if (platforms.isEmpty()) { + generateExtraDdl(request.migrationDir, databasePlatform, request.isTablePartitioning()); + } else { + for (Pair pair : platforms) { + PlatformDdlWriter platformWriter = createDdlWriter(pair.platform); + File subPath = platformWriter.subPath(request.migrationDir, pair.prefix); + generateExtraDdl(subPath, pair.platform, request.isTablePartitioning()); + } } } @@ -321,7 +333,7 @@ public class DefaultDbMigration implements DbMigration { } setDefaults(); try { - return createRequest().getPendingDrops(); + return createRequest(false).getPendingDrops(); } finally { if (!online) { DbOffline.reset(); @@ -433,32 +445,48 @@ public class DefaultDbMigration implements DbMigration { return version; } - private Request createRequest() { - return new Request(); + private Request createRequest(boolean dbinitMigration) { + return new Request(dbinitMigration); } private class Request { + final boolean dbinitMigration; final File migrationDir; final File modelDir; - final MigrationModel migrationModel; final CurrentModel currentModel; final ModelContainer migrated; final ModelContainer current; - private Request() { - this.migrationDir = getMigrationDirectory(); - this.modelDir = getModelDirectory(migrationDir); - this.migrationModel = new MigrationModel(modelDir, migrationConfig.getModelSuffix()); - this.migrated = migrationModel.read(); + private Request(boolean dbinitMigration) { + this.dbinitMigration = dbinitMigration; this.currentModel = new CurrentModel(server, constraintNaming); this.current = currentModel.read(); + this.migrationDir = getMigrationDirectory(dbinitMigration); + if (dbinitMigration) { + this.modelDir = null; + this.migrated = new ModelContainer(); + } else { + this.modelDir = getModelDirectory(migrationDir); + MigrationModel migrationModel = new MigrationModel(modelDir, migrationConfig.getModelSuffix()); + this.migrated = migrationModel.read(dbinitMigration); + } } boolean isTablePartitioning() { return current.isTablePartitioning(); } + /** + * Return the next migration version (based on existing migration versions). + */ + String nextVersion() { + // always read the next version using the main migration directory (not dbinit) + File migDirectory = getMigrationDirectory(false); + File modelDir = getModelDirectory(migDirectory); + return LastMigration.nextVersion(migDirectory, modelDir, dbinitMigration); + } + /** * Return the migration for the pending drops for a given version. */ @@ -490,10 +518,10 @@ public class DefaultDbMigration implements DbMigration { private String generateMigration(Request request, Migration dbMigration, String dropsFor) throws IOException { - String fullVersion = getFullVersion(request.migrationModel, dropsFor); + String fullVersion = getFullVersion(request.nextVersion(), dropsFor); logger.info("generating migration:{}", fullVersion); - if (!writeMigrationXml(dbMigration, request.modelDir, fullVersion)) { + if (!request.dbinitMigration && !writeMigrationXml(dbMigration, request.modelDir, fullVersion)) { logger.warn("migration already exists, not generating DDL"); return null; } else { @@ -528,11 +556,11 @@ public class DefaultDbMigration implements DbMigration { *
* The full version can contain a comment suffix after a "__" double underscore.
*/
- private String getFullVersion(MigrationModel migrationModel, String dropsFor) {
+ private String getFullVersion(String nextVersion, String dropsFor) {
String version = getVersion();
if (version == null) {
- version = migrationModel.getNextVersion(initialVersion);
+ version = (nextVersion != null) ? nextVersion : initialVersion;
}
String fullVersion = migrationConfig.getApplyPrefix() + version;
@@ -672,13 +700,20 @@ public class DefaultDbMigration implements DbMigration {
}
/**
- * Return the file path to write the xml and sql to.
+ * Return the main migration directory.
*/
File getMigrationDirectory() {
+ return getMigrationDirectory(false);
+ }
+
+ /**
+ * Return the file path to write the xml and sql to.
+ */
+ File getMigrationDirectory(boolean dbinitMigration) {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
- String resourcePath = migrationConfig.getMigrationPath();
+ String resourcePath = migrationConfig.getMigrationPath(dbinitMigration);
// expect to be a path to something like - src/main/resources/dbmigration/model
File path = new File(resourceRootDir, resourcePath);
diff --git a/src/main/java/io/ebeaninternal/dbmigration/LastMigration.java b/src/main/java/io/ebeaninternal/dbmigration/LastMigration.java
new file mode 100644
index 000000000..102eb87a9
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/dbmigration/LastMigration.java
@@ -0,0 +1,91 @@
+package io.ebeaninternal.dbmigration;
+
+import io.ebeaninternal.dbmigration.model.MigrationVersion;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility to determine the last sql migration version and next version.
+ */
+class LastMigration {
+
+ private static final String SQL = ".sql";
+
+ private static final String MODEL_XML = ".model.xml";
+
+ /**
+ * Return the next migation version given the migration directory.
+ */
+ static String nextVersion(File migDir, File modelDir, boolean dbinitMigration) {
+
+ String last = lastVersion(migDir, modelDir);
+ if (last == null) {
+ return null;
+ }
+ return (dbinitMigration) ? last : MigrationVersion.parse(last).nextVersion();
+ }
+
+ /**
+ * Return the last migation version given the migration directory.
+ */
+ static String lastVersion(File migDirectory, File modelDir) {
+
+ List