package io.ebean.dbmigration.model; import io.ebean.dbmigration.migration.AlterColumn; import io.ebean.dbmigration.migration.Column; /** * A column in the logical model. */ public class MColumn { private final String name; private String type; private String checkConstraint; private String checkConstraintName; private String defaultValue; private String references; private String foreignKeyName; private String foreignKeyIndex; private String comment; private boolean historyExclude; private boolean notnull; private boolean primaryKey; private boolean identity; private String unique; /** * Special unique for OneToOne as we need to handle that different * specifically for MsSqlServer. */ private String uniqueOneToOne; /** * Temporary variable used when building the alter column changes. */ private AlterColumn alterColumn; private boolean draftOnly; public MColumn(Column column) { this.name = column.getName(); this.type = column.getType(); this.checkConstraint = column.getCheckConstraint(); this.checkConstraintName = column.getCheckConstraintName(); this.defaultValue = column.getDefaultValue(); this.comment = column.getComment(); this.references = column.getReferences(); this.foreignKeyName = column.getForeignKeyName(); this.foreignKeyIndex = column.getForeignKeyIndex(); this.notnull = Boolean.TRUE.equals(column.isNotnull()); this.primaryKey = Boolean.TRUE.equals(column.isPrimaryKey()); this.identity = Boolean.TRUE.equals(column.isIdentity()); this.unique = column.getUnique(); this.uniqueOneToOne = column.getUniqueOneToOne(); this.historyExclude = Boolean.TRUE.equals(column.isHistoryExclude()); } public MColumn(String name, String type) { this.name = name; this.type = type; } public MColumn(String name, String type, boolean notnull) { this.name = name; this.type = type; this.notnull = notnull; } /** * Return a copy of this column used for creating the associated draft table. */ public MColumn copyForDraft() { MColumn copy = new MColumn(name, type); copy.draftOnly = draftOnly; copy.checkConstraint = checkConstraint; copy.checkConstraintName = checkConstraintName; copy.defaultValue = defaultValue; copy.references = references; copy.comment = comment; copy.foreignKeyName = foreignKeyName; copy.foreignKeyIndex = foreignKeyIndex; copy.historyExclude = historyExclude; copy.notnull = notnull; copy.primaryKey = primaryKey; copy.identity = identity; copy.unique = unique; copy.uniqueOneToOne = uniqueOneToOne; return copy; } public String getName() { return name; } public String getType() { return type; } public boolean isPrimaryKey() { return primaryKey; } public void setPrimaryKey(boolean primaryKey) { this.primaryKey = primaryKey; } public boolean isIdentity() { return identity; } public void setIdentity(boolean identity) { this.identity = identity; } public String getCheckConstraint() { return checkConstraint; } public void setCheckConstraint(String checkConstraint) { this.checkConstraint = checkConstraint; } public String getCheckConstraintName() { return checkConstraintName; } public void setCheckConstraintName(String checkConstraintName) { this.checkConstraintName = checkConstraintName; } public String getForeignKeyName() { return foreignKeyName; } public void setForeignKeyName(String foreignKeyName) { this.foreignKeyName = foreignKeyName; } public String getForeignKeyIndex() { return foreignKeyIndex; } public void setForeignKeyIndex(String foreignKeyIndex) { this.foreignKeyIndex = foreignKeyIndex; } public String getDefaultValue() { return defaultValue; } public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } public String getReferences() { return references; } public void setReferences(String references) { this.references = references; } public boolean isNotnull() { return notnull; } public void setNotnull(boolean notnull) { this.notnull = notnull; } public boolean isHistoryExclude() { return historyExclude; } public void setHistoryExclude(boolean historyExclude) { this.historyExclude = historyExclude; } public void setUnique(String unique) { this.unique = unique; } public String getUnique() { return unique; } /** * Set unique specifically for OneToOne mapping. * We need special DDL for this case for MsSqlServer. */ public void setUniqueOneToOne(String uniqueOneToOne) { this.uniqueOneToOne = uniqueOneToOne; } /** * Return true if this is unique for a OneToOne. */ public String getUniqueOneToOne() { return uniqueOneToOne; } /** * Return the column comment. */ public String getComment() { return comment; } /** * Set the column comment. */ public void setComment(String comment) { this.comment = comment; } /** * Set the draftOnly status for this column. */ public void setDraftOnly(boolean draftOnly) { this.draftOnly = draftOnly; } /** * Return the draftOnly status for this column. */ public boolean isDraftOnly() { return draftOnly; } /** * Return true if this column should be included in History DB triggers etc. */ public boolean isIncludeInHistory() { return !draftOnly && !historyExclude; } public Column createColumn() { Column c = new Column(); c.setName(name); c.setType(type); if (notnull) c.setNotnull(true); if (primaryKey) c.setPrimaryKey(true); if (identity) c.setIdentity(true); if (historyExclude) c.setHistoryExclude(true); c.setCheckConstraint(checkConstraint); c.setCheckConstraintName(checkConstraintName); c.setReferences(references); c.setForeignKeyName(foreignKeyName); c.setForeignKeyIndex(foreignKeyIndex); c.setDefaultValue(defaultValue); c.setComment(comment); c.setUnique(unique); c.setUniqueOneToOne(uniqueOneToOne); return c; } protected static boolean different(String val1, String val2) { return (val1 == null) ? val2 != null : !val1.equals(val2); } private boolean hasValue(String val) { return val != null && !val.isEmpty(); } private boolean hasValue(Boolean val) { return val != null; } 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; boolean changeBaseAttribute = false; if (historyExclude != newColumn.historyExclude) { getAlterColumn(tableName, tableWithHistory).setHistoryExclude(newColumn.historyExclude); } if (different(type, newColumn.type)) { changeBaseAttribute = true; getAlterColumn(tableName, tableWithHistory).setType(newColumn.type); } if (notnull != newColumn.notnull) { changeBaseAttribute = true; getAlterColumn(tableName, tableWithHistory).setNotnull(newColumn.notnull); } if (different(defaultValue, newColumn.defaultValue)) { AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (newColumn.defaultValue == null) { alter.setDefaultValue("DROP DEFAULT"); } else { alter.setDefaultValue(newColumn.defaultValue); } } if (different(comment, newColumn.comment)) { AlterColumn alter = getAlterColumn(tableName, tableWithHistory); alter.setComment(newColumn.comment); } if (different(checkConstraint, newColumn.checkConstraint)) { AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(checkConstraint) && !hasValue(newColumn.checkConstraint)) { alter.setDropCheckConstraint(checkConstraintName); } if (hasValue(newColumn.checkConstraint)) { alter.setCheckConstraintName(newColumn.checkConstraintName); alter.setCheckConstraint(newColumn.checkConstraint); } } if (different(references, newColumn.references)) { // foreign key change AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(foreignKeyName)) { alter.setDropForeignKey(foreignKeyName); } if (hasValue(foreignKeyIndex)) { alter.setDropForeignKeyIndex(foreignKeyIndex); } if (hasValue(newColumn.references)) { // add new foreign key constraint alter.setReferences(newColumn.references); alter.setForeignKeyName(newColumn.foreignKeyName); alter.setForeignKeyIndex(newColumn.foreignKeyIndex); } } if (different(unique, newColumn.unique)) { AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(unique)) { alter.setDropUnique(unique); } if (hasValue(newColumn.unique)) { alter.setUnique(newColumn.unique); } } if (different(uniqueOneToOne, newColumn.uniqueOneToOne)) { AlterColumn alter = getAlterColumn(tableName, tableWithHistory); if (hasValue(uniqueOneToOne)) { alter.setDropUnique(uniqueOneToOne); } if (hasValue(newColumn.uniqueOneToOne)) { alter.setUniqueOneToOne(newColumn.uniqueOneToOne); } } if (alterColumn != null) { modelDiff.addAlterColumn(alterColumn); if (changeBaseAttribute) { // support reverting these changes alterColumn.setCurrentType(type); 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.isNotnull())) { notnull = alterColumn.isNotnull(); } 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(); } } }