#374 - Update ModelDiff and migration generation

This commit is contained in:
Robin Bygrave
2015-08-15 00:06:14 +12:00
parent 215417a43c
commit 0a6941bda5
24 changed files with 811 additions and 95 deletions
@@ -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) {
@@ -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");
}
}
@@ -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 {
@@ -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;
}
}
@@ -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;
}
}
@@ -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";
}
}
@@ -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;
}
}
@@ -12,6 +12,7 @@ public class PostgresDdl extends PlatformDdl {
super(platformTypes, dbIdentity);
this.historyDdl = new PostgresHistoryDdl();
this.dropTableCascade = " cascade";
this.columnSetType = "type ";
}
/**
@@ -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<MColumn> columns = table.getColumns().values();
int i = 0;
for (MColumn column : columns) {
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}column" maxOccurs="unbounded"/>
* &lt;/sequence>
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -42,6 +43,8 @@ public class AddColumn {
protected List<Column> 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;
}
}
@@ -19,9 +19,13 @@ import javax.xml.bind.annotation.XmlType;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="columnName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="currentType" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="defaultValue" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="currentDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="currentNotnull" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;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.
*
@@ -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 }
@@ -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 }
*
@@ -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);
@@ -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();
}
}
}
@@ -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<String, MColumn> columns = new LinkedHashMap<String, MColumn>();
@@ -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<String, MColumn> getColumns() {
return columns;
}
@@ -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.
*/
@@ -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<ChangeSet> changeSets = dbMigration.getChangeSet();
for (ChangeSet changeSet : changeSets) {
handler.generate(write, changeSet);
if (!changeSet.getChangeSetChildren().isEmpty()) {
changeSetCount++;
handler.generate(write, changeSet);
}
}
return changeSetCount > 0;
}
/**
@@ -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<Object> dropChanges = new ArrayList<Object>();
/**
* List of 'drop' type changes. Expected to be placed into a separate DDL script.
*/
private final List<Object> dropHistoryChanges = new ArrayList<Object>();
/**
* 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<Object> 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<Object> 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);
}
}
@@ -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
@@ -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();
+14 -3
View File
@@ -14,7 +14,6 @@
<!--<xsd:element ref="application" minOccurs="0" maxOccurs="unbounded"/>-->
<!--</xsd:sequence>-->
<!--</xsd:complexType>-->
<!--</xsd:element>-->
<!--<xsd:element name="application">-->
<!--<xsd:complexType>-->
@@ -173,13 +172,19 @@
<!-- HISTORY -->
<xsd:element name="createHistoryTable">
<xsd:element name="addHistoryTable">
<xsd:complexType>
<xsd:attribute name="baseTable" type="xsd:string" use="required"/>
<xsd:attribute name="whenCreatedColumn" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="alterHistoryTable">
<xsd:complexType>
<xsd:attribute name="baseTable" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropHistoryTable">
<xsd:complexType>
<xsd:attribute name="baseTable" type="xsd:string" use="required"/>
@@ -194,6 +199,7 @@
<xsd:element ref="column" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="withHistory" type="xsd:boolean"/>
</xsd:complexType>
</xsd:element>
@@ -208,9 +214,13 @@
<xsd:complexType>
<xsd:attribute name="columnName" type="xsd:string" use="required"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="withHistory" type="xsd:boolean"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="currentType" type="xsd:string"/>
<xsd:attribute name="defaultValue" type="xsd:string"/>
<xsd:attribute name="currentDefaultValue" type="xsd:string"/>
<xsd:attribute name="notnull" type="xsd:boolean"/>
<xsd:attribute name="currentNotnull" type="xsd:boolean"/>
<xsd:attribute name="historyExclude" type="xsd:boolean"/>
<xsd:attribute name="checkConstraint" type="xsd:string"/>
<xsd:attribute name="checkConstraintName" type="xsd:string"/>
@@ -319,7 +329,8 @@
<xsd:element ref="dropTable" maxOccurs="unbounded"/>
<xsd:element ref="renameTable" maxOccurs="unbounded"/>
<xsd:element ref="createHistoryTable" maxOccurs="unbounded"/>
<xsd:element ref="addHistoryTable" maxOccurs="unbounded"/>
<xsd:element ref="dropHistoryTable" maxOccurs="unbounded"/>
<xsd:element ref="addColumn" maxOccurs="unbounded"/>
<xsd:element ref="dropColumn" maxOccurs="unbounded"/>
@@ -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);
}
}
@@ -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");
}
}