mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32d4b83a86 | ||
|
|
ca824c5e0d | ||
|
|
b2f7664316 | ||
|
|
062f7a281f | ||
|
|
019ce4e614 | ||
|
|
6b490ed8b1 | ||
|
|
1bee6fcae5 | ||
|
|
097552b8d3 |
+2
-1
@@ -1,5 +1,6 @@
|
||||
*.autofetch
|
||||
*.sql
|
||||
*create-all.sql
|
||||
*drop-all.sql
|
||||
*.orig
|
||||
.classpath
|
||||
.project
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>6.16.5</version>
|
||||
<version>6.17.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
|
||||
@@ -23,11 +23,6 @@ public class DbMigrationConfig {
|
||||
*/
|
||||
protected boolean generate;
|
||||
|
||||
/**
|
||||
* Set to true to suppress the output of the rollback script.
|
||||
*/
|
||||
protected boolean suppressRollback;
|
||||
|
||||
/**
|
||||
* The migration version name (typically FlywayDb compatible).
|
||||
* <p>
|
||||
@@ -61,35 +56,17 @@ public class DbMigrationConfig {
|
||||
*/
|
||||
protected String modelPath = "model";
|
||||
|
||||
/**
|
||||
* Subdirectory the drop ddl scripts go into.
|
||||
*/
|
||||
protected String dropPath = "drop";
|
||||
|
||||
/**
|
||||
* Subdirectory the rollback ddl scripts go into.
|
||||
*/
|
||||
protected String rollbackPath = "rollback";
|
||||
|
||||
/**
|
||||
* Apply script suffix.
|
||||
*/
|
||||
protected String applySuffix = ".sql";
|
||||
|
||||
/**
|
||||
* Default drop script suffix to ddl so that it isn't picked up by FlywayDb.
|
||||
*/
|
||||
protected String dropSuffix = ".drop.ddl";
|
||||
|
||||
/**
|
||||
* Default rollback script suffix to ddl so that it isn't picked up by FlywayDb.
|
||||
*/
|
||||
protected String rollbackSuffix = ".rollback.ddl";
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
protected boolean includeGeneratedFileComment;
|
||||
|
||||
/**
|
||||
* The version of a pending drop that should be generated as the next migration.
|
||||
*/
|
||||
protected String generatePendingDrop;
|
||||
|
||||
/**
|
||||
* Return the DB platform to generate migration DDL for.
|
||||
*
|
||||
@@ -140,34 +117,6 @@ public class DbMigrationConfig {
|
||||
this.modelPath = modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path for the drop ddl scripts (defaults to drop).
|
||||
*/
|
||||
public String getDropPath() {
|
||||
return dropPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative path for the drop ddl scripts (defaults to drop).
|
||||
*/
|
||||
public void setDropPath(String dropPath) {
|
||||
this.dropPath = dropPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path for the rollback ddl scripts (defaults to rollback).
|
||||
*/
|
||||
public String getRollbackPath() {
|
||||
return rollbackPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative path for the rollback ddl scripts (defaults to rollback).
|
||||
*/
|
||||
public void setRollbackPath(String rollbackPath) {
|
||||
this.rollbackPath = rollbackPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the model suffix (defaults to model.xml)
|
||||
*/
|
||||
@@ -182,20 +131,6 @@ public class DbMigrationConfig {
|
||||
this.modelSuffix = modelSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the rollback script should not be output.
|
||||
*/
|
||||
public boolean isSuppressRollback() {
|
||||
return suppressRollback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to suppress the output of the rollback script.
|
||||
*/
|
||||
public void setSuppressRollback(boolean suppressRollback) {
|
||||
this.suppressRollback = suppressRollback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply script suffix (defaults to sql).
|
||||
*/
|
||||
@@ -210,34 +145,6 @@ public class DbMigrationConfig {
|
||||
this.applySuffix = applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
|
||||
*/
|
||||
public String getDropSuffix() {
|
||||
return dropSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the drop script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
|
||||
*/
|
||||
public void setDropSuffix(String dropSuffix) {
|
||||
this.dropSuffix = dropSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
|
||||
*/
|
||||
public String getRollbackSuffix() {
|
||||
return rollbackSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rollback script suffix (defaults to ddl so that it isn't picked up by FlywayDb).
|
||||
*/
|
||||
public void setRollbackSuffix(String rollbackSuffix) {
|
||||
this.rollbackSuffix = rollbackSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the generated file comment should be included.
|
||||
*/
|
||||
@@ -252,6 +159,20 @@ public class DbMigrationConfig {
|
||||
this.includeGeneratedFileComment = includeGeneratedFileComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration version (or "next") to generate pending drops for.
|
||||
*/
|
||||
public String getGeneratePendingDrop() {
|
||||
return generatePendingDrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the migration version (or "next") to generate pending drops for.
|
||||
*/
|
||||
public void setGeneratePendingDrop(String generatePendingDrop) {
|
||||
this.generatePendingDrop = generatePendingDrop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the migration version.
|
||||
* <p>
|
||||
@@ -275,8 +196,6 @@ public class DbMigrationConfig {
|
||||
* into a single directory.
|
||||
*/
|
||||
public void singleDirectory() {
|
||||
this.dropPath = "";
|
||||
this.rollbackPath = "";
|
||||
this.modelPath = "";
|
||||
}
|
||||
|
||||
@@ -290,17 +209,13 @@ public class DbMigrationConfig {
|
||||
singleDirectory();
|
||||
} else {
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
rollbackPath = properties.get("migration.rollbackPath", rollbackPath);
|
||||
dropPath = properties.get("migration.dropPath", dropPath);
|
||||
}
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
dropSuffix = properties.get("migration.dropSuffix", dropSuffix);
|
||||
rollbackSuffix = properties.get("migration.rollbackSuffix", rollbackSuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment);
|
||||
generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop);
|
||||
|
||||
platform = properties.getEnum(DbPlatformName.class, "migration.platform", platform);
|
||||
suppressRollback = properties.getBoolean("migration.suppressRollback", suppressRollback);
|
||||
|
||||
generate = properties.getBoolean("migration.generate", generate);
|
||||
version = properties.get("migration.version", version);
|
||||
@@ -324,7 +239,6 @@ public class DbMigrationConfig {
|
||||
return generate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by EbeanServer on start.
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebean.dbmigration.model.MConfiguration;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationModel;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationVersion;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDiff;
|
||||
import com.avaje.ebean.dbmigration.model.PlatformDdlWriter;
|
||||
@@ -201,46 +202,15 @@ public class DbMigration {
|
||||
if (!online) {
|
||||
DbOffline.setRunningMigration();
|
||||
}
|
||||
|
||||
setDefaults();
|
||||
|
||||
try {
|
||||
Request request = createRequest();
|
||||
|
||||
File migrationDir = getMigrationDirectory();
|
||||
File modelDir = getModelDirectory(migrationDir);
|
||||
|
||||
MigrationModel migrationModel = new MigrationModel(modelDir, migrationConfig.getModelSuffix());
|
||||
ModelContainer migrated = migrationModel.read();
|
||||
|
||||
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
|
||||
ModelContainer current = currentModel.read();
|
||||
|
||||
ModelDiff diff = new ModelDiff(migrated);
|
||||
diff.compareTo(current);
|
||||
|
||||
if (diff.isEmpty()) {
|
||||
logger.info("no changes detected - no migration written");
|
||||
return;
|
||||
}
|
||||
|
||||
// there were actually changes to write
|
||||
Migration dbMigration = diff.getMigration();
|
||||
|
||||
String fullVersion = getFullVersion(migrationModel);
|
||||
|
||||
logger.info("generating migration:{}", fullVersion);
|
||||
if (!writeMigrationXml(dbMigration, modelDir, fullVersion)) {
|
||||
logger.warn("migration already exists, not generating DDL");
|
||||
|
||||
String pendingVersion = generatePendingDrop();
|
||||
if (pendingVersion != null) {
|
||||
generatePendingDrop(request, pendingVersion);
|
||||
} else {
|
||||
if (databasePlatform != null) {
|
||||
// writer needs the current model to provide table/column details for
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), current);
|
||||
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
|
||||
writer.processMigration(dbMigration, write, migrationDir , fullVersion);
|
||||
}
|
||||
writeExtraPlatformDdl(fullVersion, currentModel, dbMigration, migrationDir);
|
||||
generateDiff(request);
|
||||
}
|
||||
|
||||
} finally {
|
||||
@@ -250,10 +220,127 @@ public class DbMigration {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDiff(Request request) throws IOException {
|
||||
|
||||
if (request.hasPendingDrops()) {
|
||||
logger.info("Pending un-applied drops in versions {}", request.getPendingDrops());
|
||||
}
|
||||
|
||||
ModelDiff diff = request.createDiff();
|
||||
if (diff.isEmpty()) {
|
||||
logger.info("no changes detected - no migration written");
|
||||
} else {
|
||||
// there were actually changes to write
|
||||
generateMigration(request, diff.getMigration(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void generatePendingDrop(Request request, String pendingVersion) throws IOException {
|
||||
|
||||
Migration migration = request.migrationForPendingDrop(pendingVersion);
|
||||
|
||||
generateMigration(request, migration, pendingVersion);
|
||||
if (request.hasPendingDrops()) {
|
||||
logger.info("... remaining pending un-applied drops in versions {}", request.getPendingDrops());
|
||||
}
|
||||
}
|
||||
|
||||
private Request createRequest() {
|
||||
return new Request();
|
||||
}
|
||||
|
||||
private class Request {
|
||||
|
||||
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();
|
||||
this.currentModel = new CurrentModel(server, constraintNaming);
|
||||
this.current = currentModel.read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are pending un-applied drops.
|
||||
*/
|
||||
public boolean hasPendingDrops() {
|
||||
return migrated.hasPendingDrops();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration for the pending drops for a given version.
|
||||
*/
|
||||
public Migration migrationForPendingDrop(String pendingVersion) {
|
||||
|
||||
Migration migration = migrated.migrationForPendingDrop(pendingVersion);
|
||||
|
||||
// register any remaining pending drops
|
||||
migrated.registerPendingHistoryDropColumns(current);
|
||||
return migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of versions that have pending un-applied drops.
|
||||
*/
|
||||
public List<String> getPendingDrops() {
|
||||
return migrated.getPendingDrops();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an return the diff of the current model to the migration model.
|
||||
*/
|
||||
public ModelDiff createDiff() {
|
||||
ModelDiff diff = new ModelDiff(migrated);
|
||||
diff.compareTo(current);
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
|
||||
private void generateMigration(Request request, Migration dbMigration, String dropsFor) throws IOException {
|
||||
|
||||
String fullVersion = getFullVersion(request.migrationModel, dropsFor);
|
||||
|
||||
logger.info("generating migration:{}", fullVersion);
|
||||
if (!writeMigrationXml(dbMigration, request.modelDir, fullVersion)) {
|
||||
logger.warn("migration already exists, not generating DDL");
|
||||
|
||||
} else {
|
||||
if (databasePlatform != null) {
|
||||
// writer needs the current model to provide table/column details for
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), request.current);
|
||||
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
|
||||
writer.processMigration(dbMigration, write, request.migrationDir , fullVersion);
|
||||
}
|
||||
writeExtraPlatformDdl(fullVersion, request.currentModel, dbMigration, request.migrationDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the next pending drop changeSet should be generated as the next migration.
|
||||
*/
|
||||
private String generatePendingDrop() {
|
||||
|
||||
String nextDrop = System.getProperty("ddl.migration.pendingDrop");
|
||||
if (nextDrop != null) {
|
||||
return nextDrop;
|
||||
}
|
||||
return migrationConfig.getGeneratePendingDrop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full version for the migration being generated.
|
||||
*
|
||||
* The full version can contain a comment suffix after a "__" double underscore.
|
||||
*/
|
||||
private String getFullVersion(MigrationModel migrationModel) {
|
||||
private String getFullVersion(MigrationModel migrationModel, String dropsFor) {
|
||||
|
||||
String version = migrationConfig.getVersion();
|
||||
if (version == null) {
|
||||
@@ -261,10 +348,14 @@ public class DbMigration {
|
||||
}
|
||||
|
||||
String fullVersion = version;
|
||||
if (migrationConfig.getName() != null) {
|
||||
fullVersion += "__" + toUnderScore(migrationConfig.getName());
|
||||
|
||||
String name = migrationConfig.getName();
|
||||
if (name != null) {
|
||||
fullVersion += "__" + toUnderScore(name);
|
||||
} else if (dropsFor != null) {
|
||||
fullVersion += "__" + toUnderScore("dropsFor_" + MigrationVersion.trim(dropsFor));
|
||||
|
||||
} else if (version.equals(initialVersion)) {
|
||||
fullVersion += "__initial";
|
||||
}
|
||||
return fullVersion;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
@@ -30,8 +29,8 @@ public class DdlGenerator {
|
||||
private final boolean createOnly;
|
||||
|
||||
private CurrentModel currentModel;
|
||||
private String dropContent;
|
||||
private String createContent;
|
||||
private String dropAllContent;
|
||||
private String createAllContent;
|
||||
|
||||
public DdlGenerator(SpiEbeanServer server, ServerConfig serverConfig) {
|
||||
this.server = server;
|
||||
@@ -84,18 +83,18 @@ public class DdlGenerator {
|
||||
|
||||
protected void runDropSql() throws IOException {
|
||||
if (!createOnly) {
|
||||
if (dropContent == null) {
|
||||
dropContent = readFile(getDropFileName());
|
||||
if (dropAllContent == null) {
|
||||
dropAllContent = readFile(getDropFileName());
|
||||
}
|
||||
runScript(true, dropContent, getDropFileName());
|
||||
runScript(true, dropAllContent, getDropFileName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void runCreateSql() throws IOException {
|
||||
if (createContent == null) {
|
||||
createContent = readFile(getCreateFileName());
|
||||
if (createAllContent == null) {
|
||||
createAllContent = readFile(getCreateFileName());
|
||||
}
|
||||
runScript(false, createContent, getCreateFileName());
|
||||
runScript(false, createAllContent, getCreateFileName());
|
||||
}
|
||||
|
||||
protected void runInitSql() throws IOException {
|
||||
@@ -132,8 +131,7 @@ public class DdlGenerator {
|
||||
protected void writeDrop(String dropFile) {
|
||||
|
||||
try {
|
||||
String c = generateDropDdl();
|
||||
writeFile(dropFile, c);
|
||||
writeFile(dropFile, generateDropAllDdl());
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Error generating Drop DDL", e);
|
||||
}
|
||||
@@ -142,28 +140,27 @@ public class DdlGenerator {
|
||||
protected void writeCreate(String createFile) {
|
||||
|
||||
try {
|
||||
String c = generateCreateDdl();
|
||||
writeFile(createFile, c);
|
||||
writeFile(createFile, generateCreateAllDdl());
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException("Error generating Create DDL", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String generateDropDdl() {
|
||||
protected String generateDropAllDdl() {
|
||||
|
||||
try {
|
||||
dropContent = currentModel().getDropDdl();
|
||||
return dropContent;
|
||||
dropAllContent = currentModel().getDropAllDdl();
|
||||
return dropAllContent;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String generateCreateDdl() {
|
||||
protected String generateCreateAllDdl() {
|
||||
|
||||
try {
|
||||
createContent = currentModel().getCreateDdl();
|
||||
return createContent;
|
||||
createAllContent = currentModel().getCreateDdl();
|
||||
return createAllContent;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -10,12 +10,6 @@ import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
*/
|
||||
public class DdlWrite {
|
||||
|
||||
public enum Mode {
|
||||
APPLY,
|
||||
ROLLBACK,
|
||||
DROP
|
||||
}
|
||||
|
||||
private final ModelContainer currentModel;
|
||||
|
||||
private final DdlBuffer applyDropDependencies;
|
||||
@@ -26,33 +20,9 @@ public class DdlWrite {
|
||||
|
||||
private final DdlBuffer applyHistory;
|
||||
|
||||
private final DdlBuffer rollbackDropDependencies;
|
||||
private final DdlBuffer dropAllForeignKeys;
|
||||
|
||||
private final DdlBuffer rollbackForeignKeys;
|
||||
|
||||
private final DdlBuffer rollback;
|
||||
|
||||
/**
|
||||
* For DDL that drops tables and columns etc.
|
||||
*
|
||||
* This DDL typically can not run automatically in production as there is most commonly
|
||||
* existing servers running the application using these tables and columns. Typically
|
||||
* these drop statements may be executed AFTER all the servers in the application have
|
||||
* migrated onto new code.
|
||||
*/
|
||||
private final DdlBuffer drop;
|
||||
|
||||
/**
|
||||
* For use when History is turned off for a base table or history is no longer
|
||||
* desired on specific columns. This DDL should typically execute manually after review
|
||||
* by DBA's.
|
||||
*/
|
||||
private final DdlBuffer dropHistory;
|
||||
|
||||
/**
|
||||
* Buffer used to drop dependencies early in the 'drop script'.
|
||||
*/
|
||||
private final DdlBuffer dropDropDependencies;
|
||||
private final DdlBuffer dropAll;
|
||||
|
||||
/**
|
||||
* Create without any configuration or current model (no history support).
|
||||
@@ -70,12 +40,8 @@ public class DdlWrite {
|
||||
this.apply = new BaseDdlBuffer(configuration);
|
||||
this.applyForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.applyHistory = new BaseDdlBuffer(configuration);
|
||||
this.rollbackDropDependencies = new BaseDdlBuffer(configuration);
|
||||
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.rollback = new BaseDdlBuffer(configuration);
|
||||
this.drop = new BaseDdlBuffer(configuration);
|
||||
this.dropHistory = new BaseDdlBuffer(configuration);
|
||||
this.dropDropDependencies = new BaseDdlBuffer(configuration);
|
||||
this.dropAllForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.dropAll = new BaseDdlBuffer(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,63 +65,6 @@ public class DdlWrite {
|
||||
&& applyDropDependencies.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the apply rollback buffers are all empty.
|
||||
*/
|
||||
public boolean isApplyRollbackEmpty() {
|
||||
return rollback.getBuffer().isEmpty()
|
||||
&& rollbackForeignKeys.getBuffer().isEmpty()
|
||||
&& rollbackDropDependencies.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply or rollback buffer.
|
||||
*/
|
||||
public DdlBuffer buffer(Mode mode) {
|
||||
switch (mode) {
|
||||
case APPLY: return apply();
|
||||
case ROLLBACK: return rollback();
|
||||
case DROP: return drop();
|
||||
default:
|
||||
throw new IllegalStateException("Invalid mode" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply or rollback buffer.
|
||||
*/
|
||||
public DdlBuffer historyBuffer(Mode mode) {
|
||||
switch (mode) {
|
||||
case APPLY: return applyHistory();
|
||||
case ROLLBACK: return rollback();
|
||||
case DROP: return dropHistory();
|
||||
default:
|
||||
throw new IllegalStateException("Invalid mode" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply or rollback drop dependencies buffer.
|
||||
*/
|
||||
public DdlBuffer dropDependencies(Mode mode) {
|
||||
|
||||
switch (mode) {
|
||||
case APPLY: return applyDropDependencies();
|
||||
case ROLLBACK: return rollbackDropDependencies();
|
||||
case DROP: return dropDropDependencies();
|
||||
default:
|
||||
throw new IllegalStateException("Invalid mode" + mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true the drop buffers are empty.
|
||||
*/
|
||||
public boolean isDropEmpty() {
|
||||
return drop.getBuffer().isEmpty() && dropHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to.
|
||||
*/
|
||||
@@ -188,54 +97,17 @@ public class DdlWrite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that rollback executes early to drop dependencies like views.
|
||||
* Return the buffer used for the 'drop all DDL' for dropping foreign keys and associated indexes.
|
||||
*/
|
||||
public DdlBuffer rollbackDropDependencies() {
|
||||
return rollbackDropDependencies;
|
||||
public DdlBuffer dropAllForeignKeys() {
|
||||
return dropAllForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that ROLLBACK DDL is written to for foreign keys and associated indexes.
|
||||
* Return the buffer used for the 'drop all DDL' to drop tables, views and history triggers etc.
|
||||
*/
|
||||
public DdlBuffer rollbackForeignKeys() {
|
||||
return rollbackForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that ROLLBACK DDL is written to which is considered safe to run when
|
||||
* apply changes fail to execute. This will reverse the apply changes typically dropping
|
||||
* newly created tables, foreign keys etc.
|
||||
* <p>
|
||||
* When apply changes are made against DB's that support transactional DDL you could argue
|
||||
* that these rollback statements are not necessary.
|
||||
* <p>
|
||||
* Note that statements added to this rollback buffer are executed after foreign key rollback
|
||||
* has been executed.
|
||||
*/
|
||||
public DdlBuffer rollback() {
|
||||
return rollback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that destructive changes are written to. This is typically drop table and
|
||||
* drop column.
|
||||
*/
|
||||
public DdlBuffer drop() {
|
||||
return drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that is used when history is no longer required on a table or specific columns.
|
||||
*/
|
||||
public DdlBuffer dropHistory() {
|
||||
return dropHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that executes early for 'drop' script.
|
||||
*/
|
||||
public DdlBuffer dropDropDependencies() {
|
||||
return dropDropDependencies;
|
||||
public DdlBuffer dropAll() {
|
||||
return dropAll;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-42
@@ -140,7 +140,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
// add drop table to the rollback buffer - do this before
|
||||
// we drop the related sequence (if sequences are used)
|
||||
dropTable(writer.rollback(), tableName);
|
||||
dropTable(writer.dropAll(), tableName);
|
||||
|
||||
if (useSequence) {
|
||||
String pkCol = pk.get(0).getName();
|
||||
@@ -149,7 +149,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
// add blank line for a bit of whitespace between tables
|
||||
apply.end();
|
||||
writer.rollback().end();
|
||||
writer.dropAll().end();
|
||||
|
||||
writeAddForeignKeys(writer, createTable);
|
||||
|
||||
@@ -204,7 +204,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
.append(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames))
|
||||
.endOfStatement();
|
||||
|
||||
write.rollbackForeignKeys()
|
||||
write.dropAllForeignKeys()
|
||||
.append(platformDdl.dropIndex(uqName, tableName))
|
||||
.endOfStatement();
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
String createSeq = platformDdl.createSequence(seqName, initial, allocate);
|
||||
if (createSeq != null) {
|
||||
writer.apply().append(createSeq).newLine();
|
||||
writer.rollback().append(platformDdl.dropSequence(seqName)).endOfStatement();
|
||||
writer.dropAll().append(platformDdl.dropSequence(seqName)).endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,15 +295,15 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
fkeyBuffer.end();
|
||||
|
||||
write.rollbackForeignKeys()
|
||||
write.dropAllForeignKeys()
|
||||
.append(platformDdl.alterTableDropForeignKey(tableName, fkName)).endOfStatement();
|
||||
|
||||
if (indexName != null) {
|
||||
write.rollbackForeignKeys()
|
||||
write.dropAllForeignKeys()
|
||||
.append(platformDdl.dropIndex(indexName, tableName)).endOfStatement();
|
||||
}
|
||||
|
||||
write.rollbackForeignKeys().end();
|
||||
write.dropAllForeignKeys().end();
|
||||
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
.append(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), cols))
|
||||
.endOfStatement();
|
||||
|
||||
writer.rollback()
|
||||
writer.dropAll()
|
||||
.append(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()))
|
||||
.endOfStatement();
|
||||
}
|
||||
@@ -520,7 +520,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
List<Column> columns = addColumn.getColumn();
|
||||
for (Column column : columns) {
|
||||
alterTableAddColumn(writer.apply(), tableName, column, false);
|
||||
alterTableDropColumn(writer.rollback(), tableName, column.getName());
|
||||
}
|
||||
|
||||
if (isTrue(addColumn.isWithHistory())) {
|
||||
@@ -529,13 +528,11 @@ public class BaseTableDdl implements TableDdl {
|
||||
for (Column column : columns) {
|
||||
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.ADD, column.getName());
|
||||
alterTableAddColumn(writer.apply(), historyTable, column, true);
|
||||
alterTableDropColumn(writer.rollback(), historyTable, column.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// add a bit of whitespace
|
||||
writer.apply().end();
|
||||
writer.rollback().end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,7 +541,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
|
||||
|
||||
dropTable(writer.drop(), dropTable.getName());
|
||||
dropTable(writer.apply(), dropTable.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,14 +552,14 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
String tableName = dropColumn.getTableName();
|
||||
|
||||
alterTableDropColumn(writer.drop(), tableName, dropColumn.getColumnName());
|
||||
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
|
||||
if (isTrue(dropColumn.isWithHistory())) {
|
||||
// also drop from the history table
|
||||
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.DROP, dropColumn.getColumnName());
|
||||
alterTableDropColumn(writer.drop(), historyTable(tableName), dropColumn.getColumnName());
|
||||
alterTableDropColumn(writer.apply(), historyTable(tableName), dropColumn.getColumnName());
|
||||
}
|
||||
|
||||
writer.drop().end();
|
||||
writer.apply().end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -642,21 +639,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
if (hasValue(ddl)) {
|
||||
writer.apply().append(ddl).endOfStatement();
|
||||
|
||||
// reverse and generate the rollback statement
|
||||
String currentType = alter.getCurrentType();
|
||||
String type = alter.getType();
|
||||
Boolean currentNotnull = alter.isCurrentNotnull();
|
||||
Boolean notnull = alter.isNotnull();
|
||||
|
||||
alter.setCurrentType(type);
|
||||
alter.setType(currentType);
|
||||
alter.setNotnull(currentNotnull);
|
||||
alter.setCurrentNotnull(notnull);
|
||||
|
||||
// write the rollback
|
||||
ddl = platformDdl.alterColumnBaseAttributes(alter);
|
||||
writer.rollback().append(ddl).endOfStatement();
|
||||
|
||||
if (isTrue(alter.isWithHistory()) && alter.getType() != null) {
|
||||
// mysql and sql server column type change allowing nulls in the history table column
|
||||
AlterColumn alterHistoryColumn = new AlterColumn();
|
||||
@@ -667,11 +649,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
// write the apply to history table
|
||||
writer.apply().append(histColumnDdl).endOfStatement();
|
||||
|
||||
// write the rollback from history table
|
||||
alterHistoryColumn.setType(currentType);
|
||||
histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
|
||||
writer.rollback().append(histColumnDdl).endOfStatement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -689,8 +666,6 @@ public class BaseTableDdl implements TableDdl {
|
||||
String ddl = platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull());
|
||||
if (hasValue(ddl)) {
|
||||
writer.apply().append(ddl).endOfStatement();
|
||||
ddl = platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isCurrentNotnull());
|
||||
writer.rollback().append(ddl).endOfStatement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,14 +674,10 @@ public class BaseTableDdl implements TableDdl {
|
||||
String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
|
||||
if (hasValue(ddl)) {
|
||||
writer.apply().append(ddl).endOfStatement();
|
||||
ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getCurrentType());
|
||||
writer.rollback().append(ddl).endOfStatement();
|
||||
if (isTrue(alter.isWithHistory())) {
|
||||
// apply same type change to matching column in the history table
|
||||
ddl = platformDdl.alterColumnType(historyTable(alter.getTableName()), alter.getColumnName(), alter.getType());
|
||||
writer.apply().append(ddl).endOfStatement();
|
||||
ddl = platformDdl.alterColumnType(historyTable(alter.getTableName()), alter.getColumnName(), alter.getCurrentType());
|
||||
writer.rollback().append(ddl).endOfStatement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -762,7 +733,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
.append(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols))
|
||||
.endOfStatement();
|
||||
|
||||
writer.rollbackForeignKeys()
|
||||
writer.dropAllForeignKeys()
|
||||
.append(platformDdl.dropIndex(uqName, alter.getTableName()))
|
||||
.endOfStatement();
|
||||
}
|
||||
|
||||
+10
-47
@@ -69,45 +69,17 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
*/
|
||||
protected void updateTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
|
||||
|
||||
DbTriggerUpdate triggerUpdate = createDbTriggerUpdate(writer, table);
|
||||
writer.applyHistory().append("-- changes: ").append(update.description()).newLine();
|
||||
|
||||
if (update.hasApplyChanges()) {
|
||||
// includes add, include and exclude column changes
|
||||
|
||||
String applyChangeDescription = update.descriptionForApply();
|
||||
List<String> includedColumns = columnNamesForApply(table);
|
||||
|
||||
DdlBuffer apply = writer.applyHistory();
|
||||
apply.append("-- changes: ").append(applyChangeDescription).newLine();
|
||||
|
||||
triggerUpdate.prepare(DdlWrite.Mode.APPLY, includedColumns);
|
||||
updateHistoryTriggers(triggerUpdate);
|
||||
|
||||
// put a reverted version into the rollback buffer
|
||||
update.toRevertedColumns(includedColumns);
|
||||
|
||||
DdlBuffer rollback = writer.rollback();
|
||||
rollback.append("-- revert changes: ").append(applyChangeDescription).newLine();
|
||||
|
||||
triggerUpdate.prepare(DdlWrite.Mode.ROLLBACK, includedColumns);
|
||||
updateHistoryTriggers(triggerUpdate);//writer, DdlWrite.Mode.ROLLBACK, baseTableName, historyTableName, includedColumns);
|
||||
}
|
||||
|
||||
if (update.hasDropChanges()) {
|
||||
// effectively applies the dropped columns changes to history triggers
|
||||
|
||||
DdlBuffer drop = writer.dropHistory();
|
||||
drop.append("-- changes: ").append(update.descriptionForDrop()).newLine();
|
||||
|
||||
triggerUpdate.prepare(DdlWrite.Mode.DROP, columnNamesForDrop(table));
|
||||
updateHistoryTriggers(triggerUpdate);//writer, DdlWrite.Mode.DROP, baseTableName, historyTableName, columnNamesForDrop(table));
|
||||
}
|
||||
updateHistoryTriggers(createDbTriggerUpdate(writer, table));
|
||||
}
|
||||
|
||||
protected DbTriggerUpdate createDbTriggerUpdate(DdlWrite writer, MTable table) {
|
||||
|
||||
List<String> columns = columnNamesForApply(table);
|
||||
String baseTableName = table.getName();
|
||||
String historyTableName = historyTableName(baseTableName);
|
||||
return new DbTriggerUpdate(baseTableName, historyTableName, writer);
|
||||
return new DbTriggerUpdate(baseTableName, historyTableName, writer, columns);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,11 +88,10 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
String baseTable = dropHistoryTable.getBaseTable();
|
||||
|
||||
// drop in appropriate order
|
||||
dropTriggers(writer.dropHistory(), baseTable);
|
||||
dropHistoryTableEtc(writer.dropHistory(), baseTable);
|
||||
dropTriggers(writer.applyDropDependencies(), baseTable);
|
||||
dropHistoryTableEtc(writer.applyDropDependencies(), baseTable);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
|
||||
|
||||
@@ -139,9 +110,8 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
String baseTable = table.getName();
|
||||
String whenCreatedColumn = table.getWhenCreatedColumn();
|
||||
|
||||
// rollback changes in appropriate order
|
||||
dropTriggers(writer.rollback(), baseTable);
|
||||
dropHistoryTableEtc(writer.rollback(), baseTable);
|
||||
dropTriggers(writer.dropAll(), baseTable);
|
||||
dropHistoryTableEtc(writer.dropAll(), baseTable);
|
||||
|
||||
addHistoryTable(writer, table, whenCreatedColumn);
|
||||
createStoredFunction(writer, table);
|
||||
@@ -310,16 +280,9 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
|
||||
* the column.
|
||||
* </p>
|
||||
*/
|
||||
protected List<String> columnNamesForApply(MTable table) throws IOException {
|
||||
protected List<String> columnNamesForApply(MTable table) {
|
||||
|
||||
return table.allHistoryColumns(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column names included in history for the drop script.
|
||||
*/
|
||||
protected List<String> columnNamesForDrop(MTable table) throws IOException {
|
||||
|
||||
return table.allHistoryColumns(false);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-15
@@ -16,36 +16,27 @@ public class DbTriggerUpdate {
|
||||
|
||||
private final DdlWrite writer;
|
||||
|
||||
private DdlWrite.Mode mode;
|
||||
private final List<String> columns;
|
||||
|
||||
private List<String> includedColumns;
|
||||
|
||||
public DbTriggerUpdate(String baseTableName, String historyTableName, DdlWrite writer) {
|
||||
public DbTriggerUpdate(String baseTableName, String historyTableName, DdlWrite writer, List<String> columns) {
|
||||
this.baseTableName = baseTableName;
|
||||
this.historyTableName = historyTableName;
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for use given the mode and columns included in history.
|
||||
*/
|
||||
public void prepare(DdlWrite.Mode mode, List<String> includedColumns) {
|
||||
this.mode = mode;
|
||||
this.includedColumns = includedColumns;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate buffer for the current mode.
|
||||
*/
|
||||
public DdlBuffer historyBuffer() {
|
||||
return writer.historyBuffer(mode);
|
||||
return writer.applyHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the appropriate drop dependency buffer for the current mode.
|
||||
*/
|
||||
public DdlBuffer dropDependencyBuffer() {
|
||||
return writer.dropDependencies(mode);
|
||||
return writer.applyDropDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +57,7 @@ public class DbTriggerUpdate {
|
||||
* Return the included columns.
|
||||
*/
|
||||
public List<String> getColumns() {
|
||||
return includedColumns;
|
||||
return columns;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-84
@@ -10,7 +10,6 @@ import java.util.List;
|
||||
*/
|
||||
public class HistoryTableUpdate {
|
||||
|
||||
|
||||
/**
|
||||
* Column change type.
|
||||
*/
|
||||
@@ -32,31 +31,14 @@ public class HistoryTableUpdate {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return description();
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return change.name().toLowerCase()+" "+column;
|
||||
}
|
||||
|
||||
private boolean isChangeFor(boolean apply) {
|
||||
return apply ? change != Change.DROP : change == Change.DROP;
|
||||
}
|
||||
|
||||
private void revert(List<String> includedColumns) {
|
||||
switch (change) {
|
||||
case ADD:
|
||||
case INCLUDE: {
|
||||
includedColumns.remove(column);
|
||||
break;
|
||||
}
|
||||
case EXCLUDE: {
|
||||
includedColumns.add(column);
|
||||
break;
|
||||
}
|
||||
case DROP:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected change "+change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final String baseTable;
|
||||
@@ -70,71 +52,12 @@ public class HistoryTableUpdate {
|
||||
this.baseTable = baseTable;
|
||||
}
|
||||
|
||||
private boolean isChangeFor(boolean apply) {
|
||||
for (Column columnChange : columnChanges) {
|
||||
if (columnChange.isChangeFor(apply)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the change includes apply changes (ADD, INCLUDE, EXCLUDE).
|
||||
*/
|
||||
public boolean hasApplyChanges() {
|
||||
return isChangeFor(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the change includes DROP column.
|
||||
*/
|
||||
public boolean hasDropChanges() {
|
||||
return isChangeFor(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of the changes that cause the history trigger/function
|
||||
* to be regenerated (added, included or excluded columns).
|
||||
* to be regenerated (added, included, excluded and dropped columns).
|
||||
*/
|
||||
public String descriptionForApply() {
|
||||
return descriptionFor(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of the changes that cause the history trigger/function
|
||||
* to be regenerated in the drop script (dropped columns only).
|
||||
*/
|
||||
public String descriptionForDrop() {
|
||||
return descriptionFor(false);
|
||||
}
|
||||
|
||||
private String descriptionFor(boolean apply) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(90);
|
||||
boolean first = true;
|
||||
for (Column column : columnChanges) {
|
||||
if (column.isChangeFor(apply)) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(column.description());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the apply changes which equates to removing any newly added or
|
||||
* included columns.
|
||||
*/
|
||||
public void toRevertedColumns(List<String> includedColumns) {
|
||||
|
||||
for (Column columnChange : columnChanges) {
|
||||
columnChange.revert(includedColumns);
|
||||
}
|
||||
public String description() {
|
||||
return columnChanges.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,8 +27,6 @@ public class MySqlHistoryDdl extends DbTriggerBasedHistoryDdl {
|
||||
|
||||
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
|
||||
|
||||
update.prepare(DdlWrite.Mode.APPLY, columnNamesForApply(table));
|
||||
|
||||
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
|
||||
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* </choice>
|
||||
* </sequence>
|
||||
* <attribute name="type" use="required" type="{http://ebean-orm.github.io/xml/ns/dbmigration}changeSetType" />
|
||||
* <attribute name="dropsFor" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="generated" type="{http://www.w3.org/2001/XMLSchema}boolean" />
|
||||
* <attribute name="author" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* <attribute name="comment" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
@@ -62,6 +63,8 @@ public class ChangeSet {
|
||||
protected List<Object> changeSetChildren;
|
||||
@XmlAttribute(name = "type", required = true)
|
||||
protected ChangeSetType type;
|
||||
@XmlAttribute(name = "dropsFor")
|
||||
protected String dropsFor;
|
||||
@XmlAttribute(name = "generated")
|
||||
protected Boolean generated;
|
||||
@XmlAttribute(name = "author")
|
||||
@@ -134,6 +137,30 @@ public class ChangeSet {
|
||||
this.type = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the dropsFor property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getDropsFor() {
|
||||
return dropsFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the dropsFor property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setDropsFor(String value) {
|
||||
this.dropsFor = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the generated property.
|
||||
*
|
||||
|
||||
@@ -15,7 +15,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <simpleType name="changeSetType">
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}string">
|
||||
* <enumeration value="apply"/>
|
||||
* <enumeration value="drop"/>
|
||||
* <enumeration value="pendingDrops"/>
|
||||
* <enumeration value="baseline"/>
|
||||
* </restriction>
|
||||
* </simpleType>
|
||||
@@ -28,8 +28,8 @@ public enum ChangeSetType {
|
||||
|
||||
@XmlEnumValue("apply")
|
||||
APPLY("apply"),
|
||||
@XmlEnumValue("drop")
|
||||
DROP("drop"),
|
||||
@XmlEnumValue("pendingDrops")
|
||||
PENDING_DROPS("pendingDrops"),
|
||||
@XmlEnumValue("baseline")
|
||||
BASELINE("baseline");
|
||||
private final String value;
|
||||
|
||||
@@ -117,13 +117,13 @@ public class CurrentModel {
|
||||
/**
|
||||
* Return the 'Drop' DDL.
|
||||
*/
|
||||
public String getDropDdl() throws IOException {
|
||||
public String getDropAllDdl() throws IOException {
|
||||
|
||||
createDdl();
|
||||
|
||||
StringBuilder ddl = new StringBuilder(2000);
|
||||
ddl.append(write.rollbackForeignKeys().getBuffer());
|
||||
ddl.append(write.rollback().getBuffer());
|
||||
ddl.append(write.dropAllForeignKeys().getBuffer());
|
||||
ddl.append(write.dropAll().getBuffer());
|
||||
|
||||
return ddl.toString();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.slf4j.LoggerFactory;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -122,7 +121,7 @@ public class MTable {
|
||||
*/
|
||||
private AddColumn addColumn;
|
||||
|
||||
private List<DroppedColumn> droppedColumns = new ArrayList<DroppedColumn>();
|
||||
private List<String> droppedColumns = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Create a copy of this table structure as a 'draft' table.
|
||||
@@ -132,14 +131,14 @@ public class MTable {
|
||||
*/
|
||||
public MTable createDraftTable() {
|
||||
|
||||
draftTable = new MTable(name+"_draft");
|
||||
draftTable = new MTable(name + "_draft");
|
||||
draftTable.draft = true;
|
||||
draftTable.whenCreatedColumn = whenCreatedColumn;
|
||||
// compoundKeys
|
||||
// compoundUniqueConstraints
|
||||
draftTable.identityType = identityType;
|
||||
|
||||
for (MColumn col: allColumns()) {
|
||||
for (MColumn col : allColumns()) {
|
||||
draftTable.addColumn(col.copyForDraft());
|
||||
}
|
||||
|
||||
@@ -370,13 +369,8 @@ public class MTable {
|
||||
}
|
||||
}
|
||||
if (includeDropped && !droppedColumns.isEmpty()) {
|
||||
Collections.sort(droppedColumns);
|
||||
for (DroppedColumn droppedColumn : droppedColumns) {
|
||||
if (droppedColumn.columnPosition >= columnNames.size()) {
|
||||
columnNames.add(droppedColumn.name);
|
||||
} else {
|
||||
columnNames.add(droppedColumn.columnPosition, droppedColumn.name);
|
||||
}
|
||||
for (String droppedColumn : droppedColumns) {
|
||||
columnNames.add(droppedColumn);
|
||||
}
|
||||
}
|
||||
return columnNames;
|
||||
@@ -546,35 +540,19 @@ public class MTable {
|
||||
// These dropColumns should occur on the history
|
||||
// table as well as the base table
|
||||
dropColumn.setWithHistory(Boolean.TRUE);
|
||||
newTable.registerDroppedColumn(existingColumn.getName(), columnPosition);
|
||||
}
|
||||
|
||||
modelDiff.addDropColumn(dropColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a dropped column with it's previous column position.
|
||||
* We need this for history triggers and views as we don't actually drop the
|
||||
* column until the 'drop script' is run so the 'apply script' for history changes
|
||||
* still needs to include the columns that are going to be dropped.
|
||||
* Register a pending un-applied drop column.
|
||||
* <p>
|
||||
* This means this column still needs to be included in history views/triggers etc even
|
||||
* though it is not part of the current model.
|
||||
*/
|
||||
protected void registerDroppedColumn(String name, int columnPosition) {
|
||||
droppedColumns.add(new DroppedColumn(name, columnPosition));
|
||||
}
|
||||
|
||||
private static class DroppedColumn implements Comparable<DroppedColumn> {
|
||||
final String name;
|
||||
final int columnPosition;
|
||||
|
||||
DroppedColumn(String name, int columnPosition) {
|
||||
this.name = name;
|
||||
this.columnPosition = columnPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DroppedColumn o) {
|
||||
return Integer.compare(o.columnPosition, columnPosition);
|
||||
}
|
||||
public void registerPendingDropColumn(String columnName) {
|
||||
droppedColumns.add(columnName);
|
||||
}
|
||||
|
||||
private int toInt(BigInteger value) {
|
||||
@@ -588,7 +566,7 @@ public class MTable {
|
||||
/**
|
||||
* Check if there are duplicate foreign keys.
|
||||
* <p>
|
||||
* This can occur when an ManyToMany relates back to itself.
|
||||
* This can occur when an ManyToMany relates back to itself.
|
||||
* </p>
|
||||
*/
|
||||
public void checkDuplicateForeignKeys() {
|
||||
@@ -639,7 +617,7 @@ public class MTable {
|
||||
*/
|
||||
private String extractBaseTable(String references) {
|
||||
int lastDot = references.lastIndexOf('.');
|
||||
return references.substring(0,lastDot);
|
||||
return references.substring(0, lastDot);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -648,7 +626,7 @@ public class MTable {
|
||||
*/
|
||||
private String deriveReferences(String references, String draftTableName) {
|
||||
int lastDot = references.lastIndexOf('.');
|
||||
return draftTableName+"."+references.substring(lastDot+1);
|
||||
return draftTableName + "." + references.substring(lastDot + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class MigrationModel {
|
||||
List<MigrationResource> resources = new ArrayList<MigrationResource>();
|
||||
|
||||
for (File xmlFile: xmlFiles) {
|
||||
resources.add(new MigrationResource(xmlFile));
|
||||
resources.add(new MigrationResource(xmlFile, createVersion(xmlFile)));
|
||||
}
|
||||
|
||||
// sort into version order before applying
|
||||
@@ -60,7 +60,7 @@ public class MigrationModel {
|
||||
|
||||
for (MigrationResource migrationResource: resources) {
|
||||
logger.debug("read {}", migrationResource);
|
||||
model.apply(migrationResource.read());
|
||||
model.apply(migrationResource.read(), migrationResource.getVersion());
|
||||
}
|
||||
|
||||
// remember the last version
|
||||
@@ -69,6 +69,12 @@ public class MigrationModel {
|
||||
}
|
||||
}
|
||||
|
||||
private MigrationVersion createVersion(File xmlFile) {
|
||||
String fileName = xmlFile.getName();
|
||||
String versionName = fileName.substring(0, fileName.length() - modelSuffix.length());
|
||||
return MigrationVersion.parse(versionName);
|
||||
}
|
||||
|
||||
public String getNextVersion(String initialVersion) {
|
||||
|
||||
return lastVersion == null ? initialVersion : lastVersion.nextVersion();
|
||||
|
||||
@@ -17,9 +17,9 @@ public class MigrationResource implements Comparable<MigrationResource> {
|
||||
/**
|
||||
* Construct with a migration xml file.
|
||||
*/
|
||||
public MigrationResource(File migrationFile) {
|
||||
public MigrationResource(File migrationFile, MigrationVersion version) {
|
||||
this.migrationFile = migrationFile;
|
||||
this.version = MigrationVersion.parse(migrationFile.getName());
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The version of a migration used so that migrations are processed in order.
|
||||
*/
|
||||
@@ -15,23 +17,74 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
*/
|
||||
private final int[] ordering;
|
||||
|
||||
private MigrationVersion(String raw, int[] ordering) {
|
||||
private final boolean[] underscores;
|
||||
|
||||
private final String comment;
|
||||
|
||||
private MigrationVersion(String raw, int[] ordering, boolean[] underscores, String comment) {
|
||||
this.raw = raw;
|
||||
this.ordering = ordering;
|
||||
this.underscores = underscores;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version comment.
|
||||
*/
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version in raw form.
|
||||
*/
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the trimmed version excluding version comment and un-parsable string.
|
||||
*/
|
||||
public String asString() {
|
||||
return formattedVersion(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the trimmed version with any underscores replaced with '.'
|
||||
*/
|
||||
public String normalised() {
|
||||
return formattedVersion(true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next version based on this version.
|
||||
*/
|
||||
public String nextVersion() {
|
||||
return formattedVersion(false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version part of the string.
|
||||
*
|
||||
* Normalised means always use '.' delimiters (no underscores).
|
||||
* NextVersion means bump/increase the last version number by 1.
|
||||
*/
|
||||
private String formattedVersion(boolean normalised, boolean nextVersion) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ordering.length; i++) {
|
||||
if (i < ordering.length -1 ) {
|
||||
sb.append(ordering[i]).append(".");
|
||||
if (i < ordering.length - 1) {
|
||||
sb.append(ordering[i]);
|
||||
if (normalised) {
|
||||
sb.append('.');
|
||||
} else {
|
||||
sb.append(underscores[i] ? '_' : '.');
|
||||
}
|
||||
} else {
|
||||
sb.append(ordering[i]+1);
|
||||
sb.append((nextVersion) ? ordering[i] + 1 : ordering[i]);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
@@ -54,33 +107,54 @@ public class MigrationVersion implements Comparable<MigrationVersion> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw version string and just return the leading version number;
|
||||
*/
|
||||
public static String trim(String raw) {
|
||||
return parse(raw).asString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw version string into a MigrationVersion.
|
||||
*/
|
||||
public static MigrationVersion parse(String raw) {
|
||||
|
||||
String value = raw.replace("__",".");
|
||||
value = value.replace('_','.');
|
||||
String comment = "";
|
||||
String value = raw;
|
||||
int commentStart = raw.indexOf("__");
|
||||
if (commentStart > -1) {
|
||||
// trim off the trailing comment
|
||||
comment = raw.substring(commentStart + 2);
|
||||
value = value.substring(0, commentStart);
|
||||
}
|
||||
|
||||
value = value.replace('_', '.');
|
||||
|
||||
String[] sections = value.split("\\.");
|
||||
|
||||
boolean[] underscores = new boolean[sections.length];
|
||||
int[] ordering = new int[sections.length];
|
||||
|
||||
int delimiterPos = 0;
|
||||
int stopIndex = 0;
|
||||
for (int i = 0; i < sections.length; i++) {
|
||||
try {
|
||||
ordering[i] = Integer.parseInt(sections[i]);
|
||||
stopIndex++;
|
||||
|
||||
delimiterPos += sections[i].length();
|
||||
underscores[i] = (delimiterPos < raw.length() - 1 && raw.charAt(delimiterPos) == '_');
|
||||
delimiterPos++;
|
||||
} catch (NumberFormatException e) {
|
||||
// stop parsing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int[] actualOrder = new int[stopIndex];
|
||||
System.arraycopy(ordering, 0, actualOrder, 0, stopIndex);
|
||||
int[] actualOrder = Arrays.copyOf(ordering, stopIndex);
|
||||
boolean[] actualUnderscores = Arrays.copyOf(underscores, stopIndex);
|
||||
|
||||
return new MigrationVersion(raw, actualOrder);
|
||||
return new MigrationVersion(raw, actualOrder, actualUnderscores, comment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
@@ -28,15 +29,16 @@ public class ModelContainer {
|
||||
/**
|
||||
* All the tables in the model.
|
||||
*/
|
||||
private Map<String, MTable> tables = new LinkedHashMap<String, MTable>();
|
||||
private final Map<String, MTable> tables = new LinkedHashMap<String, MTable>();
|
||||
|
||||
/**
|
||||
* All the non unique non foreign key indexes.
|
||||
*/
|
||||
private Map<String, MIndex> indexes = new LinkedHashMap<String, MIndex>();
|
||||
private final Map<String, MIndex> indexes = new LinkedHashMap<String, MIndex>();
|
||||
|
||||
private final PendingDrops pendingDrops = new PendingDrops();
|
||||
|
||||
public ModelContainer() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,14 +84,31 @@ public class ModelContainer {
|
||||
/**
|
||||
* Apply a migration with associated changeSets to the model.
|
||||
*/
|
||||
public void apply(Migration migration) {
|
||||
public void apply(Migration migration, MigrationVersion version) {
|
||||
|
||||
List<ChangeSet> changeSets = migration.getChangeSet();
|
||||
for (ChangeSet changeSet : changeSets) {
|
||||
applyChangeSet(changeSet);
|
||||
boolean pending = changeSet.getType() == ChangeSetType.PENDING_DROPS;
|
||||
if (pending) {
|
||||
// un-applied drop columns etc
|
||||
pendingDrops.add(version, changeSet);
|
||||
} else if (isDropsFor(changeSet)) {
|
||||
// applied drops (so no longer pending)
|
||||
pendingDrops.remove(MigrationVersion.parse(changeSet.getDropsFor()));
|
||||
}
|
||||
if (!isDropsFor(changeSet)) {
|
||||
applyChangeSet(changeSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the changeSet contains drops for a previous PENDING_DROPS changeSet.
|
||||
*/
|
||||
private boolean isDropsFor(ChangeSet changeSet) {
|
||||
return changeSet.getDropsFor() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a changeSet to the model.
|
||||
*/
|
||||
@@ -245,4 +264,44 @@ public class ModelContainer {
|
||||
|
||||
indexes.put(indexName, new MIndex(indexName, tableName, columnNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are pending drops.
|
||||
*/
|
||||
public boolean hasPendingDrops() {
|
||||
return !pendingDrops.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of versions containing un-applied pending drops.
|
||||
*/
|
||||
public List<String> getPendingDrops() {
|
||||
return pendingDrops.pendingDrops();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration for the pending drops for a given version.
|
||||
*/
|
||||
public Migration migrationForPendingDrop(String pendingVersion) {
|
||||
return pendingDrops.migrationForVersion(pendingVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the drop columns on history tables that have not been applied yet.
|
||||
*/
|
||||
public void registerPendingHistoryDropColumns(ModelContainer newModel) {
|
||||
pendingDrops.registerPendingHistoryDropColumns(newModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a drop column on a history tables that has not been applied yet.
|
||||
*/
|
||||
public void registerPendingDropColumn(DropColumn dropColumn) {
|
||||
|
||||
MTable table = getTable(dropColumn.getTableName());
|
||||
if (table == null) {
|
||||
throw new IllegalArgumentException("Table ["+dropColumn.getTableName()+"] not found?");
|
||||
}
|
||||
table.registerPendingDropColumn(dropColumn.getColumnName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class ModelDiff {
|
||||
public ChangeSet getDropChangeSet() {
|
||||
// put the changes into a ChangeSet
|
||||
ChangeSet createChangeSet = new ChangeSet();
|
||||
createChangeSet.setType(ChangeSetType.DROP);
|
||||
createChangeSet.setType(ChangeSetType.PENDING_DROPS);
|
||||
createChangeSet.getChangeSetChildren().addAll(dropChanges);
|
||||
return createChangeSet;
|
||||
}
|
||||
@@ -156,6 +156,7 @@ public class ModelDiff {
|
||||
}
|
||||
}
|
||||
|
||||
baseModel.registerPendingHistoryDropColumns(newModel);
|
||||
}
|
||||
|
||||
protected void addDropTable(MTable existingTable) {
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The migrations with pending un-applied drops.
|
||||
*/
|
||||
public class PendingDrops {
|
||||
|
||||
private final LinkedHashMap<String, Entry> map = new LinkedHashMap<String, Entry>();
|
||||
|
||||
/**
|
||||
* Add a 'pending drops' changeSet for the given version.
|
||||
*/
|
||||
public void add(MigrationVersion version, ChangeSet changeSet) {
|
||||
|
||||
Entry entry = map.get(version.normalised());
|
||||
if (entry == null) {
|
||||
entry = new Entry(version);
|
||||
map.put(version.normalised(), entry);
|
||||
}
|
||||
entry.add(changeSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of versions with pending drops.
|
||||
*/
|
||||
public List<String> pendingDrops() {
|
||||
|
||||
List<String> versions = new ArrayList<String>();
|
||||
for (Entry value : map.values()) {
|
||||
versions.add(value.version.asString());
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the pending drops for a version (as they have been applied).
|
||||
*/
|
||||
public void remove(MigrationVersion version) {
|
||||
map.remove(version.normalised());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there are no pending drops.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the migration for the pending drops from a version.
|
||||
* <p>
|
||||
* The value of version can be "next" to find the first un-applied pending drops.
|
||||
* </p>
|
||||
*/
|
||||
public Migration migrationForVersion(String pendingVersion) {
|
||||
|
||||
Entry entry = getChangeSets(pendingVersion);
|
||||
|
||||
Migration migration = new Migration();
|
||||
for (ChangeSet changeSet : entry.list) {
|
||||
changeSet.setType(ChangeSetType.APPLY);
|
||||
changeSet.setDropsFor(entry.version.asString());
|
||||
migration.getChangeSet().add(changeSet);
|
||||
}
|
||||
|
||||
return migration;
|
||||
}
|
||||
|
||||
private Entry getChangeSets(String pendingVersion) {
|
||||
|
||||
if ("next".equalsIgnoreCase(pendingVersion)) {
|
||||
Iterator<Entry> it = map.values().iterator();
|
||||
if (it.hasNext()) {
|
||||
Entry first = it.next();
|
||||
it.remove();
|
||||
return first;
|
||||
}
|
||||
} else {
|
||||
Entry remove = map.remove(MigrationVersion.parse(pendingVersion).normalised());
|
||||
if (remove != null) {
|
||||
return remove;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No pending changeSets for version [" + pendingVersion + "] found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Register pending drop columns on history tables to the new model.
|
||||
*/
|
||||
public void registerPendingHistoryDropColumns(ModelContainer newModel) {
|
||||
|
||||
for (Entry entry : map.values()) {
|
||||
for (ChangeSet changeSet : entry.list) {
|
||||
for (Object change : changeSet.getChangeSetChildren()) {
|
||||
if (change instanceof DropColumn) {
|
||||
DropColumn dropColumn = (DropColumn) change;
|
||||
if (Boolean.TRUE.equals(dropColumn.isWithHistory())) {
|
||||
newModel.registerPendingDropColumn(dropColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Entry {
|
||||
|
||||
final MigrationVersion version;
|
||||
|
||||
final List<ChangeSet> list = new ArrayList<ChangeSet>();
|
||||
|
||||
Entry(MigrationVersion version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
void add(ChangeSet changeSet) {
|
||||
list.add(changeSet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
|
||||
import java.io.File;
|
||||
@@ -44,7 +45,7 @@ public class PlatformDdlWriter {
|
||||
|
||||
List<ChangeSet> changeSets = dbMigration.getChangeSet();
|
||||
for (ChangeSet changeSet : changeSets) {
|
||||
if (!changeSet.getChangeSetChildren().isEmpty()) {
|
||||
if (isApply(changeSet)) {
|
||||
handler.generate(write, changeSet);
|
||||
}
|
||||
}
|
||||
@@ -53,6 +54,13 @@ public class PlatformDdlWriter {
|
||||
writePlatformDdl(write, writePath, fullVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the changeSet is APPLY and not empty.
|
||||
*/
|
||||
private boolean isApply(ChangeSet changeSet) {
|
||||
return changeSet.getType() == ChangeSetType.APPLY && !changeSet.getChangeSetChildren().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the ddl files.
|
||||
*/
|
||||
@@ -66,26 +74,6 @@ public class PlatformDdlWriter {
|
||||
} finally {
|
||||
applyWriter.close();
|
||||
}
|
||||
|
||||
if (!config.isSuppressRollback() && !write.isApplyRollbackEmpty()) {
|
||||
FileWriter applyRollbackWriter = createWriter(resourcePath, fullVersion, config.getRollbackPath(), config.getRollbackSuffix());
|
||||
try {
|
||||
writeApplyRollbackDdl(applyRollbackWriter, write);
|
||||
applyRollbackWriter.flush();
|
||||
} finally {
|
||||
applyRollbackWriter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!write.isDropEmpty()) {
|
||||
FileWriter dropWriter = createWriter(resourcePath, fullVersion, config.getDropPath(), config.getDropSuffix());
|
||||
try {
|
||||
writeDropDdl(dropWriter, write);
|
||||
dropWriter.flush();
|
||||
} finally {
|
||||
dropWriter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,29 +112,6 @@ public class PlatformDdlWriter {
|
||||
writer.append(write.applyHistory().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the 'Rollback' DDL buffers to the writer.
|
||||
*/
|
||||
protected void writeApplyRollbackDdl(Writer writer, DdlWrite write) throws IOException {
|
||||
|
||||
// merge the rollback buffers in the appropriate order
|
||||
prependDropDependencies(writer, write.rollbackDropDependencies());
|
||||
writer.append("-- reverse changes\n");
|
||||
writer.append(write.rollbackForeignKeys().getBuffer());
|
||||
writer.append(write.rollback().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the 'Drop' DDL buffers to the writer.
|
||||
*/
|
||||
protected void writeDropDdl(Writer writer, DdlWrite write) throws IOException {
|
||||
|
||||
// merge the rollback buffers in the appropriate order
|
||||
prependDropDependencies(writer, write.dropDropDependencies());
|
||||
writer.append(write.dropHistory().getBuffer());
|
||||
writer.append(write.drop().getBuffer());
|
||||
}
|
||||
|
||||
private void prependDropDependencies(Writer writer, DdlBuffer buffer) throws IOException {
|
||||
if (!buffer.isEmpty()) {
|
||||
writer.append("-- drop dependencies\n");
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="changeSetType" use="required"/>
|
||||
<xsd:attribute name="dropsFor" type="xsd:string"/>
|
||||
<xsd:attribute name="generated" type="xsd:boolean"/>
|
||||
<xsd:attribute name="author" type="xsd:string"/>
|
||||
<xsd:attribute name="comment" type="xsd:string"/>
|
||||
@@ -33,7 +34,7 @@
|
||||
<xsd:simpleType name="changeSetType">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="apply"/>
|
||||
<xsd:enumeration value="drop"/>
|
||||
<xsd:enumeration value="pendingDrops"/>
|
||||
<xsd:enumeration value="baseline"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
@@ -35,7 +35,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
handler.generate(write, Helper.getAddColumn());
|
||||
|
||||
assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column added_to_foo varchar(20);\n\n");
|
||||
assertThat(write.rollback().getBuffer()).isEqualTo("alter table foo drop column added_to_foo;\n\n");
|
||||
assertThat(write.dropAll().getBuffer()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -46,8 +46,8 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
handler.generate(write, Helper.getDropColumn());
|
||||
|
||||
assertThat(write.drop().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n");
|
||||
assertThat(write.rollback().getBuffer()).isEqualTo("");
|
||||
assertThat(write.apply().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n");
|
||||
assertThat(write.dropAll().getBuffer()).isEqualTo("");
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
String createTableDDL = Helper.asText(this, "/assert/create-table.txt");
|
||||
|
||||
assertThat(write.apply().getBuffer()).isEqualTo(createTableDDL);
|
||||
assertThat(write.rollback().getBuffer().trim()).isEqualTo("drop table if exists foo;\ndrop sequence if exists foo_seq;");
|
||||
assertThat(write.dropAll().getBuffer().trim()).isEqualTo("drop table if exists foo;\ndrop sequence if exists foo_seq;");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -73,12 +73,11 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
handler.generate(write, Helper.getChangeSet());
|
||||
|
||||
String apply = Helper.asText(this, "/assert/BaseDdlHandlerTest/apply.sql");
|
||||
String rollbackLast = Helper.asText(this, "/assert/BaseDdlHandlerTest/rollback.sql");
|
||||
String apply = Helper.asText(this, "/assert/BaseDdlHandlerTest/baseApply.sql");
|
||||
String rollbackLast = Helper.asText(this, "/assert/BaseDdlHandlerTest/baseDropAll.sql");
|
||||
|
||||
assertThat(write.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(write.drop().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n");
|
||||
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
|
||||
assertThat(write.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,10 +95,10 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
handler.generate(write, createChangeSet);
|
||||
|
||||
String apply = Helper.asText(this, "/assert/changeset-apply.txt");
|
||||
String rollbackLast = Helper.asText(this, "/assert/changeset-rollback.txt");
|
||||
String rollbackLast = Helper.asText(this, "/assert/changeset-dropAll.txt");
|
||||
|
||||
assertThat(write.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
|
||||
assertThat(write.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@@ -122,8 +121,8 @@ public class BaseDdlHandlerTest extends BaseTestCase {
|
||||
|
||||
assertThat(write.apply().getBuffer()).isEqualTo(apply);
|
||||
assertThat(write.applyForeignKeys().getBuffer()).isEqualTo(applyLast);
|
||||
assertThat(write.rollbackForeignKeys().getBuffer()).isEqualTo(rollbackFirst);
|
||||
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
|
||||
assertThat(write.dropAllForeignKeys().getBuffer()).isEqualTo(rollbackFirst);
|
||||
assertThat(write.dropAll().getBuffer()).isEqualTo(rollbackLast);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -29,8 +29,8 @@ public class BaseTableDdlTest {
|
||||
String apply = write.apply().getBuffer();
|
||||
String applyLast = write.applyForeignKeys().getBuffer();
|
||||
|
||||
String rollbackFirst = write.rollbackForeignKeys().getBuffer();
|
||||
String rollbackLast = write.rollback().getBuffer();
|
||||
String rollbackFirst = write.dropAllForeignKeys().getBuffer();
|
||||
String rollbackLast = write.dropAll().getBuffer();
|
||||
|
||||
assertThat(apply).isEqualTo(Helper.asText(this, "/assert/BaseTableDdlTest/createTable-apply.txt"));
|
||||
assertThat(applyLast).isEqualTo(Helper.asText(this, "/assert/BaseTableDdlTest/createTable-applyLast.txt"));
|
||||
|
||||
+1
-6
@@ -33,14 +33,9 @@ public class H2HistoryDdlTest {
|
||||
h2Ddl.configure(ebeanServer.getServerConfig());
|
||||
h2Ddl.regenerateHistoryTriggers(write, update);
|
||||
|
||||
assertThat(write.dropHistory().isEmpty()).isFalse();
|
||||
assertThat(write.dropHistory().getBuffer()).contains("drop two");
|
||||
|
||||
assertThat(write.applyHistory().isEmpty()).isFalse();
|
||||
assertThat(write.applyHistory().getBuffer()).contains("add one");
|
||||
assertThat(write.applyHistory().getBuffer()).doesNotContain("two");
|
||||
|
||||
assertThat(write.rollback().isEmpty()).isFalse();
|
||||
assertThat(write.dropAll().isEmpty()).isTrue();
|
||||
|
||||
}
|
||||
}
|
||||
+2
-74
@@ -2,80 +2,19 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class HistoryTableUpdateTest {
|
||||
|
||||
@Test
|
||||
public void testToRevertedColumns_add() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
assertThat(upd.getBaseTable()).isEqualTo("mytab");
|
||||
|
||||
upd.add(HistoryTableUpdate.Change.ADD, "two");
|
||||
assertThat(upd.hasApplyChanges()).isTrue();
|
||||
assertThat(upd.hasDropChanges()).isFalse();
|
||||
|
||||
List<String> current = current();
|
||||
upd.toRevertedColumns(current);
|
||||
assertThat(current).contains("one","three");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToRevertedColumns_include() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.INCLUDE, "two");
|
||||
assertThat(upd.hasApplyChanges()).isTrue();
|
||||
assertThat(upd.hasDropChanges()).isFalse();
|
||||
|
||||
List<String> current = current();
|
||||
upd.toRevertedColumns(current);
|
||||
assertThat(current).contains("one","three");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToRevertedColumns_drop() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.DROP, "three");
|
||||
assertThat(upd.hasApplyChanges()).isFalse();
|
||||
assertThat(upd.hasDropChanges()).isTrue();
|
||||
|
||||
List<String> current = current();
|
||||
upd.toRevertedColumns(current);
|
||||
assertThat(current).contains("one","two","three");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToRevertedColumns_exclude() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.EXCLUDE, "four");
|
||||
assertThat(upd.hasApplyChanges()).isTrue();
|
||||
assertThat(upd.hasDropChanges()).isFalse();
|
||||
|
||||
List<String> current = current();
|
||||
upd.toRevertedColumns(current);
|
||||
assertThat(current).contains("one","two","three","four");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDescription() throws Exception {
|
||||
|
||||
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
|
||||
upd.add(HistoryTableUpdate.Change.ADD, "two");
|
||||
upd.add(HistoryTableUpdate.Change.DROP, "four");
|
||||
assertThat(upd.hasApplyChanges()).isTrue();
|
||||
assertThat(upd.hasDropChanges()).isTrue();
|
||||
|
||||
assertThat(upd.descriptionForApply()).isEqualTo("add two");
|
||||
assertThat(upd.descriptionForDrop()).isEqualTo("drop four");
|
||||
assertThat(upd.description()).isEqualTo("[add two, drop four]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -86,19 +25,8 @@ public class HistoryTableUpdateTest {
|
||||
upd.add(HistoryTableUpdate.Change.INCLUDE, "five");
|
||||
upd.add(HistoryTableUpdate.Change.EXCLUDE, "six");
|
||||
upd.add(HistoryTableUpdate.Change.DROP, "four");
|
||||
assertThat(upd.hasApplyChanges()).isTrue();
|
||||
assertThat(upd.hasDropChanges()).isTrue();
|
||||
|
||||
assertThat(upd.descriptionForApply()).isEqualTo("add two, include five, exclude six");
|
||||
assertThat(upd.descriptionForDrop()).isEqualTo("drop four");
|
||||
assertThat(upd.description()).isEqualTo("[add two, include five, exclude six, drop four]");
|
||||
}
|
||||
|
||||
List<String> current() {
|
||||
|
||||
List<String> currentColumns = new ArrayList<String>();
|
||||
currentColumns.add("one");
|
||||
currentColumns.add("two");
|
||||
currentColumns.add("three");
|
||||
return currentColumns;
|
||||
}
|
||||
}
|
||||
@@ -57,11 +57,11 @@ public class MTableTest {
|
||||
public void test_allHistoryColumns() throws Exception {
|
||||
|
||||
MTable base = base();
|
||||
base.registerDroppedColumn("fullName",2);
|
||||
base.registerDroppedColumn("last",4);
|
||||
base.registerPendingDropColumn("fullName");
|
||||
base.registerPendingDropColumn("last");
|
||||
|
||||
assertThat(base.allHistoryColumns(false)).containsExactly("id","name","status");
|
||||
assertThat(base.allHistoryColumns(true)).containsExactly("id","name","fullName","status","last");
|
||||
assertThat(base.allHistoryColumns(true)).containsExactly("id","name","status","fullName","last");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -6,8 +6,47 @@ import static org.assertj.core.api.StrictAssertions.assertThat;
|
||||
|
||||
public class MigrationVersionTest {
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testParse() throws Exception {
|
||||
public void test_parse_getComment() throws Exception {
|
||||
|
||||
assertThat(MigrationVersion.parse("1.1.1_2__Foo").getComment()).isEqualTo("Foo");
|
||||
assertThat(MigrationVersion.parse("1.1.1.2__junk").getComment()).isEqualTo("junk");
|
||||
assertThat(MigrationVersion.parse("1.1_1.2_foo").getComment()).isEqualTo("");
|
||||
assertThat(MigrationVersion.parse("1.1_1.2_d").getComment()).isEqualTo("");
|
||||
assertThat(MigrationVersion.parse("1.1_1.2_").getComment()).isEqualTo("");
|
||||
assertThat(MigrationVersion.parse("1.1_1.2").getComment()).isEqualTo("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_nextVersion_expect_preserveUnderscores() {
|
||||
|
||||
assertThat(MigrationVersion.parse("2").nextVersion()).isEqualTo("3");
|
||||
assertThat(MigrationVersion.parse("1.0").nextVersion()).isEqualTo("1.1");
|
||||
assertThat(MigrationVersion.parse("2.0.b34").nextVersion()).isEqualTo("2.1");
|
||||
assertThat(MigrationVersion.parse("1.1.1_2__Foo").nextVersion()).isEqualTo("1.1.1_3");
|
||||
assertThat(MigrationVersion.parse("1.1.1.2_junk").nextVersion()).isEqualTo("1.1.1.3");
|
||||
assertThat(MigrationVersion.parse("1_2.3_4__Foo").nextVersion()).isEqualTo("1_2.3_5");
|
||||
assertThat(MigrationVersion.parse("1_2.3_4_").nextVersion()).isEqualTo("1_2.3_5");
|
||||
assertThat(MigrationVersion.parse("1_2_3_4__Foo").nextVersion()).isEqualTo("1_2_3_5");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_normalised_expect_periods() {
|
||||
|
||||
assertThat(MigrationVersion.parse("2").normalised()).isEqualTo("2");
|
||||
assertThat(MigrationVersion.parse("1.0").normalised()).isEqualTo("1.0");
|
||||
assertThat(MigrationVersion.parse("2.0.b34").normalised()).isEqualTo("2.0");
|
||||
assertThat(MigrationVersion.parse("1.1.1_2__Foo").normalised()).isEqualTo("1.1.1.2");
|
||||
assertThat(MigrationVersion.parse("1.1.1.2_junk").normalised()).isEqualTo("1.1.1.2");
|
||||
assertThat(MigrationVersion.parse("1_2.3_4__Foo").normalised()).isEqualTo("1.2.3.4");
|
||||
assertThat(MigrationVersion.parse("1_2.3_4_").normalised()).isEqualTo("1.2.3.4");
|
||||
assertThat(MigrationVersion.parse("1_2_3_4__Foo").normalised()).isEqualTo("1.2.3.4");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_compareTo_isEqual() throws Exception {
|
||||
|
||||
MigrationVersion v0 = MigrationVersion.parse("1.1.1_2__Foo");
|
||||
MigrationVersion v1 = MigrationVersion.parse("1.1.1.2_junk");
|
||||
@@ -16,32 +55,21 @@ public class MigrationVersionTest {
|
||||
assertThat(v0.compareTo(v1)).isEqualTo(0);
|
||||
assertThat(v1.compareTo(v0)).isEqualTo(0);
|
||||
assertThat(v1.compareTo(v2)).isEqualTo(0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNextVersion() {
|
||||
|
||||
assertThat(MigrationVersion.parse("2").nextVersion()).isEqualTo("3");
|
||||
assertThat(MigrationVersion.parse("1.0").nextVersion()).isEqualTo("1.1");
|
||||
assertThat(MigrationVersion.parse("2.0.b34").nextVersion()).isEqualTo("2.1");
|
||||
assertThat(MigrationVersion.parse("1.1.1_2__Foo").nextVersion()).isEqualTo("1.1.1.3");
|
||||
assertThat(MigrationVersion.parse("1.1.1.2_junk").nextVersion()).isEqualTo("1.1.1.3");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareTo() throws Exception {
|
||||
public void test_compareTo() throws Exception {
|
||||
|
||||
MigrationVersion v0 = MigrationVersion.parse("1.1.1.1_junk");
|
||||
MigrationVersion v1 = MigrationVersion.parse("1.1.1.2_junk");
|
||||
MigrationVersion v2 = MigrationVersion.parse("2.1_1.2_junk");
|
||||
MigrationVersion v2 = MigrationVersion.parse("1.1_1.3_junk");
|
||||
MigrationVersion v3 = MigrationVersion.parse("1.2_1.2_junk");
|
||||
MigrationVersion v4 = MigrationVersion.parse("1.1_1.3_junk");
|
||||
MigrationVersion v5 = MigrationVersion.parse("1.1.1.1_junk");
|
||||
MigrationVersion v4 = MigrationVersion.parse("2.1_1.2_junk");
|
||||
|
||||
assertThat(v1.compareTo(v0)).isEqualTo(1);
|
||||
|
||||
assertThat(v1.compareTo(v2)).isEqualTo(-1);
|
||||
assertThat(v1.compareTo(v3)).isEqualTo(-1);
|
||||
assertThat(v1.compareTo(v4)).isEqualTo(-1);
|
||||
|
||||
assertThat(v1.compareTo(v5)).isEqualTo(1);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class ModelContainerApplyTest {
|
||||
assertThat(changeSetChildren.get(2)).isInstanceOf(DropColumn.class);
|
||||
|
||||
ModelContainer model = new ModelContainer();
|
||||
model.apply(migration);
|
||||
model.apply(migration, MigrationVersion.parse("1.1"));
|
||||
|
||||
MTable foo = model.getTable("foo");
|
||||
assertThat(foo.getComment()).isEqualTo("comment");
|
||||
|
||||
+2
@@ -9,3 +9,5 @@ create sequence foo_seq;
|
||||
|
||||
alter table foo add column added_to_foo varchar(20);
|
||||
|
||||
alter table foo drop column col2;
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
drop table if exists foo;
|
||||
drop sequence if exists foo_seq;
|
||||
|
||||
alter table foo drop column added_to_foo;
|
||||
|
||||
Reference in New Issue
Block a user