mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#374 - Refactor to support generating multiple platform DDL for a single migration
This commit is contained in:
@@ -16,11 +16,12 @@ import com.avaje.ebean.config.dbplatform.PostgresPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
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.ModelContainer;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDdlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.PlatformDdlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDiff;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
@@ -28,25 +29,29 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class DbMigration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
|
||||
|
||||
private SpiEbeanServer server;
|
||||
protected SpiEbeanServer server;
|
||||
|
||||
private DbMigrationConfig migrationConfig;
|
||||
protected DbMigrationConfig migrationConfig;
|
||||
|
||||
private String pathToResources = "src/main/resources";
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
private DatabasePlatform databasePlatform;
|
||||
protected DatabasePlatform databasePlatform;
|
||||
|
||||
private ServerConfig serverConfig;
|
||||
protected List<Pair> platforms = new ArrayList<Pair>();
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
protected ServerConfig serverConfig;
|
||||
|
||||
protected DbConstraintNaming constraintNaming;
|
||||
|
||||
public DbMigration() {
|
||||
DbOffline.asH2();
|
||||
@@ -82,6 +87,16 @@ public class DbMigration {
|
||||
DbOffline.setPlatform(databasePlatform.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional platform to write the migration DDL.
|
||||
*/
|
||||
public void addPlatform(DbPlatformName platform, String prefix) {
|
||||
if (!prefix.endsWith("-")) {
|
||||
prefix+="-";
|
||||
}
|
||||
platforms.add(new Pair(getPlatform(platform), prefix));
|
||||
}
|
||||
|
||||
|
||||
public void runMigration() throws IOException {
|
||||
|
||||
@@ -102,35 +117,58 @@ public class DbMigration {
|
||||
|
||||
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();
|
||||
|
||||
// writer needs the current model to provide table/column details for
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
File writePath = getWritePath();
|
||||
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
|
||||
writeMigrationXml(dbMigration, writePath, nextMajorVersion);
|
||||
|
||||
ModelDdlWriter writer = new ModelDdlWriter(databasePlatform, serverConfig);
|
||||
if (!writer.processMigration(dbMigration, write)) {
|
||||
logger.info("no changes detected - no migration written");
|
||||
|
||||
} else {
|
||||
// there were actually changes to write
|
||||
File writePath = getWritePath();
|
||||
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
|
||||
writer.writeMigration(writePath, nextMajorVersion);
|
||||
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(), currentModel.read());
|
||||
PlatformDdlWriter writer = new PlatformDdlWriter(databasePlatform, serverConfig);
|
||||
writer.processMigration(dbMigration, write, writePath, nextMajorVersion);
|
||||
}
|
||||
|
||||
writeExtraPlatformDdl(nextMajorVersion, currentModel, dbMigration, writePath);
|
||||
|
||||
} finally {
|
||||
DbOffline.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write any extra platform ddl.
|
||||
*/
|
||||
protected void writeExtraPlatformDdl(int nextMajorVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
|
||||
|
||||
for (Pair pair : platforms) {
|
||||
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
|
||||
PlatformDdlWriter platformWriter = new PlatformDdlWriter(pair.platform, serverConfig, pair.prefix);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, writePath, nextMajorVersion);
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeMigrationXml(Migration dbMigration, File resourcePath, int migrationVersion) {
|
||||
File file = new File(resourcePath, "v"+migrationVersion+".0.xml");
|
||||
|
||||
MigrationXmlWriter xmlWriter = new MigrationXmlWriter();
|
||||
xmlWriter.write(dbMigration, file);
|
||||
}
|
||||
|
||||
protected void setDefaults() {
|
||||
if (server == null) {
|
||||
setServer(Ebean.getDefaultServer());
|
||||
}
|
||||
if (databasePlatform == null) {
|
||||
databasePlatform = server.getDatabasePlatform();
|
||||
}
|
||||
}
|
||||
|
||||
protected File getWritePath() {
|
||||
@@ -172,4 +210,26 @@ public class DbMigration {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds a platform and prefix. Used to generate multiple platform specific DDL
|
||||
* for a single migration.
|
||||
*/
|
||||
public static class Pair {
|
||||
|
||||
/**
|
||||
* The platform to generate the DDL for.
|
||||
*/
|
||||
public final DatabasePlatform platform;
|
||||
|
||||
/**
|
||||
* A prefix included into the file/resource names indicating the platform.
|
||||
*/
|
||||
public final String prefix;
|
||||
|
||||
public Pair(DatabasePlatform platform, String prefix) {
|
||||
this.platform = platform;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -81,17 +81,18 @@ public class DdlWrite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true the drop buffer is empty.
|
||||
* Return true if the apply rollback buffers are all empty.
|
||||
*/
|
||||
public boolean isDropEmpty() {
|
||||
return drop.getBuffer().isEmpty();
|
||||
public boolean isApplyRollbackEmpty() {
|
||||
return rollback.getBuffer().isEmpty()
|
||||
&& rollbackForeignKeys.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true the drop history buffer is empty.
|
||||
* Return true the drop buffers are empty.
|
||||
*/
|
||||
public boolean isDropHistoryEmpty() {
|
||||
return dropHistory.getBuffer().isEmpty();
|
||||
public boolean isDropEmpty() {
|
||||
return drop.getBuffer().isEmpty() && dropHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
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.Migration;
|
||||
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ModelDdlWriter {
|
||||
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DatabasePlatform platform;
|
||||
|
||||
private Migration dbMigration;
|
||||
|
||||
private DdlWrite write;
|
||||
|
||||
int changeSetCount;
|
||||
|
||||
public ModelDdlWriter(DatabasePlatform platform, ServerConfig serverConfig) {
|
||||
this.platform = platform;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
public boolean processMigration(Migration dbMigration, DdlWrite write) throws IOException {
|
||||
|
||||
this.changeSetCount = 0;
|
||||
this.dbMigration = dbMigration;
|
||||
this.write = write;
|
||||
|
||||
DdlHandler handler = handler();
|
||||
|
||||
List<ChangeSet> changeSets = dbMigration.getChangeSet();
|
||||
for (ChangeSet changeSet : changeSets) {
|
||||
if (!changeSet.getChangeSetChildren().isEmpty()) {
|
||||
changeSetCount++;
|
||||
handler.generate(write, changeSet);
|
||||
}
|
||||
}
|
||||
handler.generateExtra(write);
|
||||
|
||||
return changeSetCount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write as migration xml to the given file.
|
||||
*/
|
||||
public void writeMigration(File resourcePath, int migrationVersion) throws IOException {
|
||||
|
||||
File file = new File(resourcePath, "v"+migrationVersion+".0.xml");
|
||||
|
||||
MigrationXmlWriter xmlWriter = new MigrationXmlWriter();
|
||||
xmlWriter.write(dbMigration, file);
|
||||
|
||||
if (!write.isApplyEmpty()) {
|
||||
FileWriter ddlWriter = createWriter(resourcePath, migrationVersion, ".0-apply.sql");
|
||||
try {
|
||||
writeApplyDdl(ddlWriter);
|
||||
ddlWriter.flush();
|
||||
} finally {
|
||||
ddlWriter.close();
|
||||
}
|
||||
|
||||
FileWriter rbWriter = createWriter(resourcePath, migrationVersion, ".0-applyRollback.sql");
|
||||
try {
|
||||
writeApplyRollbackDdl(rbWriter);
|
||||
rbWriter.flush();
|
||||
} finally {
|
||||
rbWriter.close();
|
||||
}
|
||||
}
|
||||
|
||||
String content = write.drop().getBuffer();
|
||||
if (!content.isEmpty()) {
|
||||
writeFile(resourcePath, migrationVersion, ".0-drop.sql", content);
|
||||
}
|
||||
|
||||
String dropHistory = write.dropHistory().getBuffer();
|
||||
if (!dropHistory.isEmpty()) {
|
||||
writeFile(resourcePath, migrationVersion, ".0-dropHistory.sql", dropHistory);
|
||||
}
|
||||
}
|
||||
|
||||
private FileWriter createWriter(File resourcePath, int migrationVersion, String suffix) throws IOException {
|
||||
|
||||
File applyFile = new File(resourcePath, "v" + migrationVersion + suffix);
|
||||
return new FileWriter(applyFile);
|
||||
}
|
||||
|
||||
private void writeFile(File resourcePath, int migrationVersion, String suffix, String content) throws IOException {
|
||||
|
||||
FileWriter ddlWriter =createWriter(resourcePath, migrationVersion, suffix);
|
||||
try {
|
||||
ddlWriter.append(content);
|
||||
ddlWriter.flush();
|
||||
} finally {
|
||||
ddlWriter.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the 'Create' DDL.
|
||||
*/
|
||||
private void writeApplyDdl(Writer writer) throws IOException {
|
||||
|
||||
writer.append(write.apply().getBuffer());
|
||||
writer.append(write.applyForeignKeys().getBuffer());
|
||||
writer.append(write.applyHistory().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'Rollback' DDL.
|
||||
*/
|
||||
private void writeApplyRollbackDdl(Writer writer) throws IOException {
|
||||
|
||||
writer.append(write.rollbackForeignKeys().getBuffer());
|
||||
writer.append(write.rollback().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform specific DdlHandler (to generate DDL).
|
||||
*/
|
||||
private DdlHandler handler() {
|
||||
return platform.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,6 +50,15 @@ public class ModelDiff {
|
||||
this.baseModel = new ModelContainer();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the apply and drop changes are both empty.
|
||||
* This means there are no migration changes.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return applyChanges.isEmpty() && dropChanges.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the diff as a migration potentially containing
|
||||
* an apply changeSet and a drop changeSet.
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
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.Migration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Writes migration changes as platform specific DDL.
|
||||
*/
|
||||
public class PlatformDdlWriter {
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DatabasePlatform platform;
|
||||
|
||||
private final String platformPrefix;
|
||||
|
||||
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig) {
|
||||
this(platform, serverConfig, "");
|
||||
}
|
||||
|
||||
public PlatformDdlWriter(DatabasePlatform platform, ServerConfig serverConfig, String platformPrefix) {
|
||||
this.platform = platform;
|
||||
this.serverConfig = serverConfig;
|
||||
this.platformPrefix = platformPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the migration as platform specific ddl.
|
||||
*/
|
||||
public void processMigration(Migration dbMigration, DdlWrite write, File writePath, int nextMajorVersion) throws IOException {
|
||||
|
||||
DdlHandler handler = handler();
|
||||
|
||||
List<ChangeSet> changeSets = dbMigration.getChangeSet();
|
||||
for (ChangeSet changeSet : changeSets) {
|
||||
if (!changeSet.getChangeSetChildren().isEmpty()) {
|
||||
handler.generate(write, changeSet);
|
||||
}
|
||||
}
|
||||
handler.generateExtra(write);
|
||||
|
||||
writePlatformDdl(write, writePath, nextMajorVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the ddl files.
|
||||
*/
|
||||
protected void writePlatformDdl(DdlWrite write, File resourcePath, int migrationVersion) throws IOException {
|
||||
|
||||
if (!write.isApplyEmpty()) {
|
||||
FileWriter applyWriter = createWriter(resourcePath, migrationVersion, "apply.sql");
|
||||
try {
|
||||
writeApplyDdl(applyWriter, write);
|
||||
applyWriter.flush();
|
||||
} finally {
|
||||
applyWriter.close();
|
||||
}
|
||||
|
||||
if (!write.isApplyRollbackEmpty()) {
|
||||
FileWriter applyRollbackWriter = createWriter(resourcePath, migrationVersion, "applyRollback.sql");
|
||||
try {
|
||||
writeApplyRollbackDdl(applyRollbackWriter, write);
|
||||
applyRollbackWriter.flush();
|
||||
} finally {
|
||||
applyRollbackWriter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!write.isDropEmpty()) {
|
||||
FileWriter dropWriter = createWriter(resourcePath, migrationVersion, "drop.sql");
|
||||
try {
|
||||
writeDropDdl(dropWriter, write);
|
||||
dropWriter.flush();
|
||||
} finally {
|
||||
dropWriter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected FileWriter createWriter(File resourcePath, int migrationVersion, String suffix) throws IOException {
|
||||
|
||||
File applyFile = new File(resourcePath, "v" + migrationVersion + ".0-" + platformPrefix + suffix);
|
||||
return new FileWriter(applyFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the 'Apply' DDL buffers to the writer.
|
||||
*/
|
||||
protected void writeApplyDdl(Writer writer, DdlWrite write) throws IOException {
|
||||
|
||||
// merge the apply buffers in the appropriate order
|
||||
writer.append(write.apply().getBuffer());
|
||||
writer.append(write.applyForeignKeys().getBuffer());
|
||||
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
|
||||
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
|
||||
writer.append(write.dropHistory().getBuffer());
|
||||
writer.append(write.drop().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform specific DdlHandler (to generate DDL).
|
||||
*/
|
||||
protected DdlHandler handler() {
|
||||
return platform.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user