ENH: Support @Index platforms attribute - platform specific indexes

This is a potential alternative to using extra-dll.xml. Might be
appropriate to use over extra-dll in small simple cases.

We might look to extend this in the future to allow full raw platform specific ddl - the ability to specify the entire create index statement.
This commit is contained in:
rob bygrave
2020-01-15 15:47:14 +13:00
parent 7d98355d39
commit 05be24b8b2
33 changed files with 366 additions and 165 deletions
@@ -41,17 +41,20 @@ public class DbConstraintNormalise {
}
/**
* Normalise the column name by removing any quoted identifier characters.
* Normalise the column name by removing any quoted identifier characters and formula brackets.
*/
public String normaliseColumn(String columnName) {
columnName = trimQuotes(columnName);
columnName = trimBrackets(trimQuotes(columnName));
if (lowerCaseColumns) {
columnName = columnName.toLowerCase();
}
return columnName;
}
private String trimBrackets(String value) {
return value.replace("(","").replace(")","");
}
/**
* Lower case the table name checking for quoted identifiers.
*/
@@ -112,8 +112,8 @@ public class BaseTableDdl implements TableDdl {
handleStrictError(tableName, columnName);
}
before = getScriptsForPlatform(column.getBefore(), platformDdl.getPlatform().getName());
after = getScriptsForPlatform(column.getAfter(), platformDdl.getPlatform().getName());
before = getScriptsForPlatform(column.getBefore());
after = getScriptsForPlatform(column.getAfter());
this.withHistory = withHistory;
}
@@ -136,9 +136,9 @@ public class BaseTableDdl implements TableDdl {
}
before = Collections.singletonList(platformDdl.getUpdateNullWithDefault());
} else {
before = getScriptsForPlatform(alter.getBefore(), platformDdl.getPlatform().getName());
before = getScriptsForPlatform(alter.getBefore());
}
after = getScriptsForPlatform(alter.getAfter(), platformDdl.getPlatform().getName());
after = getScriptsForPlatform(alter.getAfter());
}
void writeBefore(DdlBuffer buffer) throws IOException {
@@ -167,7 +167,8 @@ public class BaseTableDdl implements TableDdl {
}
}
private List<String> getScriptsForPlatform(List<DdlScript> scripts, String searchPlatform) {
private List<String> getScriptsForPlatform(List<DdlScript> scripts) {
String searchPlatform = platformDdl.getPlatform().getName();
List<String> ret = Collections.emptyList();
for (DdlScript script : scripts) {
if (script.getPlatforms() == null || script.getPlatforms().isEmpty()) {
@@ -358,7 +359,6 @@ public class BaseTableDdl implements TableDdl {
* For all other DB platforms these unique constraints are done inline as per normal.
*/
protected void writeUniqueOneToOneConstraints(DdlWrite write, CreateTable createTable) throws IOException {
String tableName = createTable.getName();
for (Column col : externalUnique) {
String uqName = col.getUniqueOneToOne();
@@ -381,7 +381,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeSequence(DdlWrite writer, CreateTable createTable, String pk) throws IOException {
// explicit sequence use or platform decides
String explicitSequenceName = createTable.getSequenceName();
int initial = toInt(createTable.getSequenceInitial());
@@ -400,13 +399,11 @@ public class BaseTableDdl implements TableDdl {
}
protected void createWithHistory(DdlWrite writer, String name) throws IOException {
MTable table = writer.getTable(name);
platformDdl.createWithHistory(writer, table);
}
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
@@ -417,13 +414,11 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
}
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (ForeignKey key : createTable.getForeignKey()) {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
@@ -431,7 +426,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
@@ -443,7 +437,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeAddCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
for (ForeignKey key : createTable.getForeignKey()) {
writeForeignKey(write, new WriteForeignKey(createTable.getName(), key));
}
@@ -454,7 +447,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException {
DdlBuffer fkeyBuffer = write.applyForeignKeys();
String tableName = lowerTableName(request.table());
if (request.indexName() != null) {
@@ -474,7 +466,6 @@ public class BaseTableDdl implements TableDdl {
}
protected void alterTableAddForeignKey(DdlOptions options, DdlBuffer buffer, WriteForeignKey request) throws IOException {
buffer.appendStatement(platformDdl.alterTableAddForeignKey(options, request));
}
@@ -493,7 +484,6 @@ public class BaseTableDdl implements TableDdl {
* Add 'drop table' statement to the buffer.
*/
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
buffer.appendStatement(platformDdl.dropTable(tableName));
}
@@ -501,26 +491,38 @@ public class BaseTableDdl implements TableDdl {
* Add 'drop sequence' statement to the buffer.
*/
protected void dropSequence(DdlBuffer buffer, String sequenceName) throws IOException {
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
}
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
for (UniqueConstraint uniqueConstraint : createTable.getUniqueConstraint()) {
if (inlineUniqueWhenNull) {
String uqName = uniqueConstraint.getName();
String[] columns = split(uniqueConstraint.getColumnNames());
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(columns, apply);
} else {
externalCompoundUnique.add(uniqueConstraint);
if (platformInclude(uniqueConstraint.getPlatforms())) {
if (inlineUniqueWhenNull) {
String uqName = uniqueConstraint.getName();
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(split(uniqueConstraint.getColumnNames()), apply);
} else {
externalCompoundUnique.add(uniqueConstraint);
}
}
}
}
private boolean platformInclude(String platforms) {
if (platforms == null || platforms.isEmpty()) {
return true;
}
String currentPlatform = platformDdl.getPlatform().getPlatform().name();
for (String name : StringHelper.splitNames(platforms)) {
if (currentPlatform.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
/**
* Write the unique constraints inline with the create table statement.
*/
@@ -608,25 +610,30 @@ public class BaseTableDdl implements TableDdl {
@Override
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns())));
writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()));
if (platformInclude(createIndex.getPlatforms())) {
writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns())));
writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()));
}
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
if (platformInclude(dropIndex.getPlatforms())) {
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
}
}
@Override
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
if (platformInclude(constraint.getPlatforms())) {
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
} else {
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
} else {
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
}
}
}
@@ -12,4 +12,13 @@ public class SplitColumns {
return columns.split(",");
}
/**
* Split returning null when columns is null or empty.
*/
public static String[] splitWithNull(String columns) {
if (columns == null || columns.isEmpty()) {
return null;
}
return columns.split(",");
}
}
@@ -21,6 +21,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -41,6 +42,8 @@ public class AddUniqueConstraint {
protected Boolean oneToOne;
@XmlAttribute(name = "nullableColumns")
protected String nullableColumns;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the constraintName property.
@@ -142,4 +145,17 @@ public class AddUniqueConstraint {
this.nullableColumns = value;
}
/**
* Return the platforms.
*/
public String getPlatforms() {
return platforms;
}
/**
* Set the platforms.
*/
public void setPlatforms(String platforms) {
this.platforms = platforms;
}
}
@@ -19,6 +19,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="indexName" 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="columns" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -35,6 +36,8 @@ public class CreateIndex {
protected String tableName;
@XmlAttribute(name = "columns", required = true)
protected String columns;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the indexName property.
@@ -96,4 +99,17 @@ public class CreateIndex {
this.columns = value;
}
/**
* Return the platforms.
*/
public String getPlatforms() {
return platforms;
}
/**
* Set the platforms.
*/
public void setPlatforms(String platforms) {
this.platforms = platforms;
}
}
@@ -18,6 +18,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="indexName" 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="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -32,6 +33,8 @@ public class DropIndex {
protected String indexName;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the indexName property.
@@ -73,4 +76,17 @@ public class DropIndex {
this.tableName = value;
}
/**
* Return the platforms.
*/
public String getPlatforms() {
return platforms;
}
/**
* Set the platforms.
*/
public void setPlatforms(String platforms) {
this.platforms = platforms;
}
}
@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType;
* &lt;attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="oneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="nullableColumns" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
@@ -38,6 +39,8 @@ public class UniqueConstraint {
protected Boolean oneToOne;
@XmlAttribute(name = "nullableColumns")
protected String nullableColumns;
@XmlAttribute(name = "platforms")
protected String platforms;
/**
* Gets the value of the name property.
@@ -119,4 +122,17 @@ public class UniqueConstraint {
this.nullableColumns = value;
}
/**
* Return the platforms.
*/
public String getPlatforms() {
return platforms;
}
/**
* Set the platforms.
*/
public void setPlatforms(String platforms) {
this.platforms = platforms;
}
}
@@ -7,6 +7,9 @@ import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
import java.util.Arrays;
import java.util.Objects;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.splitWithNull;
/**
* A unique constraint for multiple columns.
* <p>
@@ -28,12 +31,41 @@ public class MCompoundUniqueConstraint {
*/
private final String[] columns;
private final String platforms;
private String[] nullableColumns;
public MCompoundUniqueConstraint(String[] columns, Boolean oneToOne, String name) {
/**
* Create for OneToOne.
*/
public MCompoundUniqueConstraint(String[] columns, String name) {
this.name = name;
this.columns = columns;
this.oneToOne = Boolean.TRUE.equals(oneToOne);
this.oneToOne = true;
this.platforms = null;
}
public MCompoundUniqueConstraint(String[] columns, boolean oneToOne, String name, String platforms) {
this.name = name;
this.columns = columns;
this.oneToOne = oneToOne;
this.platforms = platforms;
}
public MCompoundUniqueConstraint(AddUniqueConstraint change) {
this.name = change.getConstraintName();
this.columns = split(change.getColumnNames());
this.oneToOne = change.isOneToOne();
this.platforms = change.getPlatforms();
this.nullableColumns = splitWithNull(change.getNullableColumns());
}
public MCompoundUniqueConstraint(UniqueConstraint uq) {
this.name = uq.getName();
this.columns = split(uq.getColumnNames());
this.oneToOne = uq.isOneToOne();
this.platforms = uq.getPlatforms();
this.nullableColumns = splitWithNull(uq.getNullableColumns());
}
/**
@@ -44,7 +76,7 @@ public class MCompoundUniqueConstraint {
}
/**
* Return true if this unqiue constraint is specifically for OneToOne mapping.
* Return true if this unique constraint is specifically for OneToOne mapping.
*/
public boolean isOneToOne() {
return oneToOne;
@@ -57,12 +89,17 @@ public class MCompoundUniqueConstraint {
return name;
}
public String getPlatforms() {
return platforms;
}
public UniqueConstraint getUniqueConstraint() {
UniqueConstraint uq = new UniqueConstraint();
uq.setName(getName());
uq.setColumnNames(join(columns));
uq.setNullableColumns(join(nullableColumns));
uq.setOneToOne(isOneToOne());
uq.setPlatforms(platforms);
return uq;
}
@@ -76,6 +113,7 @@ public class MCompoundUniqueConstraint {
create.setColumnNames(join(columns));
create.setNullableColumns(join(nullableColumns));
create.setOneToOne(isOneToOne());
create.setPlatforms(platforms);
return create;
}
@@ -83,12 +121,13 @@ public class MCompoundUniqueConstraint {
* Create a AddUniqueConstraint migration with 'DROP CONSTRAINT' set for this index.
*/
public AddUniqueConstraint dropUniqueConstraint(String tableName) {
AddUniqueConstraint dropUniqueConstraint = new AddUniqueConstraint();
dropUniqueConstraint.setConstraintName(name);
dropUniqueConstraint.setTableName(tableName);
dropUniqueConstraint.setColumnNames(DdlHelp.DROP_CONSTRAINT);
dropUniqueConstraint.setNullableColumns(join(nullableColumns));
return dropUniqueConstraint;
AddUniqueConstraint drop = new AddUniqueConstraint();
drop.setConstraintName(name);
drop.setTableName(tableName);
drop.setColumnNames(DdlHelp.DROP_CONSTRAINT);
drop.setNullableColumns(join(nullableColumns));
drop.setPlatforms(platforms);
return drop;
}
public void setNullableColumns(String[] nullableColumns) {
@@ -127,9 +166,10 @@ public class MCompoundUniqueConstraint {
return false;
}
MCompoundUniqueConstraint other = (MCompoundUniqueConstraint) obj;
return Arrays.equals(columns, other.columns)
&& Arrays.equals(nullableColumns, other.nullableColumns)
// not including platforms in equals check
return oneToOne == other.oneToOne
&& Objects.equals(name, other.name)
&& oneToOne == other.oneToOne;
&& Arrays.equals(columns, other.columns)
&& Arrays.equals(nullableColumns, other.nullableColumns);
}
}
@@ -16,6 +16,8 @@ public class MIndex {
private String indexName;
private String platforms;
private List<String> columns = new ArrayList<>();
/**
@@ -27,6 +29,11 @@ public class MIndex {
this.columns.add(columnName);
}
public MIndex(String indexName, String tableName, String[] columnNames, String platforms) {
this(indexName, tableName, columnNames);
this.platforms = platforms;
}
/**
* Create a multi column non unique index.
*/
@@ -40,6 +47,12 @@ public class MIndex {
this.indexName = createIndex.getIndexName();
this.tableName = createIndex.getTableName();
this.columns = split(createIndex.getColumns());
this.platforms = createIndex.getPlatforms();
}
public String getKey() {
// currently indexName should be unique (not indexName + platforms)
return indexName;
}
/**
@@ -71,6 +84,7 @@ public class MIndex {
create.setIndexName(indexName);
create.setTableName(tableName);
create.setColumns(join());
create.setPlatforms(platforms);
return create;
}
@@ -81,6 +95,7 @@ public class MIndex {
DropIndex dropIndex = new DropIndex();
dropIndex.setIndexName(indexName);
dropIndex.setTableName(tableName);
dropIndex.setPlatforms(platforms);
return dropIndex;
}
@@ -88,7 +103,6 @@ public class MIndex {
* Compare with an index of the same name.
*/
public void compare(ModelDiff modelDiff, MIndex newIndex) {
if (changed(newIndex)) {
// drop and recreate the index
modelDiff.addDropIndex(dropIndex());
@@ -27,6 +27,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
/**
* Holds the logical model for a given Table and everything associated to it.
* <p>
@@ -173,11 +175,8 @@ public class MTable {
for (Column column : cols) {
addColumn(column);
}
List<UniqueConstraint> uqConstraints = createTable.getUniqueConstraint();
for (UniqueConstraint uq : uqConstraints) {
MCompoundUniqueConstraint mUq = new MCompoundUniqueConstraint(SplitColumns.split(uq.getColumnNames()), uq.isOneToOne(), uq.getName());
mUq.setNullableColumns(SplitColumns.split(uq.getNullableColumns()));
uniqueConstraints.add(mUq);
for (UniqueConstraint uq : createTable.getUniqueConstraint()) {
uniqueConstraints.add(new MCompoundUniqueConstraint(uq));
}
for (ForeignKey fk : createTable.getForeignKey()) {
@@ -189,11 +188,10 @@ public class MTable {
}
}
public void addForeignKey(String name, String refTableName, String indexName, String columnNames, String refColumnNames) {
MCompoundForeignKey foreignKey = new MCompoundForeignKey(name, refTableName, indexName);
String[] cols = SplitColumns.split(columnNames);
String[] refCols = SplitColumns.split(refColumnNames);
String[] cols = split(columnNames);
String[] refCols = split(refColumnNames);
for (int i = 0; i < cols.length && i < refCols.length; i++) {
foreignKey.addColumnPair(cols[i], refCols[i]);
}
@@ -597,19 +595,8 @@ public class MTable {
/**
* Add a unique constraint.
*/
public void addUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) {
uniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName));
}
/**
* Add a unique constraint.
*/
public void addUniqueConstraint(List<MColumn> columns, boolean oneToOne, String constraintName) {
String[] cols = new String[columns.size()];
for (int i = 0; i < columns.size(); i++) {
cols[i] = columns.get(i).getName();
}
addUniqueConstraint(cols, oneToOne, constraintName);
public void addUniqueConstraint(MCompoundUniqueConstraint uniqueConstraint) {
uniqueConstraints.add(uniqueConstraint);
}
/**
@@ -2,7 +2,6 @@ package io.ebeaninternal.dbmigration.model;
import io.ebean.migration.MigrationVersion;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns;
import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.AddTableComment;
@@ -21,6 +20,7 @@ import io.ebeaninternal.dbmigration.migration.Migration;
import io.ebeaninternal.dbmigration.migration.Sql;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -82,13 +82,6 @@ public class ModelContainer {
return tables;
}
/**
* Return the map of all the non unique non fk indexes.
*/
public Map<String, MIndex> getIndexes() {
return indexes;
}
/**
* Return the table by name.
*/
@@ -97,10 +90,21 @@ public class ModelContainer {
}
/**
* Return the index by name.
* Lookup the matching index during DIFF migration processing.
*/
public MIndex getIndex(String indexName) {
return indexes.get(indexName);
public MIndex getIndex(MIndex newIndex) {
return indexes.get(newIndex.getKey());
}
public Collection<MIndex> allIndexes() {
return indexes.values();
}
/**
* Return true if the index does not exist and should be dropped.
*/
public boolean dropIndex(MIndex existingIndex) {
return !indexes.containsKey(existingIndex.getKey());
}
/**
@@ -201,10 +205,7 @@ public class ModelContainer {
if (DdlHelp.isDropConstraint(change.getColumnNames())) {
table.getUniqueConstraints().removeIf(constraint -> constraint.getName().equals(change.getConstraintName()));
} else {
MCompoundUniqueConstraint constraint = new MCompoundUniqueConstraint(
SplitColumns.split(change.getColumnNames()), change.isOneToOne(), change.getConstraintName());
constraint.setNullableColumns(SplitColumns.split(change.getNullableColumns()));
table.getUniqueConstraints().add(constraint);
table.getUniqueConstraints().add(new MCompoundUniqueConstraint(change));
}
}
@@ -216,8 +217,7 @@ public class ModelContainer {
if (DdlHelp.isDropForeignKey(change.getColumnNames())) {
table.removeForeignKey(change.getName());
} else {
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(),
change.getRefColumnNames());
table.addForeignKey(change.getName(), change.getRefTableName(), change.getIndexName(), change.getColumnNames(), change.getRefColumnNames());
}
}
@@ -259,7 +259,8 @@ public class ModelContainer {
if (indexes.containsKey(indexName)) {
throw new IllegalStateException("Index [" + indexName + "] already exists in model?");
}
indexes.put(createIndex.getIndexName(), new MIndex(createIndex));
MIndex index = new MIndex(createIndex);
indexes.put(index.getKey(), index);
}
/**
@@ -321,7 +322,7 @@ public class ModelContainer {
if (reusedElementCollection != null) {
final MIndex index = reusedElementCollection.setReusedElementCollection();
if (index != null) {
indexes.put(index.getIndexName(), index);
indexes.put(index.getKey(), index);
}
} else {
if (table.isPartitioned()) {
@@ -332,17 +333,10 @@ public class ModelContainer {
}
/**
* Add a single column index.
* Add an index.
*/
public void addIndex(String indexName, String tableName, String columnName) {
indexes.put(indexName, new MIndex(indexName, tableName, columnName));
}
/**
* Add a multi column index.
*/
public void addIndex(String indexName, String tableName, String[] columnNames) {
indexes.put(indexName, new MIndex(indexName, tableName, columnNames));
public void addIndex(MIndex index) {
indexes.put(index.getKey(), index);
}
/**
@@ -140,9 +140,8 @@ public class ModelDiff {
}
}
Map<String, MIndex> newIndexes = newModel.getIndexes();
for (MIndex newIndex : newIndexes.values()) {
MIndex currentIndex = baseModel.getIndex(newIndex.getIndexName());
for (MIndex newIndex : newModel.allIndexes()) {
MIndex currentIndex = baseModel.getIndex(newIndex);
if (currentIndex == null) {
addCreateIndex(newIndex.createIndex());
} else {
@@ -151,8 +150,8 @@ public class ModelDiff {
}
// search for indexes that are no longer used
for (MIndex existingIndex : baseModel.getIndexes().values()) {
if (!newIndexes.containsKey(existingIndex.getIndexName())) {
for (MIndex existingIndex : baseModel.allIndexes()) {
if (newModel.dropIndex(existingIndex)) {
addDropIndex(existingIndex.dropIndex());
}
}
@@ -7,6 +7,7 @@ import io.ebean.config.dbplatform.DbPlatformTypeMapping;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MIndex;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.ModelContainer;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -125,12 +126,8 @@ public class ModelBuildContext {
model.addTableElementCollection(table);
}
public void addIndex(String indexName, String tableName, String columnName) {
model.addIndex(indexName, tableName, columnName);
}
public void addIndex(String indexName, String tableName, String[] columnNames) {
model.addIndex(indexName, tableName, columnNames);
public void addIndex(MIndex index) {
model.addIndex(index);
}
/**
@@ -1,8 +1,11 @@
package io.ebeaninternal.dbmigration.model.build;
import io.ebean.annotation.Platform;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.IndexSet;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MCompoundForeignKey;
import io.ebeaninternal.dbmigration.model.MCompoundUniqueConstraint;
import io.ebeaninternal.dbmigration.model.MIndex;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.visitor.BaseTablePropertyVisitor;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -20,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
/**
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
@@ -42,7 +46,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
private int countUnique;
private int countCheck;
public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table, BeanDescriptor<?> beanDescriptor) {
this.ctx = ctx;
this.table = table;
@@ -54,31 +57,55 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Add unique constraints defined via JPA UniqueConstraint annotations.
*/
private void addIndexes(IndexDefinition[] indexes) {
if (indexes != null) {
for (IndexDefinition index : indexes) {
String[] columns = index.getColumns();
indexSet.add(columns);
if (index.isUnique()) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
uqName = determineUniqueConstraintName(columns);
}
table.addUniqueConstraint(columns, false, uqName);
table.addUniqueConstraint(createMUniqueConstraint(index, columns));
} else {
// 'just' an index (not a unique constraint)
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(columns);
}
ctx.addIndex(idxName, table.getName(), columns);
ctx.addIndex(createMIndex(indexName(index), table.getName(), index));
}
}
}
}
private MCompoundUniqueConstraint createMUniqueConstraint(IndexDefinition index, String[] columns) {
return new MCompoundUniqueConstraint(columns, false, uniqueConstraintName(index), platforms(index.getPlatforms()));
}
private String uniqueConstraintName(IndexDefinition index) {
String uqName = index.getName();
if (uqName == null || uqName.trim().isEmpty()) {
return determineUniqueConstraintName(index.getColumns());
}
return uqName;
}
private String indexName(IndexDefinition index) {
String idxName = index.getName();
if (idxName == null || idxName.trim().isEmpty()) {
idxName = determineIndexName(index.getColumns());
}
return idxName;
}
private MIndex createMIndex(String indexName, String tableName, IndexDefinition index) {
return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms()));
}
private String platforms(Platform[] platforms) {
if (platforms == null || platforms.length == 0) {
return null;
}
StringJoiner joiner = new StringJoiner(",");
for (Platform platform : platforms) {
joiner.add(platform.name());
}
return joiner.toString();
}
@Override
public void visitEnd() {
@@ -105,7 +132,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
addDraftTable();
table.updateCompoundIndices();
}
@@ -146,9 +172,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
if (p instanceof BeanPropertyAssocOne) {
visitOneImported((BeanPropertyAssocOne)p);
visitOneImported((BeanPropertyAssocOne<?>)p);
} else {
visitScalar(p);
}
@@ -222,13 +247,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
// for MsSqlServer we need different DDL to handle NULL values on this constraint
if (modelColumns.size() == 1) {
MColumn col = modelColumns.get(0);
col.setUniqueOneToOne(determineUniqueConstraintName(col.getName()));
indexSetAdd(col.getName());
col.setUniqueOneToOne(determineUniqueConstraintName(col.getName()));
} else {
String[] cols = indexSetAdd(toColumnNames(modelColumns));
String uqName = determineUniqueConstraintName(p.getName());
table.addUniqueConstraint(modelColumns, true, uqName);
indexSetAdd(modelColumns);
table.addUniqueConstraint(new MCompoundUniqueConstraint(cols, uqName));
}
}
}
@@ -313,19 +338,23 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
indexSet.add(column);
}
private void indexSetAdd(List<MColumn> modelColumns) {
private String[] indexSetAdd(String[] cols) {
indexSet.add(cols);
return cols;
}
private String[] toColumnNames(List<MColumn> modelColumns) {
String[] cols = new String[modelColumns.size()];
for (int i = 0; i < modelColumns.size(); i++) {
cols[i] = modelColumns.get(i).getName();
}
indexSet.add(cols);
return cols;
}
/**
* Return the primary key constraint name.
*/
protected String determinePrimaryKeyName() {
return ctx.primaryKeyName(table.getName());
}
@@ -333,12 +362,10 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyConstraintName(String columnName) {
return ctx.foreignKeyConstraintName(table.getName(), columnName, ++countForeignKey);
}
protected String determineForeignKeyIndexName(String column) {
String[] cols = {column};
return determineForeignKeyIndexName(cols);
}
@@ -347,7 +374,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyIndexName(String[] columns) {
return ctx.foreignKeyIndexName(table.getName(), columns, ++countIndex);
}
@@ -355,7 +381,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the index name given a single column foreign key.
*/
protected String determineIndexName(String column) {
return ctx.indexName(table.getName(), column, ++countIndex);
}
@@ -363,7 +388,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the index name given multiple columns.
*/
protected String determineIndexName(String[] columns) {
return ctx.indexName(table.getName(), columns, ++countIndex);
}
@@ -371,7 +395,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the unique constraint name.
*/
protected String determineUniqueConstraintName(String columnName) {
return ctx.uniqueConstraintName(table.getName(), columnName, ++countUnique);
}
@@ -379,7 +402,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the unique constraint name.
*/
protected String determineUniqueConstraintName(String[] columnNames) {
return ctx.uniqueConstraintName(table.getName(), columnNames, ++countUnique);
}
@@ -387,11 +409,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
* Return the constraint name.
*/
protected String determineCheckConstraintName(String columnName) {
return ctx.checkConstraintName(table.getName(), columnName, ++countCheck);
}
private boolean hasValue(String val) {
return val != null && !val.isEmpty();
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.annotation.Platform;
/**
* Holds multiple column unique constraints defined for an entity.
*/
@@ -9,12 +11,18 @@ public class IndexDefinition {
private final String name;
private final Platform[] platforms;
private final boolean unique;
public IndexDefinition(String[] columns, String name, boolean unique) {
/**
* Create from Index annotation.
*/
public IndexDefinition(String[] columns, String name, boolean unique, Platform[] platforms) {
this.columns = columns;
this.unique = unique;
this.name = name;
this.platforms = platforms;
}
/**
@@ -24,6 +32,7 @@ public class IndexDefinition {
this.columns = columns;
this.unique = true;
this.name = null;
this.platforms = null;
}
/**
@@ -47,4 +56,10 @@ public class IndexDefinition {
return columns;
}
/**
* Return the platforms this index applies to.
*/
public Platform[] getPlatforms() {
return platforms;
}
}
@@ -134,7 +134,7 @@ public class AnnotationClass extends AnnotationParser {
}
for (Index index : findAnnotationsRecursive(cls, Index.class)) {
descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(), index.unique()));
descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(), index.unique(), index.platforms()));
}
UniqueConstraint uc = findAnnotationRecursive(cls, UniqueConstraint.class);
@@ -416,7 +416,7 @@ public class AnnotationFields extends AnnotationParser {
if (columnNames.length == 1 && hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique()));
descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique(), index.platforms()));
}
private void readJsonAnnotations(DeployBeanProperty prop) {