#374 - Move db constraint max length to database platform

This commit is contained in:
Robin Bygrave
2015-08-14 17:06:08 +12:00
parent 60c1a5b111
commit 215417a43c
27 changed files with 587 additions and 1432 deletions
File diff suppressed because it is too large Load Diff
@@ -9,6 +9,21 @@ package com.avaje.ebean.config;
*/
public class DbConstraintNaming {
/**
* Defines how constraint names are shortened if required based on platform limitations.
*/
public interface MaxLength {
/**
* Truncate or shorten the constraint name to support DB platform limitations.
* <p>
* There is a default implementation of this which is used if an implementation is
* not specified.
* </p>
*/
String maxLength(String constraintName, int count);
}
protected String pkPrefix = "pk_";
protected String pkSuffix = "";
@@ -28,11 +43,27 @@ public class DbConstraintNaming {
protected boolean lowerCaseNames = true;
protected MaxLength maxLength;
protected DbConstraintNormalise normalise = new DbConstraintNormalise();
public DbConstraintNaming() {
}
/**
* Return the MaxLength implementation used to truncate/shorten db constraint names as necessary.
*/
public MaxLength getMaxLength() {
return maxLength;
}
/**
* Set the MaxLength implementation used to truncate/shorten db constraint names as necessary.
*/
public void setMaxLength(MaxLength maxLength) {
this.maxLength = maxLength;
}
/**
* Return the primary key constraint name.
*/
@@ -16,6 +16,7 @@ public class DB2Platform extends DatabasePlatform {
super();
this.name = "db2";
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.sqlLimiter = new Db2SqlLimiter();
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
@@ -26,7 +27,6 @@ public class DB2Platform extends DatabasePlatform {
dbTypeMap.put(Types.REAL, new DbType("real"));
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
}
/**
@@ -152,6 +152,12 @@ public class DatabasePlatform {
*/
protected int maxTableNameLength = 60;
/**
* A value of 60 is a reasonable default for all databases except
* Oracle (limited to 30) and DB2 (limited to 18).
*/
protected int maxConstraintNameLength = 60;
/**
* Instantiates a new database platform.
*/
@@ -179,6 +185,13 @@ public class DatabasePlatform {
return maxTableNameLength;
}
/**
* Return the maximum constraint name allowed for the platform.
*/
public int getMaxConstraintNameLength() {
return maxConstraintNameLength;
}
/**
* Return the platform specific DDL.
*/
@@ -0,0 +1,47 @@
package com.avaje.ebean.config.dbplatform;
/**
* Built in supported platforms.
*/
public enum DbPlatformName {
/**
* Generic base platform configured via properties or code.
*/
GENERIC,
/**
* H2.
*/
H2,
/**
* Postgres.
*/
POSTGRES,
/**
* MySql.
*/
MYSQL,
/**
* Oracle.
*/
ORACLE,
/**
* Microsoft SQL Server.
*/
SQLSERVER,
/**
* DB2.
*/
DB2,
/**
* SQLite.
*/
SQLITE
}
@@ -15,6 +15,7 @@ public class Oracle10Platform extends DatabasePlatform {
super();
this.name = "oracle";
this.maxTableNameLength = 30;
this.maxConstraintNameLength = 30;
// OnQueryOnly.CLOSE as a performance optimisation on Oracle
this.onQueryOnly = OnQueryOnly.CLOSE;
this.dbEncrypt = new Oracle10DbEncrypt();
@@ -54,8 +55,7 @@ public class Oracle10Platform extends DatabasePlatform {
}
@Override
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
String seqName, int batchSize) {
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
}
@@ -2,13 +2,30 @@ package com.avaje.ebean.dbmigration;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.DbMigrationConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DB2Platform;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
import com.avaje.ebean.config.dbplatform.Oracle10Platform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.model.CurrentModel;
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.ModelDiff;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
/**
*
@@ -17,38 +34,131 @@ public class DbMigration {
private static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
private final SpiEbeanServer server;
private SpiEbeanServer server;
private final DbMigrationConfig migrationConfig;
private DbMigrationConfig migrationConfig;
private String pathToResources = "src/main/resources";
private DatabasePlatform databasePlatform;
private ServerConfig serverConfig;
private DbConstraintNaming constraintNaming;
public DbMigration() {
this(Ebean.getDefaultServer());
DbOffline.asH2();
}
public DbMigration(EbeanServer ebeanServer) {
public void setPathToResources(String pathToResources) {
this.pathToResources = pathToResources;
}
public void setServer(EbeanServer ebeanServer) {
this.server = (SpiEbeanServer) ebeanServer;
this.migrationConfig = server.getServerConfig().getMigrationConfig();
setServerConfig(server.getServerConfig());
}
public void writeCurrent() {
CurrentModel currentModel = new CurrentModel(server);
File writeTo = getWritePath();
logger.info("... write to {}", writeTo.getAbsolutePath());
currentModel.writeMigration(writeTo);
public void setServerConfig(ServerConfig config) {
if (this.serverConfig == null) {
this.serverConfig = config;
}
if (migrationConfig == null) {
this.migrationConfig = serverConfig.getMigrationConfig();
}
if (constraintNaming == null) {
this.constraintNaming = serverConfig.getConstraintNaming();
}
}
public File getWritePath() {
File resourceRootDir = new File("./dbmigration-test/resources");
public void setPlatform(DbPlatformName platform) {
setPlatform(getPlatform(platform));
}
public void setPlatform(DatabasePlatform databasePlatform) {
this.databasePlatform = databasePlatform;
DbOffline.setPlatform(databasePlatform.getName());
}
public void runMigration() throws IOException {
setDefaults();
try {
MigrationModel migrationModel = new MigrationModel(migrationConfig.getResourcePath());
ModelContainer migrated = migrationModel.read();
int nextMajorVersion = migrationModel.getNextMajorVersion();
logger.info("next migration version {}", nextMajorVersion);
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
ModelContainer current = currentModel.read();
ModelDiff diff = new ModelDiff(migrated);
diff.compareTo(current);
Migration dbMigration = diff.getMigration();
ModelDdlWriter writer = new ModelDdlWriter(databasePlatform, serverConfig);
writer.processMigration(dbMigration);
File writePath = getWritePath();
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
writer.writeMigration(writePath, nextMajorVersion);
} finally {
DbOffline.reset();
}
}
protected void setDefaults() {
if (server == null) {
String set = DbOffline.getPlatform();
setServer(Ebean.getDefaultServer());
}
if (databasePlatform == null) {
databasePlatform = server.getDatabasePlatform();
}
}
protected File getWritePath() {
// path to src/main/resources in typical maven project
File resourceRootDir = new File(pathToResources);
// expect to be a relative path
String resourcePath = migrationConfig.getResourcePath();
// expect to be a path to something like - src/main/resources/dbmigration/myapp
File path = new File(resourceRootDir, resourcePath);
if (!path.exists()) {
path.mkdirs();
if (!path.mkdirs()) {
logger.debug("Unable to ensure migration directory exists at {}", path.getAbsolutePath());
}
}
return new File(path, "migration-current.xml");
return path;
}
protected DatabasePlatform getPlatform(DbPlatformName platform) {
switch (platform) {
case H2:
return new H2Platform();
case POSTGRES:
return new PostgresPlatform();
case MYSQL:
return new MySqlPlatform();
case ORACLE:
return new Oracle10Platform();
case SQLSERVER:
return new MsSqlServer2005Platform();
case DB2:
return new DB2Platform();
case SQLITE:
return new SQLitePlatform();
default:
throw new IllegalArgumentException("Platform missing? " + platform);
}
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.config.dbplatform.DbPlatformName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -12,7 +13,9 @@ public class DbOffline {
private static final String KEY = "ebean.dboffline";
public static final String H2 = "H2";
public static void setPlatform(DbPlatformName dbPlatform) {
System.setProperty(KEY, dbPlatform.name());
}
public static void setPlatform(String platformName) {
System.setProperty(KEY, platformName);
@@ -23,7 +26,7 @@ public class DbOffline {
}
public static void asH2() {
setPlatform(H2);
setPlatform(DbPlatformName.H2);
}
public static boolean isSet() {
@@ -62,10 +62,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
if (generateDdl) {
writeDrop(getDropFileName());
writeCreate(getCreateFileName());
String mn = server.getName() + "-migration.xml";
File migrationXml = new File(mn);
writeMigration(migrationXml);
}
}
@@ -122,11 +118,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
}
}
public void writeMigration(File file) {
currentModel().writeMigration(file);
}
public String generateCreateDdl() {
try {
@@ -138,11 +129,11 @@ public class DdlGenerator implements SpiEbeanPlugin {
}
protected String getDropFileName() {
return server.getName() + "-drop.sql";
return server.getName() + "-drop-all.sql";
}
protected String getCreateFileName() {
return server.getName() + "-create.sql";
return server.getName() + "-create-all.sql";
}
protected CurrentModel currentModel() {
@@ -14,6 +14,11 @@ public interface DdlBuffer {
*/
MConfiguration getConfiguration();
/**
* Return true if the buffer is empty.
*/
boolean isEmpty();
/**
* Append DDL content to the buffer.
*/
@@ -20,7 +20,24 @@ public class DdlWrite {
private final DdlBuffer rollbackForeignKeys;
private final DdlBuffer rollbackLast;
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;
/**
* Create without any configuration or current model (no history support).
@@ -38,7 +55,9 @@ public class DdlWrite {
this.applyForeignKeys = new BaseDdlBuffer(configuration);
this.applyHistory = new BaseDdlBuffer(configuration);
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
this.rollbackLast = new BaseDdlBuffer(configuration);
this.rollback = new BaseDdlBuffer(configuration);
this.drop = new BaseDdlBuffer(configuration);
this.dropHistory = new BaseDdlBuffer(configuration);
}
/**
@@ -52,6 +71,29 @@ public class DdlWrite {
return currentModel.getTable(tableName);
}
/**
* Return true if the apply buffers are all empty.
*/
public boolean isApplyEmpty() {
return apply.getBuffer().isEmpty()
&& applyForeignKeys.getBuffer().isEmpty()
&& applyHistory.getBuffer().isEmpty();
}
/**
* Return true the drop buffer is empty.
*/
public boolean isDropEmpty() {
return drop.getBuffer().isEmpty();
}
/**
* Return true the drop history buffer is empty.
*/
public boolean isDropHistoryEmpty() {
return dropHistory.getBuffer().isEmpty();
}
/**
* Return the buffer that APPLY DDL is written to.
*/
@@ -84,13 +126,33 @@ public class DdlWrite {
}
/**
* Return the buffer that ROLLBACK DDL is written to (typically drop tables).
* 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>
* Statements added to this rollback buffer are executed after foreign key rollback
* 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 rollbackLast;
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;
}
@@ -4,6 +4,7 @@ import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.DropTable;
import java.io.IOException;
@@ -22,14 +23,18 @@ public interface TableDdl {
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
/**
* Write the alter column changes.
*/
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
}
@@ -5,14 +5,13 @@ import com.avaje.ebean.dbmigration.model.MConfiguration;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
/**
* Base implementation of DdlBuffer using an underlying writer.
*/
public class BaseDdlBuffer implements DdlBuffer {
protected final Writer writer;
protected final StringWriter writer;
protected final MConfiguration configuration;
@@ -26,6 +25,11 @@ public class BaseDdlBuffer implements DdlBuffer {
return configuration;
}
@Override
public boolean isEmpty() {
return writer.getBuffer().length() == 0;
}
@Override
public DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException {
if (foreignKeyRestrict != null && !foreignKeyRestrict.isEmpty()) {
@@ -13,6 +13,7 @@ import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.Column;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.DropTable;
import com.avaje.ebean.dbmigration.migration.ForeignKey;
import com.avaje.ebean.dbmigration.model.MTable;
@@ -460,15 +461,20 @@ public class BaseTableDdl implements TableDdl {
}
}
@Override
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
String tableName = dropTable.getName();
dropTable(writer.drop(), tableName);
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
String tableName = dropColumn.getTableName();
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
// no good rollback option here, it is best if drop columns
// are put into a separate changeSet that is run last
alterTableDropColumn(writer.drop(), tableName, dropColumn.getColumnName());
}
@Override
@@ -11,7 +11,6 @@ public class DB2Ddl extends PlatformDdl {
public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
super(platformTypes, dbIdentity);
this.identitySuffix = " generated by default as identity";
this.maxConstraintNameLength = 18;
}
}
@@ -0,0 +1,37 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.VowelRemover;
/**
* Default implementation used to truncate or shorten db constraint names as required.
*/
public class DefaultConstraintMaxLength implements DbConstraintNaming.MaxLength {
private final int maxConstraintNameLength;
public DefaultConstraintMaxLength(int maxConstraintNameLength) {
this.maxConstraintNameLength = maxConstraintNameLength;
}
/**
* Apply a maximum length to the constraint name.
* <p>
* This implementation should work well apart from perhaps DB2 where the limit is 18.
*/
public String maxLength(String constraintName, int count) {
if (constraintName.length() < maxConstraintNameLength) {
return constraintName;
}
if (maxConstraintNameLength < 60) {
// trim out vowels for Oracle / DB2 with short max lengths
constraintName = VowelRemover.trim(constraintName, 4);
if (constraintName.length() < maxConstraintNameLength) {
return constraintName;
}
}
// add the count to ensure the constraint name is unique
// (relying on the prefix having the table name to be globally unique)
return constraintName.substring(0, maxConstraintNameLength - 3) + "_" + count;
}
}
@@ -13,7 +13,6 @@ public class Oracle10Ddl extends PlatformDdl {
this.dropTableIfExists = "drop table ";
this.dropSequenceIfExists = "drop sequence ";
this.dropTableCascade = " cascade constraints purge";
this.maxConstraintNameLength = 30;
this.foreignKeyRestrict = "";
}
@@ -57,12 +57,6 @@ public class PlatformDdl {
*/
protected boolean inlineUniqueOneToOne = true;
/**
* A value of 60 is a reasonable default for all databases except
* Oracle (limited to 30) and DB2 (limited to 18).
*/
protected int maxConstraintNameLength = 60;
public PlatformDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
this.dbIdentity = dbIdentity;
this.typeConverter = new PlatformTypeConverter(platformTypes);
@@ -73,27 +67,6 @@ public class PlatformDdl {
return new BaseDdlHandler(serverConfig.getNamingConvention(), serverConfig.getConstraintNaming(), this);
}
/**
* Apply a maximum length to the constraint name.
* <p>
* This implementation should work well apart from perhaps DB2 where the limit is 18.
*/
public String maxLength(String constraintName, int count) {
if (constraintName.length() < maxConstraintNameLength) {
return constraintName;
}
if (maxConstraintNameLength < 60) {
// trim out vowels for Oracle / DB2 with short max lengths
constraintName = VowelRemover.trim(constraintName, 4);
if (constraintName.length() < maxConstraintNameLength) {
return constraintName;
}
}
// add the count to ensure the constraint name is unique
// (relying on the prefix having the table name to be globally unique)
return constraintName.substring(0, maxConstraintNameLength - 3) + "_" + count;
}
public IdType useIdentityType(IdentityType modelIdentityType) {
return dbIdentity.useIdentityType(modelIdentityType);
@@ -1,18 +1,15 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
import com.avaje.ebean.dbmigration.model.build.ModelBuildBeanVisitor;
import com.avaje.ebean.dbmigration.model.build.ModelBuildContext;
import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import java.io.File;
import java.io.IOException;
import java.util.List;
@@ -25,7 +22,7 @@ public class CurrentModel {
private final DbConstraintNaming constraintNaming;
private final PlatformDdl platformDdl;
private final DbConstraintNaming.MaxLength maxLength;
private ModelContainer model;
@@ -37,9 +34,36 @@ public class CurrentModel {
* Construct with a given EbeanServer instance.
*/
public CurrentModel(SpiEbeanServer server) {
this(server, server.getServerConfig().getConstraintNaming());
}
/**
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
* <p>
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
* the platform specific handling on
* </p>
*/
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
this.server = server;
this.platformDdl = server.getDatabasePlatform().getPlatformDdl();
this.constraintNaming = server.getServerConfig().getConstraintNaming();
this.constraintNaming = constraintNaming;
this.maxLength = maxLength(server, constraintNaming);
}
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
this.server = server;
this.constraintNaming = constraintNaming;
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
}
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
if (naming.getMaxLength() != null) {
return naming.getMaxLength();
}
int maxConstraintNameLength = server.getDatabasePlatform().getMaxConstraintNameLength();
return new DefaultConstraintMaxLength(maxConstraintNameLength);
}
/**
@@ -48,7 +72,8 @@ public class CurrentModel {
public ModelContainer read() {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, platformDdl);
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
@@ -71,19 +96,6 @@ public class CurrentModel {
return changeSet;
}
/**
* Write as migration xml to the given file.
*/
public void writeMigration(File file) {
ChangeSet changeSet = getChangeSet();
Migration migration = new Migration();
migration.getChangeSet().add(changeSet);
MigrationXmlWriter writer = new MigrationXmlWriter();
writer.write(migration, file);
}
/**
* Return the 'Create' DDL.
*/
@@ -21,6 +21,8 @@ public class MigrationModel {
private final String resourcePath;
int nextMajorVersion;
public MigrationModel(String resourcePath) {
this.resourcePath = normaliseResourcePath(resourcePath);
}
@@ -55,10 +57,16 @@ public class MigrationModel {
return readVersions;
}
public int getNextMajorVersion() {
return nextMajorVersion;
}
private void readMigrations() {
for (int majorVersion = 1; majorVersion < 100; majorVersion++) {
if (!readMinorVersions(majorVersion)){
// no major.0 version so stopping
nextMajorVersion = majorVersion;
return;
}
}
@@ -82,6 +90,7 @@ public class MigrationModel {
Migration migration = MigrationXmlReader.readMaybe(path);
if (migration == null) {
logger.info("... no migration at path:{}", path);
return false;
}
readVersions.add(version);
@@ -0,0 +1,131 @@
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;
public ModelDdlWriter(DatabasePlatform platform, ServerConfig serverConfig) {
this.platform = platform;
this.serverConfig = serverConfig;
}
public void processMigration(Migration dbMigration) throws IOException {
this.dbMigration = dbMigration;
this.write = new DdlWrite();
DdlHandler handler = handler();
List<ChangeSet> changeSets = dbMigration.getChangeSet();
for (ChangeSet changeSet : changeSets) {
handler.generate(write, changeSet);
}
}
/**
* 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);
}
}
@@ -2,7 +2,10 @@ package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.AddColumn;
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.DropColumn;
import com.avaje.ebean.dbmigration.migration.Migration;
import java.util.ArrayList;
import java.util.List;
@@ -49,6 +52,30 @@ public class ModelDiff {
return createChanges;
}
public ChangeSet getApplyChangeSet() {
// put the changes into a ChangeSet
ChangeSet createChangeSet = new ChangeSet();
createChangeSet.setType(ChangeSetType.APPLY);
createChangeSet.getChangeSetChildren().addAll(createChanges);
return createChangeSet;
}
public ChangeSet getDropChangeSet() {
// put the changes into a ChangeSet
ChangeSet createChangeSet = new ChangeSet();
createChangeSet.setType(ChangeSetType.DROP);
createChangeSet.getChangeSetChildren().addAll(dropChanges);
return createChangeSet;
}
public Migration getMigration() {
Migration migration = new Migration();
migration.getChangeSet().add(getApplyChangeSet());
migration.getChangeSet().add(getDropChangeSet());
return migration;
}
/**
* Return the list of 'drop' changes.
*/
@@ -1,12 +1,11 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.type.ScalarType;
/**
@@ -24,12 +23,12 @@ public class ModelBuildContext {
private final DbConstraintNaming constraintNaming;
private final PlatformDdl platformDdl;
private final DbConstraintNaming.MaxLength maxLength;
public ModelBuildContext(ModelContainer model, DbConstraintNaming constraintNaming, PlatformDdl platformDdl) {
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
this.model = model;
this.constraintNaming = constraintNaming;
this.platformDdl = platformDdl;
this.constraintNaming = naming;
this.maxLength = maxLength;
}
public String primaryKeyName(String tableName) {
@@ -65,7 +64,7 @@ public class ModelBuildContext {
}
private String maxLength(String constraintName, int indexCount) {
return platformDdl.maxLength(constraintName, indexCount);
return maxLength.maxLength(constraintName, indexCount);
}
/**
@@ -60,6 +60,12 @@ public class DatabasePlatformFactory {
private DatabasePlatform byDatabaseName(String dbName) {
dbName = dbName.toLowerCase();
if (dbName.equals("h2")) {
return new H2Platform();
}
if (dbName.equals("mysql")) {
return new MySqlPlatform();
}
if (dbName.equals("postgres") || dbName.equals("postgres9")) {
return new PostgresPlatform();
}
@@ -72,6 +78,9 @@ public class DatabasePlatformFactory {
if (dbName.equals("oracle") || dbName.equals("oracle10")) {
return new Oracle10Platform();
}
if (dbName.equals("sqlserver")) {
return new MsSqlServer2005Platform();
}
if (dbName.equals("sqlserver2005")) {
return new MsSqlServer2005Platform();
}
@@ -84,12 +93,6 @@ public class DatabasePlatformFactory {
if (dbName.equals("db2")) {
return new DB2Platform();
}
if (dbName.equals("mysql")) {
return new MySqlPlatform();
}
if (dbName.equals("h2")) {
return new H2Platform();
}
if (dbName.equals("sqlite")) {
return new SQLitePlatform();
}
@@ -1,12 +1,11 @@
package com.avaje.ebean.dbmigration;
import com.avaje.ebean.BaseTestCase;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
public class DbMigrationTest extends BaseTestCase {
@@ -22,7 +21,7 @@ public class DbMigrationTest extends BaseTestCase {
DbMigration migration = new DbMigration();
DbOffline.reset();
migration.writeCurrent();
//migration.writeCurrent();
assertThat(DbOffline.isSet()).isFalse();
@@ -4,7 +4,7 @@ package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.config.DbConstraintNaming;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
@@ -22,9 +22,10 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
ModelContainer model = new ModelContainer();
PlatformDdl platformDdl = defaultServer.getDatabasePlatform().getPlatformDdl();
DbConstraintNaming constraintNaming = defaultServer.getServerConfig().getConstraintNaming();
ModelBuildContext ctx = new ModelBuildContext(model, constraintNaming, platformDdl);
DefaultConstraintMaxLength maxLength = new DefaultConstraintMaxLength(60);
ModelBuildContext ctx = new ModelBuildContext(model, constraintNaming, maxLength);
ModelBuildBeanVisitor addTable = new ModelBuildBeanVisitor(ctx);
+1 -1
View File
@@ -23,7 +23,7 @@ ebean.autofetch.traceUsageCollection=false
ebean.ddl.generate=true
ebean.ddl.run=true
datasource.default=pg
datasource.default=mysql
ebean.persistBatch=NONE
ebean.persistBatchOnCascade=ALL