From 0a6941bda53df64a899dc79bd70087ea01567670 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Sat, 15 Aug 2015 00:06:14 +1200 Subject: [PATCH] #374 - Update ModelDiff and migration generation --- .../avaje/ebean/dbmigration/DbMigration.java | 23 ++- .../avaje/ebean/dbmigration/DbOffline.java | 23 +++ .../ddlgeneration/platform/BaseTableDdl.java | 74 ++++++++- .../platform/MsSqlServerDdl.java | 24 +++ .../ddlgeneration/platform/MySqlDdl.java | 34 ++++ .../ddlgeneration/platform/Oracle10Ddl.java | 4 + .../ddlgeneration/platform/PlatformDdl.java | 42 ++++- .../ddlgeneration/platform/PostgresDdl.java | 1 + .../platform/PostgresHistoryDdl.java | 76 +++++---- .../dbmigration/migration/AddColumn.java | 27 ++++ .../dbmigration/migration/AlterColumn.java | 108 +++++++++++++ .../dbmigration/migration/ChangeSet.java | 6 +- .../dbmigration/migration/ObjectFactory.java | 14 +- .../ebean/dbmigration/model/CurrentModel.java | 2 +- .../ebean/dbmigration/model/MColumn.java | 108 +++++++++++-- .../avaje/ebean/dbmigration/model/MTable.java | 52 +++++- .../dbmigration/model/ModelContainer.java | 14 ++ .../dbmigration/model/ModelDdlWriter.java | 14 +- .../ebean/dbmigration/model/ModelDiff.java | 85 +++++++--- .../model/build/ModelBuildBeanVisitor.java | 4 +- .../server/core/DefaultContainer.java | 4 +- src/main/resources/ebean-dbmigration-1.0.xsd | 17 +- .../platform/PlatformDdl_AlterColumnTest.java | 148 ++++++++++++++++++ .../model/ModelContainerApplyTest.java | 2 +- 24 files changed, 811 insertions(+), 95 deletions(-) create mode 100644 src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java index 9d970b3ad..789a8aa56 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java @@ -14,8 +14,10 @@ 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.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.migration.Migration; 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; @@ -83,6 +85,9 @@ public class DbMigration { public void runMigration() throws IOException { + // use this flag to stop other plugins like full DDL generation + DbOffline.setRunningMigration(); + setDefaults(); try { @@ -99,13 +104,20 @@ public class DbMigration { diff.compareTo(current); 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()); + ModelDdlWriter writer = new ModelDdlWriter(databasePlatform, serverConfig); - writer.processMigration(dbMigration); + if (!writer.processMigration(dbMigration, write)) { + logger.info("no changes detected - no migration written"); - File writePath = getWritePath(); - - logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath()); - writer.writeMigration(writePath, nextMajorVersion); + } else { + // there were actually changes to write + File writePath = getWritePath(); + logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath()); + writer.writeMigration(writePath, nextMajorVersion); + } } finally { DbOffline.reset(); @@ -114,7 +126,6 @@ public class DbMigration { protected void setDefaults() { if (server == null) { - String set = DbOffline.getPlatform(); setServer(Ebean.getDefaultServer()); } if (databasePlatform == null) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java b/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java index fe041a8c7..dc2743df3 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java @@ -13,6 +13,8 @@ public class DbOffline { private static final String KEY = "ebean.dboffline"; + private static boolean runningMigration; + public static void setPlatform(DbPlatformName dbPlatform) { System.setProperty(KEY, dbPlatform.name()); } @@ -33,8 +35,29 @@ public class DbOffline { return getPlatform() != null; } + /** + * Return true if the migration is runing. This typically means don't run the + * plugins like full DDL generation. + */ + public static boolean isRunningMigration() { + return runningMigration; + } + + /** + * Called when the migration is running is order to stop other plugins + * like the full DDL generation from executing. + */ + public static void setRunningMigration() { + runningMigration = true; + } + + /** + * Reset the offline platform and runningMigration flag. + */ public static void reset() { + runningMigration = false; System.clearProperty(KEY); logger.info("reset"); } + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java index d54426b3b..a0ed3caed 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -121,6 +121,12 @@ public class BaseTableDdl implements TableDdl { writeUniqueOneToOneConstraints(writer, createTable); + if (isTrue(createTable.isWithHistory())) { + // create history with rollback before the + // associated drop table is written to rollback + createWithHistory(writer, createTable.getName()); + } + // add drop table to the rollback buffer - do this before // we drop the related sequence (if sequences are used) dropTable(writer.rollback(), tableName); @@ -136,10 +142,6 @@ public class BaseTableDdl implements TableDdl { writeAddForeignKeys(writer, createTable); - if (isTrue(createTable.isWithHistory())) { - createWithHistory(writer, createTable.getName()); - } - } /** @@ -503,6 +505,70 @@ public class BaseTableDdl implements TableDdl { alterColumnAddUniqueOneToOneConstraint(writer, alterColumn); } + boolean alterBaseAttributes = false; + if (hasValue(alterColumn.getType())) { + alterColumnType(writer, alterColumn); + alterBaseAttributes = true; + } + if (hasValue(alterColumn.getDefaultValue())) { + alterColumnDefaultValue(writer, alterColumn); + alterBaseAttributes = true; + } + if (alterColumn.isNotnull() != null) { + alterColumnNotnull(writer, alterColumn); + alterBaseAttributes = true; + } + + if (alterBaseAttributes) { + alterColumnBaseAttributes(writer, alterColumn); + } + } + + /** + * This is mysql specific - alter all the base attributes of the column together. + */ + protected void alterColumnBaseAttributes(DdlWrite writer, AlterColumn alter) throws IOException { + + String ddl = platformDdl.alterColumnBaseAttributes(alter); + if (hasValue(ddl)) { + writer.apply().append(ddl).endOfStatement(); + } + } + + protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException { + + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + String defaultValue = alter.getDefaultValue(); + + String ddl = platformDdl.alterColumnDefaultValue(tableName, columnName, defaultValue); + if (hasValue(ddl)) { + writer.apply().append(ddl).endOfStatement(); + } + } + + protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException { + + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + Boolean notnull = alter.isNotnull(); + + String ddl = platformDdl.alterColumnNotnull(tableName, columnName, notnull); + if (hasValue(ddl)) { + writer.apply().append(ddl).endOfStatement(); + } + } + + protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException { + + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + String type = alter.getType(); + + String ddl = platformDdl.alterColumnType(tableName, columnName, type); + if (hasValue(ddl)) { + writer.apply().append(ddl).endOfStatement(); + } } protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) throws IOException { diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java index 8204eb8df..86008d08d 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java @@ -2,6 +2,7 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; import com.avaje.ebean.config.dbplatform.DbIdentity; import com.avaje.ebean.config.dbplatform.DbTypeMap; +import com.avaje.ebean.dbmigration.migration.AlterColumn; /** * MS SQL Server platform specific DDL. @@ -48,4 +49,27 @@ public class MsSqlServerDdl extends PlatformDdl { return sb.toString(); } + public String alterColumnBaseAttributes(AlterColumn alter) { + + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + String type = alter.getType() != null ? alter.getType() : alter.getCurrentType(); + boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull()); + String notnullClause = notnull ? " not null" : ""; + + return "alter table " + tableName + " alter column " + columnName + " " + type + notnullClause; + } + + @Override + public String alterColumnType(String tableName, String columnName, String type) { + + // can't alter itself - done in alterColumnBaseAttributes() + return null; + } + + public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { + + // can't alter itself - done in alterColumnBaseAttributes() + return null; + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java index 73fcbeadb..754770719 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java @@ -2,6 +2,7 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; import com.avaje.ebean.config.dbplatform.DbIdentity; import com.avaje.ebean.config.dbplatform.DbTypeMap; +import com.avaje.ebean.dbmigration.migration.AlterColumn; /** * MySql specific DDL. @@ -10,6 +11,7 @@ public class MySqlDdl extends PlatformDdl { public MySqlDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); + this.alterColumn = "modify"; } /** @@ -28,4 +30,36 @@ public class MySqlDdl extends PlatformDdl { return "alter table " + tableName + " drop foreign key " + fkName; } + @Override + public String alterColumnType(String tableName, String columnName, String type) { + + // can't alter itself - done in alterColumnBaseAttributes() + return null; + } + + public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { + + // can't alter itself - done in alterColumnBaseAttributes() + return null; + } + + public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { + + String suffix = isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + defaultValue; + + // use alter + return "alter table " + tableName + " alter " + columnName + " " + suffix; + } + + public String alterColumnBaseAttributes(AlterColumn alter) { + + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + String type = alter.getType() != null ? alter.getType() : alter.getCurrentType(); + boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull()); + String notnullClause = notnull ? " not null" : ""; + + // use modify + return "alter table " + tableName + " modify " + columnName + " " + type + notnullClause; + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java index 50eff659a..6d19307fb 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java @@ -14,6 +14,10 @@ public class Oracle10Ddl extends PlatformDdl { this.dropSequenceIfExists = "drop sequence "; this.dropTableCascade = " cascade constraints purge"; this.foreignKeyRestrict = ""; + this.alterColumn = "modify"; + this.columnSetNotnull = "not null"; + this.columnSetNull = "null"; + this.columnSetDefault = "default"; } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java index ef3420c4e..ac9caaf54 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -8,7 +8,6 @@ import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter; -import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.VowelRemover; import com.avaje.ebean.dbmigration.migration.AlterColumn; import com.avaje.ebean.dbmigration.migration.IdentityType; import com.avaje.ebean.dbmigration.model.MTable; @@ -52,6 +51,19 @@ public class PlatformDdl { protected String dropIndexIfExists = "drop index if exists "; + + protected String alterColumn = "alter column"; + + protected String columnSetType = ""; + + protected String columnSetDefault = "set default"; + + protected String columnDropDefault = "drop default"; + + protected String columnSetNotnull = "set not null"; + + protected String columnSetNull = "set null"; + /** * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. */ @@ -171,4 +183,32 @@ public class PlatformDdl { public void historyIncludeColumn(DdlWrite writer, AlterColumn alterColumn) { } + + + public String alterColumnType(String tableName, String columnName, String type) { + + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + type; + } + + public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { + + String suffix = notnull ? columnSetNotnull : columnSetNull; + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix; + } + + public boolean isDropDefault(String defaultValue) { + return "DROP DEFAULT".equals(defaultValue); + } + + public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { + + String suffix = isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + defaultValue; + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix; + } + + public String alterColumnBaseAttributes(AlterColumn alter) { + // by default do nothing, only used by mysql as it can only modify the column with the + // full column definition + return null; + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java index bb0d3ffbf..fcf86b808 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java @@ -12,6 +12,7 @@ public class PostgresDdl extends PlatformDdl { super(platformTypes, dbIdentity); this.historyDdl = new PostgresHistoryDdl(); this.dropTableCascade = " cascade"; + this.columnSetType = "type "; } /** diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java index 90b2adb14..ca54f2783 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java @@ -36,93 +36,108 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { @Override public void createWithHistory(DdlWrite writer, MTable table) throws IOException { + + String baseTable = table.getName(); + + // rollback trigger then function + DdlBuffer rollback = writer.rollback(); + rollback.append("drop trigger if exists ").append(triggerName(baseTable)).append(" on ").append(baseTable).append(" cascade").endOfStatement(); + rollback.append("drop function if exists ").append(procedureName(baseTable)).append("()").endOfStatement(); + rollback.end(); + addHistoryTable(writer, table); addStoredFunction(writer, table); addTrigger(writer, table); } + protected String normalise(String tableName) { + return constraintNaming.normaliseTable(tableName); + } + protected String historyTableName(String baseTableName) { - return baseTableName + historySuffix; + return normalise(baseTableName) + historySuffix; } protected String procedureName(String baseTableName) { - return baseTableName + "_history_version"; + return normalise(baseTableName) + "_history_version"; } protected String triggerName(String baseTableName) { - return baseTableName + "_history_upd"; + return normalise(baseTableName) + "_history_upd"; } public void addHistoryTable(DdlWrite writer, MTable table) throws IOException { - String baseTableName = constraintNaming.normaliseTable(table.getName()); + String baseTableName = table.getName(); - DdlBuffer buffer = writer.applyHistory(); + DdlBuffer apply = writer.applyHistory(); - buffer + apply .append("alter table ").append(baseTableName) .append(" add column ").append(sysPeriod).append(" tstzrange not null") - .endOfStatement().end(); + .endOfStatement(); - buffer + apply .append("create table ").append(baseTableName).append(historySuffix) .append(" (like ").append(baseTableName).append(")") - .endOfStatement().end(); + .endOfStatement(); - buffer + apply .append("create view ").append(baseTableName).append(viewSuffix) - .append(" as select * from").append(baseTableName) - .append(" union all select * from").append(baseTableName).append(historySuffix) + .append(" as select * from ").append(baseTableName) + .append(" union all select * from ").append(baseTableName).append(historySuffix) .endOfStatement().end(); + // rollback changes in appropriate order + DdlBuffer rollback = writer.rollback(); + rollback.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement(); + rollback.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriod).endOfStatement(); + rollback.append("drop table ").append(baseTableName).append(historySuffix).endOfStatement().end(); } public void addTrigger(DdlWrite writer, MTable table) throws IOException { - String baseTableName = constraintNaming.normaliseTable(table.getName()); + String baseTableName = table.getName(); String procedureName = procedureName(baseTableName); String triggerName = triggerName(baseTableName); - DdlBuffer buffer = writer.applyHistory(); - buffer + DdlBuffer apply = writer.applyHistory(); + apply .append("create trigger ").append(triggerName).newLine() .append(" before insert or update or delete on ").append(baseTableName).newLine() .append(" for each row execute procedure ").append(procedureName).append("();").newLine().newLine(); - } - public void addStoredFunction(DdlWrite writer, MTable table) throws IOException { - String baseTableName = constraintNaming.normaliseTable(table.getName()); - String procedureName = procedureName(baseTableName); - DdlBuffer buffer = writer.applyHistory(); + String procedureName = procedureName(table.getName()); - buffer + DdlBuffer apply = writer.applyHistory(); + apply .append("create or replace function ").append(procedureName).append("() returns trigger as $$").newLine() .append("begin").newLine(); - buffer + apply .append(" if (TG_OP = 'INSERT') then").newLine() .append(" NEW.").append(sysPeriod).append(" = tstzrange(CURRENT_TIMESTAMP,null);").newLine() .append(" return new;").newLine().newLine(); - buffer + apply .append(" elsif (TG_OP = 'UPDATE') then").newLine(); - appendInsertIntoHistory(buffer, table); - buffer + appendInsertIntoHistory(apply, table); + apply .append(" NEW.").append(sysPeriod).append(" = tstzrange(CURRENT_TIMESTAMP,null);").newLine() .append(" return new;").newLine().newLine(); - buffer + apply .append(" elsif (TG_OP = 'DELETE') then").newLine(); - appendInsertIntoHistory(buffer, table); - buffer + appendInsertIntoHistory(apply, table); + apply .append(" return old;").newLine().newLine(); - buffer + apply .append(" end if;").newLine() .append("end;").newLine() .append("$$ LANGUAGE plpgsql;").newLine(); - buffer.end(); + apply.end(); } protected void appendInsertIntoHistory(DdlBuffer buffer, MTable table) throws IOException { @@ -138,7 +153,6 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { protected void appendColumnNames(DdlBuffer buffer, MTable table, String columnPrefix) throws IOException { - //id, line1, line2, city, country_code, version, when_created, when_updated Collection columns = table.getColumns().values(); int i = 0; for (MColumn column : columns) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/AddColumn.java b/src/main/java/com/avaje/ebean/dbmigration/migration/AddColumn.java index 112f4cc0b..58de889a3 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/AddColumn.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/AddColumn.java @@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlType; * <element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}column" maxOccurs="unbounded"/> * </sequence> * <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * </restriction> * </complexContent> * </complexType> @@ -42,6 +43,8 @@ public class AddColumn { protected List column; @XmlAttribute(name = "tableName", required = true) protected String tableName; + @XmlAttribute(name = "withHistory") + protected Boolean withHistory; /** * Gets the value of the column property. @@ -96,4 +99,28 @@ public class AddColumn { this.tableName = value; } + /** + * Gets the value of the withHistory property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isWithHistory() { + return withHistory; + } + + /** + * Sets the value of the withHistory property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setWithHistory(Boolean value) { + this.withHistory = value; + } + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java index ff67d66dc..90c86842a 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java @@ -19,9 +19,13 @@ import javax.xml.bind.annotation.XmlType; * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <attribute name="columnName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="currentType" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="defaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="currentDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" /> + * <attribute name="currentNotnull" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="checkConstraintName" type="{http://www.w3.org/2001/XMLSchema}string" /> @@ -50,12 +54,20 @@ public class AlterColumn { protected String columnName; @XmlAttribute(name = "tableName", required = true) protected String tableName; + @XmlAttribute(name = "withHistory") + protected Boolean withHistory; @XmlAttribute(name = "type") protected String type; + @XmlAttribute(name = "currentType") + protected String currentType; @XmlAttribute(name = "defaultValue") protected String defaultValue; + @XmlAttribute(name = "currentDefaultValue") + protected String currentDefaultValue; @XmlAttribute(name = "notnull") protected Boolean notnull; + @XmlAttribute(name = "currentNotnull") + protected Boolean currentNotnull; @XmlAttribute(name = "historyExclude") protected Boolean historyExclude; @XmlAttribute(name = "checkConstraint") @@ -129,6 +141,30 @@ public class AlterColumn { this.tableName = value; } + /** + * Gets the value of the withHistory property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isWithHistory() { + return withHistory; + } + + /** + * Sets the value of the withHistory property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setWithHistory(Boolean value) { + this.withHistory = value; + } + /** * Gets the value of the type property. * @@ -153,6 +189,30 @@ public class AlterColumn { this.type = value; } + /** + * Gets the value of the currentType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCurrentType() { + return currentType; + } + + /** + * Sets the value of the currentType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCurrentType(String value) { + this.currentType = value; + } + /** * Gets the value of the defaultValue property. * @@ -177,6 +237,30 @@ public class AlterColumn { this.defaultValue = value; } + /** + * Gets the value of the currentDefaultValue property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCurrentDefaultValue() { + return currentDefaultValue; + } + + /** + * Sets the value of the currentDefaultValue property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCurrentDefaultValue(String value) { + this.currentDefaultValue = value; + } + /** * Gets the value of the notnull property. * @@ -201,6 +285,30 @@ public class AlterColumn { this.notnull = value; } + /** + * Gets the value of the currentNotnull property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isCurrentNotnull() { + return currentNotnull; + } + + /** + * Sets the value of the currentNotnull property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setCurrentNotnull(Boolean value) { + this.currentNotnull = value; + } + /** * Gets the value of the historyExclude property. * diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java b/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java index 16fd6b4aa..801769bb2 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java @@ -50,7 +50,8 @@ public class ChangeSet { @XmlElement(name = "createTable", type = CreateTable.class), @XmlElement(name = "dropTable", type = DropTable.class), @XmlElement(name = "renameTable", type = RenameTable.class), - @XmlElement(name = "createHistoryTable", type = CreateHistoryTable.class), + @XmlElement(name = "addHistoryTable", type = AddHistoryTable.class), + @XmlElement(name = "dropHistoryTable", type = DropHistoryTable.class), @XmlElement(name = "addColumn", type = AddColumn.class), @XmlElement(name = "dropColumn", type = DropColumn.class), @XmlElement(name = "alterColumn", type = AlterColumn.class), @@ -89,7 +90,8 @@ public class ChangeSet { * {@link CreateTable } * {@link DropTable } * {@link RenameTable } - * {@link CreateHistoryTable } + * {@link AddHistoryTable } + * {@link DropHistoryTable } * {@link AddColumn } * {@link DropColumn } * {@link AlterColumn } diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java b/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java index 83a1ae9ef..af430d4fb 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java @@ -158,11 +158,11 @@ public class ObjectFactory { } /** - * Create an instance of {@link CreateHistoryTable } + * Create an instance of {@link AddHistoryTable } * */ - public CreateHistoryTable createCreateHistoryTable() { - return new CreateHistoryTable(); + public AddHistoryTable createAddHistoryTable() { + return new AddHistoryTable(); } /** @@ -173,6 +173,14 @@ public class ObjectFactory { return new RenameColumn(); } + /** + * Create an instance of {@link AlterHistoryTable } + * + */ + public AlterHistoryTable createAlterHistoryTable() { + return new AlterHistoryTable(); + } + /** * Create an instance of {@link Migration } * diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java index 342057bf0..19782bd7c 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java @@ -133,7 +133,7 @@ public class CurrentModel { if (write == null) { ChangeSet createChangeSet = getChangeSet(); - write = new DdlWrite(); + write = new DdlWrite(new MConfiguration(), model); DdlHandler handler = handler(); handler.generate(write, createChangeSet); diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java index 601df6513..a8d1fbca6 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java @@ -9,7 +9,7 @@ import com.avaje.ebean.dbmigration.migration.Column; public class MColumn { private final String name; - private final String type; + private String type; private String checkConstraint; private String checkConstraintName; private String defaultValue; @@ -30,6 +30,11 @@ public class MColumn { */ private String uniqueOneToOne; + /** + * Temporary variable used when building the alter column changes. + */ + private AlterColumn alterColumn; + public MColumn(Column column) { this.name = column.getName(); this.type = column.getType(); @@ -200,40 +205,57 @@ public class MColumn { return val != null && !val.isEmpty(); } - AlterColumn alterColumn; - - private AlterColumn getAlterColumn(String tableName) { + private AlterColumn getAlterColumn(String tableName, boolean tableWithHistory) { if (alterColumn == null) { alterColumn = new AlterColumn(); alterColumn.setColumnName(name); alterColumn.setTableName(tableName); + if (tableWithHistory) { + alterColumn.setWithHistory(Boolean.TRUE); + } } return alterColumn; } + /** + * Compare the column meta data and return true if there is a change that means + * the history table column needs + + */ public void compare(ModelDiff modelDiff, MTable table, MColumn newColumn) { + boolean tableWithHistory = table.isWithHistory(); String tableName = table.getName(); // set to null and check at the end this.alterColumn = null; - if (different(type, newColumn.type)) { - getAlterColumn(tableName).setType(newColumn.type); - } + boolean changeType = false; + boolean changeNotnull = false; + if (historyExclude != newColumn.historyExclude) { - getAlterColumn(tableName).setHistoryExclude(newColumn.historyExclude); + getAlterColumn(tableName, tableWithHistory).setHistoryExclude(newColumn.historyExclude); + } + + if (different(type, newColumn.type)) { + changeType = true; + getAlterColumn(tableName, tableWithHistory).setType(newColumn.type); } if (notnull != newColumn.notnull) { - getAlterColumn(tableName).setNotnull(newColumn.notnull); + changeNotnull = true; + getAlterColumn(tableName, tableWithHistory).setNotnull(newColumn.notnull); } if (different(defaultValue, newColumn.defaultValue)) { - AlterColumn alter = getAlterColumn(tableName); - alter.setDefaultValue(newColumn.defaultValue); + AlterColumn alter = getAlterColumn(tableName, tableWithHistory); + if (newColumn.defaultValue == null) { + alter.setDefaultValue("DROP DEFAULT"); + } else { + alter.setDefaultValue(newColumn.defaultValue); + } } if (different(checkConstraint, newColumn.checkConstraint)) { - AlterColumn alter = getAlterColumn(tableName); + AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(checkConstraint)) { alter.setDropCheckConstraint(checkConstraintName); } @@ -244,7 +266,7 @@ public class MColumn { } if (different(references, newColumn.references)) { // foreign key change - AlterColumn alter = getAlterColumn(tableName); + AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(foreignKeyName)) { alter.setDropForeignKey(foreignKeyName); } @@ -260,7 +282,7 @@ public class MColumn { } if (different(unique, newColumn.unique)) { - AlterColumn alter = getAlterColumn(tableName); + AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(unique)) { alter.setDropUnique(unique); } @@ -269,7 +291,7 @@ public class MColumn { } } if (different(uniqueOneToOne, newColumn.uniqueOneToOne)) { - AlterColumn alter = getAlterColumn(tableName); + AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(uniqueOneToOne)) { alter.setDropUnique(uniqueOneToOne); } @@ -280,6 +302,62 @@ public class MColumn { if (alterColumn != null) { modelDiff.addAlterColumn(alterColumn); + // we need the current type, notnull together for some db's + if (!changeType) { + alterColumn.setCurrentType(type); + } + if (!changeNotnull) { + alterColumn.setCurrentNotnull(notnull); + } } } + + /** + * Apply changes based on the AlterColumn request. + */ + public void apply(AlterColumn alterColumn) { + + if (hasValue(alterColumn.getDropCheckConstraint())) { + checkConstraint = null; + } + if (hasValue(alterColumn.getDropForeignKey())) { + foreignKeyName = null; + } + if (hasValue(alterColumn.getDropForeignKeyIndex())) { + foreignKeyIndex = null; + } + if (hasValue(alterColumn.getDropUnique())) { + unique = null; + uniqueOneToOne = null; + } + + if (hasValue(alterColumn.getType())) { + type = alterColumn.getType(); + } + if (hasValue(alterColumn.getDefaultValue())) { + defaultValue = alterColumn.getDefaultValue(); + } + if (hasValue(alterColumn.getCheckConstraint())) { + checkConstraint = alterColumn.getCheckConstraint(); + } + if (hasValue(alterColumn.getCheckConstraintName())) { + checkConstraintName = alterColumn.getCheckConstraintName(); + } + if (hasValue(alterColumn.getUnique())) { + unique = alterColumn.getUnique(); + } + if (hasValue(alterColumn.getUniqueOneToOne())) { + uniqueOneToOne = alterColumn.getUniqueOneToOne(); + } + if (hasValue(alterColumn.getReferences())) { + references = alterColumn.getReferences(); + } + if (hasValue(alterColumn.getForeignKeyName())) { + foreignKeyName = alterColumn.getForeignKeyName(); + } + if (hasValue(alterColumn.getForeignKeyIndex())) { + foreignKeyIndex = alterColumn.getForeignKeyIndex(); + } + + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java index a96e50d06..3d49c753d 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java @@ -1,9 +1,12 @@ package com.avaje.ebean.dbmigration.model; 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.Column; import com.avaje.ebean.dbmigration.migration.CreateTable; import com.avaje.ebean.dbmigration.migration.DropColumn; +import com.avaje.ebean.dbmigration.migration.DropHistoryTable; import com.avaje.ebean.dbmigration.migration.IdentityType; import java.math.BigInteger; @@ -52,7 +55,7 @@ public class MTable { private int sequenceInitial; private int sequenceAllocate; - private Boolean withHistory; + private boolean withHistory; private Map columns = new LinkedHashMap(); @@ -71,7 +74,7 @@ public class MTable { this.comment = createTable.getComment(); this.tablespace = createTable.getTablespace(); this.indexTablespace = createTable.getIndexTablespace(); - this.withHistory = createTable.isWithHistory(); + this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory()); this.sequenceName = createTable.getSequenceName(); this.sequenceInitial = toInt(createTable.getSequenceInitial()); this.sequenceAllocate = toInt(createTable.getSequenceAllocate()); @@ -97,11 +100,13 @@ public class MTable { createTable.setComment(comment); createTable.setTablespace(tablespace); createTable.setIndexTablespace(indexTablespace); - createTable.setWithHistory(withHistory); createTable.setSequenceName(sequenceName); createTable.setSequenceInitial(toBigInteger(sequenceInitial)); createTable.setSequenceAllocate(toBigInteger(sequenceAllocate)); createTable.setIdentityType(identityType); + if (withHistory) { + createTable.setWithHistory(Boolean.TRUE); + } for (MColumn column : this.columns.values()) { createTable.getColumn().add(column.createColumn()); @@ -116,6 +121,20 @@ public class MTable { public void compare(ModelDiff modelDiff, MTable newTable) { + if (withHistory != newTable.withHistory) { + if (withHistory) { + DropHistoryTable dropHistoryTable = new DropHistoryTable(); + dropHistoryTable.setBaseTable(name); + modelDiff.addDropHistoryTable(dropHistoryTable); + + } else { + AddHistoryTable addHistoryTable = new AddHistoryTable(); + addHistoryTable.setBaseTable(name); + //addHistoryTable.setWhenCreatedColumn(); + modelDiff.addAddHistoryTable(addHistoryTable); + } + } + // TODO: compare indexes? // TODO: compare primary key @@ -129,6 +148,8 @@ public class MTable { if (localColumn == null) { diffNewColumn(newColumn); } else { + // note that if there are alter column changes in here then + // the table withHistory is taken into account localColumn.compare(modelDiff, this, newColumn); mappedColumns.add(newColumn.getName()); } @@ -142,9 +163,13 @@ public class MTable { } if (addColumn != null) { + if (withHistory) { + // These addColumns need to occur on the history + // table as well as the base table + addColumn.setWithHistory(Boolean.TRUE); + } modelDiff.addAddColumn(addColumn); } - } /** @@ -157,6 +182,19 @@ public class MTable { } } + /** + * Apply AddColumn migration. + */ + public void apply(AlterColumn alterColumn) { + checkTableName(alterColumn.getTableName()); + String columnName = alterColumn.getColumnName(); + MColumn existingColumn = columns.get(columnName); + if (existingColumn == null) { + throw new IllegalStateException("Column ["+columnName+"] does not exist for AlterColumn change?"); + } + existingColumn.apply(alterColumn); + } + /** * Apply DropColumn migration. */ @@ -189,10 +227,14 @@ public class MTable { return indexTablespace; } - public Boolean getWithHistory() { + public boolean isWithHistory() { return withHistory; } + public void setWithHistory() { + withHistory = true; + } + public Map getColumns() { return columns; } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java b/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java index c57b4f392..5ce9a7b81 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java @@ -1,6 +1,7 @@ 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.CreateTable; import com.avaje.ebean.dbmigration.migration.DropColumn; @@ -62,6 +63,8 @@ public class ModelContainer { for (Object change : changeSetChildren) { if (change instanceof CreateTable) { applyChange((CreateTable) change); + } else if (change instanceof AlterColumn) { + applyChange((AlterColumn) change); } else if (change instanceof AddColumn) { applyChange((AddColumn) change); } else if (change instanceof DropColumn) { @@ -93,6 +96,17 @@ public class ModelContainer { table.apply(addColumn); } + /** + * Apply a AddColumn change to the model. + */ + protected void applyChange(AlterColumn alterColumn) { + MTable table = tables.get(alterColumn.getTableName()); + if (table == null) { + throw new IllegalStateException("Table [" + alterColumn.getTableName() + "] does not exist in model?"); + } + table.apply(alterColumn); + } + /** * Apply a DropColumn change to the model. */ diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDdlWriter.java b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDdlWriter.java index eb7bc329b..d8da80a8e 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDdlWriter.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDdlWriter.java @@ -27,22 +27,30 @@ public class ModelDdlWriter { private DdlWrite write; + int changeSetCount; + public ModelDdlWriter(DatabasePlatform platform, ServerConfig serverConfig) { this.platform = platform; this.serverConfig = serverConfig; } - public void processMigration(Migration dbMigration) throws IOException { + public boolean processMigration(Migration dbMigration, DdlWrite write) throws IOException { + + this.changeSetCount = 0; this.dbMigration = dbMigration; - this.write = new DdlWrite(); + this.write = write; DdlHandler handler = handler(); List changeSets = dbMigration.getChangeSet(); for (ChangeSet changeSet : changeSets) { - handler.generate(write, changeSet); + if (!changeSet.getChangeSetChildren().isEmpty()) { + changeSetCount++; + handler.generate(write, changeSet); + } } + return changeSetCount > 0; } /** diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java index f950fbe26..b9d928f3b 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java @@ -1,10 +1,12 @@ package com.avaje.ebean.dbmigration.model; 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.DropColumn; +import com.avaje.ebean.dbmigration.migration.DropHistoryTable; import com.avaje.ebean.dbmigration.migration.Migration; import java.util.ArrayList; @@ -31,6 +33,11 @@ public class ModelDiff { */ private final List dropChanges = new ArrayList(); + /** + * List of 'drop' type changes. Expected to be placed into a separate DDL script. + */ + private final List dropHistoryChanges = new ArrayList(); + /** * Construct with a base model. */ @@ -45,6 +52,27 @@ public class ModelDiff { this.baseModel = new ModelContainer(); } + /** + * Return the diff as a migration potentially containing + * an apply changeSet and a drop changeSet. + */ + public Migration getMigration() { + + Migration migration = new Migration(); + ChangeSet applyChangeSet = getApplyChangeSet(); + if (!applyChangeSet.getChangeSetChildren().isEmpty()) { + // add a non empty apply changeSet + migration.getChangeSet().add(applyChangeSet); + } + + ChangeSet dropChangeSet = getDropChangeSet(); + if (!dropChangeSet.getChangeSetChildren().isEmpty()) { + // add a non empty drop changeSet + migration.getChangeSet().add(dropChangeSet); + } + return migration; + } + /** * Return the list of 'create' changes. */ @@ -52,6 +80,16 @@ public class ModelDiff { return createChanges; } + /** + * Return the list of 'drop' changes. + */ + public List getDropChanges() { + return dropChanges; + } + + /** + * Return the 'apply' changeSet. + */ public ChangeSet getApplyChangeSet() { // put the changes into a ChangeSet ChangeSet createChangeSet = new ChangeSet(); @@ -60,6 +98,9 @@ public class ModelDiff { return createChangeSet; } + /** + * Return the 'drop' changeSet. + */ public ChangeSet getDropChangeSet() { // put the changes into a ChangeSet ChangeSet createChangeSet = new ChangeSet(); @@ -68,21 +109,6 @@ public class ModelDiff { 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. - */ - public List getDropChanges() { - return dropChanges; - } - /** * Compare to a 'newer' model and collect the differences. */ @@ -116,18 +142,41 @@ public class ModelDiff { protected void compareTables(MTable currentTable, MTable newTable) { currentTable.compare(this, newTable); - } + /** + * Add the AlterColumn to the 'apply' changes. + */ public void addAlterColumn(AlterColumn alterColumn) { createChanges.add(alterColumn); } + /** + * Add the AlterColumn to the 'apply' changes. + */ + public void addAddColumn(AddColumn addColumn) { + createChanges.add(addColumn); + } + + /** + * Add the DropColumn to the 'drop' changes. + */ public void addDropColumn(DropColumn dropColumn) { dropChanges.add(dropColumn); } - public void addAddColumn(AddColumn addColumn) { - createChanges.add(addColumn); + /** + * Add the AddHistoryTable to apply changes. + */ + public void addAddHistoryTable(AddHistoryTable addHistoryTable) { + createChanges.add(addHistoryTable); } + + /** + * Add the DropHistoryTable to the 'drop history' changes. + */ + public void addDropHistoryTable(DropHistoryTable dropHistoryTable) { + dropHistoryChanges.add(dropHistoryTable); + } + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java index cf407a75f..1dc15ad9f 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java @@ -35,7 +35,9 @@ public class ModelBuildBeanVisitor implements BeanVisitor { } MTable table = new MTable(descriptor.getBaseTable()); - + if (descriptor.isHistorySupport()) { + table.setWithHistory(); + } setIdentity(descriptor, table); // add the table to the model diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java index e6d847c03..99213518b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java @@ -146,7 +146,9 @@ public class DefaultContainer implements SpiContainer { // generate and run DDL if required // if there are any other tasks requiring action in their plugins, do them as well - server.executePlugins(online); + if (!DbOffline.isRunningMigration()) { + server.executePlugins(online); + } // initialise prior to registering with clusterManager server.initialise(); diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd index 318c40635..a785f3239 100644 --- a/src/main/resources/ebean-dbmigration-1.0.xsd +++ b/src/main/resources/ebean-dbmigration-1.0.xsd @@ -14,7 +14,6 @@ - @@ -173,13 +172,19 @@ - + + + + + + + @@ -194,6 +199,7 @@ + @@ -208,9 +214,13 @@ + + + + @@ -319,7 +329,8 @@ - + + diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java new file mode 100644 index 000000000..635f17f5e --- /dev/null +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java @@ -0,0 +1,148 @@ +package com.avaje.ebean.dbmigration.ddlgeneration.platform; + +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.dbmigration.migration.AlterColumn; +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class PlatformDdl_AlterColumnTest { + + PlatformDdl h2Ddl = new H2Platform().getPlatformDdl(); + PlatformDdl pgDdl = new PostgresPlatform().getPlatformDdl(); + PlatformDdl mysqlDdl = new MySqlPlatform().getPlatformDdl(); + PlatformDdl oraDdl = new Oracle10Platform().getPlatformDdl(); + PlatformDdl sqlServerDdl = new MsSqlServer2005Platform().getPlatformDdl(); + + + AlterColumn alterNotNull() { + AlterColumn alterColumn = new AlterColumn(); + alterColumn.setTableName("mytab"); + alterColumn.setColumnName("acol"); + alterColumn.setCurrentType("varchar(5)"); + alterColumn.setNotnull(Boolean.TRUE); + + return alterColumn; + } + + @Test + public void testAlterColumnBaseAttributes() throws Exception { + + AlterColumn alterColumn = alterNotNull(); + assertNull(h2Ddl.alterColumnBaseAttributes(alterColumn)); + assertNull(pgDdl.alterColumnBaseAttributes(alterColumn)); + assertNull(oraDdl.alterColumnBaseAttributes(alterColumn)); + + String sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab modify acol varchar(5) not null", sql); + + sql = sqlServerDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab alter column acol varchar(5) not null", sql); + + alterColumn.setNotnull(Boolean.FALSE); + sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab modify acol varchar(5)", sql); + + alterColumn.setNotnull(null); + alterColumn.setType("varchar(100)"); + + sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab modify acol varchar(100)", sql); + + alterColumn.setCurrentNotnull(Boolean.TRUE); + sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab modify acol varchar(100) not null", sql); + + } + + @Test + public void testAlterColumnType() throws Exception { + + String sql = h2Ddl.alterColumnType("mytab", "acol", "varchar(20)"); + assertEquals("alter table mytab alter column acol varchar(20)", sql); + + sql = pgDdl.alterColumnType("mytab", "acol", "varchar(20)"); + assertEquals("alter table mytab alter column acol type varchar(20)", sql); + + sql = sqlServerDdl.alterColumnType("mytab", "acol", "varchar(20)"); + assertEquals("alter table mytab alter column acol varchar(20)", sql); + + sql = oraDdl.alterColumnType("mytab", "acol", "varchar(20)"); + assertEquals("alter table mytab modify acol varchar(20)", sql); + + sql = mysqlDdl.alterColumnType("mytab", "acol", "varchar(20)"); + assertNull(sql); + } + + @Test + public void testAlterColumnNotnull() throws Exception { + + String sql = h2Ddl.alterColumnNotnull("mytab", "acol", true); + assertEquals("alter table mytab alter column acol set not null", sql); + + sql = pgDdl.alterColumnNotnull("mytab", "acol", true); + assertEquals("alter table mytab alter column acol set not null", sql); + + sql = oraDdl.alterColumnNotnull("mytab", "acol", true); + assertEquals("alter table mytab modify acol not null", sql); + + sql = mysqlDdl.alterColumnNotnull("mytab", "acol", true); + assertNull(sql); + } + + @Test + public void testAlterColumnNull() throws Exception { + + String sql = h2Ddl.alterColumnNotnull("mytab", "acol", false); + assertEquals("alter table mytab alter column acol set null", sql); + + sql = pgDdl.alterColumnNotnull("mytab", "acol", false); + assertEquals("alter table mytab alter column acol set null", sql); + + sql = oraDdl.alterColumnNotnull("mytab", "acol", false); + assertEquals("alter table mytab modify acol null", sql); + + sql = mysqlDdl.alterColumnNotnull("mytab", "acol", false); + assertNull(sql); + } + + @Test + public void testAlterColumnDefaultValue() throws Exception { + + String sql = h2Ddl.alterColumnDefaultValue("mytab", "acol", "'hi'"); + assertEquals("alter table mytab alter column acol set default 'hi'", sql); + + sql = pgDdl.alterColumnDefaultValue("mytab", "acol", "'hi'"); + assertEquals("alter table mytab alter column acol set default 'hi'", sql); + + sql = oraDdl.alterColumnDefaultValue("mytab", "acol", "'hi'"); + assertEquals("alter table mytab modify acol default 'hi'", sql); + + sql = mysqlDdl.alterColumnDefaultValue("mytab", "acol", "'hi'"); + assertEquals("alter table mytab alter acol set default 'hi'", sql); + + } + + @Test + public void testAlterColumnDropDefault() throws Exception { + + String sql = h2Ddl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); + assertEquals("alter table mytab alter column acol drop default", sql); + + sql = pgDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); + assertEquals("alter table mytab alter column acol drop default", sql); + + sql = oraDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); + assertEquals("alter table mytab modify acol drop default", sql); + + sql = mysqlDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); + assertEquals("alter table mytab alter acol drop default", sql); + + } + +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java index c60798008..0e35e847f 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java @@ -35,7 +35,7 @@ public class ModelContainerApplyTest { assertThat(foo.getComment()).isEqualTo("comment"); assertThat(foo.getTablespace()).isEqualTo("fooSpace"); assertThat(foo.getIndexTablespace()).isEqualTo("fooIndexSpace"); - assertThat(foo.getWithHistory()).isEqualTo(true); + assertThat(foo.isWithHistory()).isEqualTo(true); assertThat(foo.getColumns()).containsKeys("col1", "col3", "added_to_foo"); } } \ No newline at end of file