Polishing.
Removed tests for circular references since they are not supported by Spring Data Relational. Closes #1599 See #756, #1600 Original pull request #1629
This commit is contained in:
@@ -32,6 +32,8 @@ import org.springframework.util.ClassUtils;
|
||||
* instance of a class implementing {@link SqlTypeMapping} interface can be set on the {@link Tables} class
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Evgenii Koba
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
public class DefaultSqlTypeMapping implements SqlTypeMapping {
|
||||
@@ -61,11 +63,11 @@ public class DefaultSqlTypeMapping implements SqlTypeMapping {
|
||||
|
||||
@Override
|
||||
public String getColumnType(RelationalPersistentProperty property) {
|
||||
return typeMap.get(ClassUtils.resolvePrimitiveIfNecessary(property.getActualType()));
|
||||
return getColumnType(property.getActualType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnTypeByClass(Class clazz) {
|
||||
return typeMap.get(clazz);
|
||||
public String getColumnType(Class<?> type) {
|
||||
return typeMap.get(ClassUtils.resolvePrimitiveIfNecessary(type));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import java.util.Objects;
|
||||
* Models a Foreign Key for generating SQL for Schema generation.
|
||||
*
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
* @since 3.3
|
||||
*/
|
||||
record ForeignKey(String name, String tableName, List<String> columnNames, String referencedTableName,
|
||||
List<String> referencedColumnNames) {
|
||||
List<String> referencedColumnNames) {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
@@ -18,9 +18,9 @@ record ForeignKey(String name, String tableName, List<String> columnNames, Strin
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
ForeignKey that = (ForeignKey) o;
|
||||
return Objects.equals(tableName, that.tableName) && Objects.equals(columnNames, that.columnNames) && Objects.equals(
|
||||
referencedTableName, that.referencedTableName) && Objects.equals(referencedColumnNames,
|
||||
that.referencedColumnNames);
|
||||
return Objects.equals(tableName, that.tableName) && Objects.equals(columnNames, that.columnNames)
|
||||
&& Objects.equals(referencedTableName, that.referencedTableName)
|
||||
&& Objects.equals(referencedColumnNames, that.referencedColumnNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -55,6 +55,7 @@ import java.util.Set;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
@@ -90,6 +91,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Mark Paluch
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
*/
|
||||
public class LiquibaseChangeSetWriter {
|
||||
@@ -323,16 +325,18 @@ public class LiquibaseChangeSetWriter {
|
||||
|
||||
private SchemaDiff initial() {
|
||||
|
||||
Tables mappedEntities = Tables.from(mappingContext.getPersistentEntities().stream().filter(schemaFilter),
|
||||
sqlTypeMapping, null, mappingContext);
|
||||
Stream<? extends RelationalPersistentEntity<?>> entities = mappingContext.getPersistentEntities().stream()
|
||||
.filter(schemaFilter);
|
||||
Tables mappedEntities = Tables.from(entities, sqlTypeMapping, null, mappingContext);
|
||||
return SchemaDiff.diff(mappedEntities, Tables.empty(), nameComparator);
|
||||
}
|
||||
|
||||
private SchemaDiff differenceOf(Database database) throws LiquibaseException {
|
||||
|
||||
Tables existingTables = getLiquibaseModel(database);
|
||||
Tables mappedEntities = Tables.from(mappingContext.getPersistentEntities().stream().filter(schemaFilter),
|
||||
sqlTypeMapping, database.getDefaultCatalogName(), mappingContext);
|
||||
Stream<? extends RelationalPersistentEntity<?>> entities = mappingContext.getPersistentEntities().stream()
|
||||
.filter(schemaFilter);
|
||||
Tables mappedEntities = Tables.from(entities, sqlTypeMapping, database.getDefaultCatalogName(), mappingContext);
|
||||
|
||||
return SchemaDiff.diff(mappedEntities, existingTables, nameComparator);
|
||||
}
|
||||
@@ -482,12 +486,15 @@ public class LiquibaseChangeSetWriter {
|
||||
private static List<ForeignKey> extractForeignKeys(liquibase.structure.core.Table table) {
|
||||
|
||||
return table.getOutgoingForeignKeys().stream().map(foreignKey -> {
|
||||
|
||||
String tableName = foreignKey.getForeignKeyTable().getName();
|
||||
List<String> columnNames = foreignKey.getForeignKeyColumns().stream()
|
||||
.map(liquibase.structure.core.Column::getName).toList();
|
||||
|
||||
String referencedTableName = foreignKey.getPrimaryKeyTable().getName();
|
||||
List<String> referencedColumnNames = foreignKey.getPrimaryKeyColumns().stream()
|
||||
.map(liquibase.structure.core.Column::getName).toList();
|
||||
|
||||
return new ForeignKey(foreignKey.getName(), tableName, columnNames, referencedTableName, referencedColumnNames);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
@@ -582,6 +589,7 @@ public class LiquibaseChangeSetWriter {
|
||||
change.setBaseColumnNames(String.join(",", foreignKey.columnNames()));
|
||||
change.setReferencedTableName(foreignKey.referencedTableName());
|
||||
change.setReferencedColumnNames(String.join(",", foreignKey.referencedColumnNames()));
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
@@ -590,6 +598,7 @@ public class LiquibaseChangeSetWriter {
|
||||
DropForeignKeyConstraintChange change = new DropForeignKeyConstraintChange();
|
||||
change.setConstraintName(foreignKey.name());
|
||||
change.setBaseTableName(foreignKey.tableName());
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.function.Predicate;
|
||||
* or delete)
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
*/
|
||||
record SchemaDiff(List<Table> tableAdditions, List<Table> tableDeletions, List<TableDiff> tableDiffs) {
|
||||
@@ -120,6 +121,7 @@ record SchemaDiff(List<Table> tableAdditions, List<Table> tableDeletions, List<T
|
||||
|
||||
private static <T> Collection<T> findDiffs(Map<String, T> baseMapping, Map<String, T> toCompareMapping,
|
||||
Comparator<String> nameComparator) {
|
||||
|
||||
Map<String, T> diff = new TreeMap<>(nameComparator);
|
||||
diff.putAll(toCompareMapping);
|
||||
baseMapping.keySet().forEach(diff::remove);
|
||||
|
||||
@@ -25,6 +25,8 @@ import org.springframework.util.ObjectUtils;
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Mark Paluch
|
||||
* @author Evgenii Koba
|
||||
* @author Jens Schauder
|
||||
* @since 3.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@@ -43,12 +45,14 @@ public interface SqlTypeMapping {
|
||||
/**
|
||||
* Determines a column type for Class.
|
||||
*
|
||||
* @param clazz class for which the type should be determined.
|
||||
* @param type class for which the type should be determined.
|
||||
* @return the SQL type to use, such as {@code VARCHAR} or {@code NUMERIC}. Can be {@literal null} if the strategy
|
||||
* cannot provide a column type.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
@Nullable
|
||||
default String getColumnTypeByClass(Class clazz) {
|
||||
default String getColumnType(Class<?> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* Models a Table for generating SQL for Schema generation.
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
*/
|
||||
record Table(@Nullable String schema, String name, List<Column> columns, List<ForeignKey> foreignKeys) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
* target {@link Tables}.
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
*/
|
||||
record TableDiff(Table table, List<Column> columnsToAdd, List<Column> columnsToDrop, List<ForeignKey> fkToAdd,
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
@@ -34,11 +35,13 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentEnti
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
import org.springframework.data.relational.core.sql.SqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Model class that contains Table/Column information that can be used to generate SQL for Schema generation.
|
||||
*
|
||||
* @author Kurt Niemi
|
||||
* @author Evgenii Koba
|
||||
* @since 3.2
|
||||
*/
|
||||
record Tables(List<Table> tables) {
|
||||
@@ -71,7 +74,7 @@ record Tables(List<Table> tables) {
|
||||
}
|
||||
|
||||
Column column = new Column(property.getColumnName().getReference(), sqlTypeMapping.getColumnType(property),
|
||||
sqlTypeMapping.isNullable(property), identifierColumns.contains(property));
|
||||
sqlTypeMapping.isNullable(property), identifierColumns.contains(property));
|
||||
table.columns().add(column);
|
||||
}
|
||||
return table;
|
||||
@@ -92,34 +95,40 @@ record Tables(List<Table> tables) {
|
||||
private static void applyForeignKeyMetadata(List<Table> tables, List<ForeignKeyMetadata> foreignKeyMetadataList) {
|
||||
|
||||
foreignKeyMetadataList.forEach(foreignKeyMetadata -> {
|
||||
Table table = tables.stream().filter(t -> t.name().equals(foreignKeyMetadata.tableName)).findAny().get();
|
||||
|
||||
Table table = tables.stream().filter(t -> t.name().equals(foreignKeyMetadata.tableName)).findAny().orElseThrow();
|
||||
|
||||
List<Column> parentIdColumns = collectParentIdentityColumns(foreignKeyMetadata, foreignKeyMetadataList, tables);
|
||||
List<String> parentIdColumnNames = parentIdColumns.stream().map(Column::name).toList();
|
||||
|
||||
String foreignKeyName = getForeignKeyName(foreignKeyMetadata.parentTableName, parentIdColumnNames);
|
||||
if(parentIdColumnNames.size() == 1) {
|
||||
addIfAbsent(table.columns(), new Column(foreignKeyMetadata.referencingColumnName(), parentIdColumns.get(0).type(),
|
||||
false, table.getIdColumns().isEmpty()));
|
||||
if(foreignKeyMetadata.keyColumnName() != null) {
|
||||
addIfAbsent(table.columns(), new Column(foreignKeyMetadata.keyColumnName(), foreignKeyMetadata.keyColumnType(),
|
||||
false, true));
|
||||
if (parentIdColumnNames.size() == 1) {
|
||||
|
||||
addIfAbsent(table.columns(), new Column(foreignKeyMetadata.referencingColumnName(),
|
||||
parentIdColumns.get(0).type(), false, table.getIdColumns().isEmpty()));
|
||||
if (foreignKeyMetadata.keyColumnName() != null) {
|
||||
addIfAbsent(table.columns(),
|
||||
new Column(foreignKeyMetadata.keyColumnName(), foreignKeyMetadata.keyColumnType(), false, true));
|
||||
}
|
||||
addIfAbsent(table.foreignKeys(), new ForeignKey(foreignKeyName, foreignKeyMetadata.tableName(),
|
||||
List.of(foreignKeyMetadata.referencingColumnName()), foreignKeyMetadata.parentTableName(), parentIdColumnNames));
|
||||
addIfAbsent(table.foreignKeys(),
|
||||
new ForeignKey(foreignKeyName, foreignKeyMetadata.tableName(),
|
||||
List.of(foreignKeyMetadata.referencingColumnName()), foreignKeyMetadata.parentTableName(),
|
||||
parentIdColumnNames));
|
||||
} else {
|
||||
|
||||
addIfAbsent(table.columns(), parentIdColumns.toArray(new Column[0]));
|
||||
addIfAbsent(table.columns(), new Column(foreignKeyMetadata.keyColumnName(), foreignKeyMetadata.keyColumnType(),
|
||||
false, true));
|
||||
addIfAbsent(table.foreignKeys(), new ForeignKey(foreignKeyName, foreignKeyMetadata.tableName(), parentIdColumnNames,
|
||||
foreignKeyMetadata.parentTableName(), parentIdColumnNames));
|
||||
addIfAbsent(table.columns(),
|
||||
new Column(foreignKeyMetadata.keyColumnName(), foreignKeyMetadata.keyColumnType(), false, true));
|
||||
addIfAbsent(table.foreignKeys(), new ForeignKey(foreignKeyName, foreignKeyMetadata.tableName(),
|
||||
parentIdColumnNames, foreignKeyMetadata.parentTableName(), parentIdColumnNames));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private static <E> void addIfAbsent(List<E> list, E... elements) {
|
||||
for(E element : elements) {
|
||||
private static <E> void addIfAbsent(List<E> list, E... elements) {
|
||||
|
||||
for (E element : elements) {
|
||||
if (!list.contains(element)) {
|
||||
list.add(element);
|
||||
}
|
||||
@@ -137,26 +146,28 @@ record Tables(List<Table> tables) {
|
||||
excludeTables.add(child.tableName());
|
||||
|
||||
Table parentTable = findTableByName(tables, child.parentTableName());
|
||||
ForeignKeyMetadata parentMetadata = findMetadataByTableName(foreignKeyMetadataList, child.parentTableName(), excludeTables);
|
||||
ForeignKeyMetadata parentMetadata = findMetadataByTableName(foreignKeyMetadataList, child.parentTableName(),
|
||||
excludeTables);
|
||||
List<Column> parentIdColumns = parentTable.getIdColumns();
|
||||
|
||||
if (!parentIdColumns.isEmpty()) {
|
||||
return new ArrayList<>(parentIdColumns);
|
||||
} else if(parentMetadata == null) {
|
||||
//mustn't happen, probably wrong entity declaration
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
List<Column> parentParentIdColumns = collectParentIdentityColumns(parentMetadata, foreignKeyMetadataList, tables);
|
||||
if (parentParentIdColumns.size() == 1) {
|
||||
Column parentParentIdColumn = parentParentIdColumns.get(0);
|
||||
Column withChangedName = new Column(parentMetadata.referencingColumnName, parentParentIdColumn.type(), false, true);
|
||||
parentParentIdColumns = new LinkedList<>(List.of(withChangedName));
|
||||
}
|
||||
if (parentMetadata.keyColumnName() != null) {
|
||||
parentParentIdColumns.add(new Column(parentMetadata.keyColumnName(), parentMetadata.keyColumnType(), false, true));
|
||||
}
|
||||
return parentParentIdColumns;
|
||||
}
|
||||
|
||||
Assert.state(parentMetadata != null, "parentMetadata must not be null at this stage");
|
||||
|
||||
List<Column> parentParentIdColumns = collectParentIdentityColumns(parentMetadata, foreignKeyMetadataList, tables);
|
||||
if (parentParentIdColumns.size() == 1) {
|
||||
Column parentParentIdColumn = parentParentIdColumns.get(0);
|
||||
Column withChangedName = new Column(parentMetadata.referencingColumnName, parentParentIdColumn.type(), false,
|
||||
true);
|
||||
parentParentIdColumns = new LinkedList<>(List.of(withChangedName));
|
||||
}
|
||||
if (parentMetadata.keyColumnName() != null) {
|
||||
parentParentIdColumns
|
||||
.add(new Column(parentMetadata.keyColumnName(), parentMetadata.keyColumnType(), false, true));
|
||||
}
|
||||
return parentParentIdColumns;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -167,14 +178,13 @@ record Tables(List<Table> tables) {
|
||||
@Nullable
|
||||
private static ForeignKeyMetadata findMetadataByTableName(List<ForeignKeyMetadata> metadata, String tableName,
|
||||
Set<String> excludeTables) {
|
||||
|
||||
return metadata.stream()
|
||||
.filter(m -> m.tableName().equals(tableName) && !excludeTables.contains(m.parentTableName()))
|
||||
.findAny()
|
||||
.filter(m -> m.tableName().equals(tableName) && !excludeTables.contains(m.parentTableName())).findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static ForeignKeyMetadata createForeignKeyMetadata(
|
||||
RelationalPersistentEntity<?> entity,
|
||||
private static ForeignKeyMetadata createForeignKeyMetadata(RelationalPersistentEntity<?> entity,
|
||||
RelationalPersistentProperty property,
|
||||
MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> context,
|
||||
SqlTypeMapping sqlTypeMapping) {
|
||||
@@ -182,30 +192,26 @@ record Tables(List<Table> tables) {
|
||||
RelationalPersistentEntity childEntity = context.getRequiredPersistentEntity(property.getActualType());
|
||||
|
||||
String referencedKeyColumnType = null;
|
||||
if(property.isAnnotationPresent(MappedCollection.class)) {
|
||||
if (property.isAnnotationPresent(MappedCollection.class)) {
|
||||
if (property.getType() == List.class) {
|
||||
referencedKeyColumnType = sqlTypeMapping.getColumnTypeByClass(Integer.class);
|
||||
referencedKeyColumnType = sqlTypeMapping.getColumnType(Integer.class);
|
||||
} else if (property.getType() == Map.class) {
|
||||
referencedKeyColumnType = sqlTypeMapping.getColumnTypeByClass(property.getComponentType());
|
||||
referencedKeyColumnType = sqlTypeMapping.getColumnType(property.getComponentType());
|
||||
}
|
||||
}
|
||||
|
||||
return new ForeignKeyMetadata(
|
||||
childEntity.getTableName().getReference(),
|
||||
return new ForeignKeyMetadata(childEntity.getTableName().getReference(),
|
||||
property.getReverseColumnName(entity).getReference(),
|
||||
Optional.ofNullable(property.getKeyColumn()).map(SqlIdentifier::getReference).orElse(null),
|
||||
referencedKeyColumnType,
|
||||
entity.getTableName().getReference()
|
||||
);
|
||||
referencedKeyColumnType, entity.getTableName().getReference());
|
||||
}
|
||||
|
||||
//TODO should we place it in BasicRelationalPersistentProperty/BasicRelationalPersistentEntity and generate using NamingStrategy?
|
||||
private static String getForeignKeyName(String referencedTableName, List<String> referencedColumnNames) {
|
||||
return String.format("%s_%s_fk", referencedTableName, String.join("_", referencedColumnNames));
|
||||
}
|
||||
|
||||
private record ForeignKeyMetadata(String tableName, String referencingColumnName, @Nullable String keyColumnName,
|
||||
@Nullable String keyColumnType, String parentTableName) {
|
||||
@Nullable String keyColumnType, String parentTableName) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
* Integration tests for {@link LiquibaseChangeSetWriter}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Evgenii Koba
|
||||
*/
|
||||
class LiquibaseChangeSetWriterIntegrationTests {
|
||||
|
||||
|
||||
@@ -15,15 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core.mapping.schema;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import liquibase.change.Change;
|
||||
import liquibase.change.ColumnConfig;
|
||||
import liquibase.change.core.AddForeignKeyConstraintChange;
|
||||
@@ -31,6 +24,12 @@ import liquibase.change.core.CreateTableChange;
|
||||
import liquibase.changelog.ChangeSet;
|
||||
import liquibase.changelog.DatabaseChangeLog;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.assertj.core.groups.Tuple;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.annotation.Id;
|
||||
@@ -39,12 +38,12 @@ import org.springframework.data.relational.core.mapping.Column;
|
||||
import org.springframework.data.relational.core.mapping.MappedCollection;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.util.Optionals;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LiquibaseChangeSetWriter}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Evgenii Koba
|
||||
*/
|
||||
class LiquibaseChangeSetWriterUnitTests {
|
||||
|
||||
@@ -117,8 +116,8 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
ChangeSet changeSet = writer.createChangeSet(ChangeSetMetadata.create(), new DatabaseChangeLog());
|
||||
|
||||
Optional<Change> tableWithFk = changeSet.getChanges().stream().filter(change -> {
|
||||
return change instanceof CreateTableChange && ((CreateTableChange) change).getTableName()
|
||||
.equals("table_with_fk_field");
|
||||
return change instanceof CreateTableChange
|
||||
&& ((CreateTableChange) change).getTableName().equals("table_with_fk_field");
|
||||
}).findFirst();
|
||||
assertThat(tableWithFk.isPresent()).isEqualTo(true);
|
||||
|
||||
@@ -136,23 +135,19 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
|
||||
ChangeSet changeSet = writer.createChangeSet(ChangeSetMetadata.create(), new DatabaseChangeLog());
|
||||
|
||||
assertCreateTable(changeSet, "no_id_table",
|
||||
Tuple.tuple("field", "VARCHAR(255 BYTE)", null),
|
||||
Tuple.tuple("list_id", "INT", true),
|
||||
Tuple.tuple("list_of_map_of_no_id_tables_key", "INT", true),
|
||||
assertCreateTable(changeSet, "no_id_table", Tuple.tuple("field", "VARCHAR(255 BYTE)", null),
|
||||
Tuple.tuple("list_id", "INT", true), Tuple.tuple("list_of_map_of_no_id_tables_key", "INT", true),
|
||||
Tuple.tuple("map_of_no_id_tables_key", "VARCHAR(255 BYTE)", true));
|
||||
|
||||
assertCreateTable(changeSet, "map_of_no_id_tables",
|
||||
Tuple.tuple("list_id", "INT", true),
|
||||
assertCreateTable(changeSet, "map_of_no_id_tables", Tuple.tuple("list_id", "INT", true),
|
||||
Tuple.tuple("list_of_map_of_no_id_tables_key", "INT", true));
|
||||
|
||||
assertCreateTable(changeSet, "list_of_map_of_no_id_tables", Tuple.tuple("id", "INT", true));
|
||||
|
||||
assertAddForeignKey(changeSet, "no_id_table", "list_id,list_of_map_of_no_id_tables_key",
|
||||
"map_of_no_id_tables", "list_id,list_of_map_of_no_id_tables_key");
|
||||
assertAddForeignKey(changeSet, "no_id_table", "list_id,list_of_map_of_no_id_tables_key", "map_of_no_id_tables",
|
||||
"list_id,list_of_map_of_no_id_tables_key");
|
||||
|
||||
assertAddForeignKey(changeSet, "map_of_no_id_tables", "list_id",
|
||||
"list_of_map_of_no_id_tables", "id");
|
||||
assertAddForeignKey(changeSet, "map_of_no_id_tables", "list_id", "list_of_map_of_no_id_tables", "id");
|
||||
}
|
||||
|
||||
@Test // GH-1599
|
||||
@@ -165,76 +160,25 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
|
||||
ChangeSet changeSet = writer.createChangeSet(ChangeSetMetadata.create(), new DatabaseChangeLog());
|
||||
|
||||
assertCreateTable(changeSet, "other_table",
|
||||
Tuple.tuple("id", "BIGINT", true), Tuple.tuple("one_to_one_level1", "INT", null));
|
||||
assertCreateTable(changeSet, "other_table", Tuple.tuple("id", "BIGINT", true),
|
||||
Tuple.tuple("one_to_one_level1", "INT", null));
|
||||
|
||||
assertCreateTable(changeSet, "one_to_one_level2", Tuple.tuple("one_to_one_level1", "INT", true));
|
||||
|
||||
assertCreateTable(changeSet, "no_id_table", Tuple.tuple("field", "VARCHAR(255 BYTE)", null),
|
||||
Tuple.tuple("one_to_one_level2", "INT", true), Tuple.tuple("additional_one_to_one_level2", "INT", null));
|
||||
|
||||
assertAddForeignKey(changeSet, "other_table", "one_to_one_level1",
|
||||
"one_to_one_level1", "id");
|
||||
assertAddForeignKey(changeSet, "other_table", "one_to_one_level1", "one_to_one_level1", "id");
|
||||
|
||||
assertAddForeignKey(changeSet, "one_to_one_level2", "one_to_one_level1",
|
||||
"one_to_one_level1", "id");
|
||||
assertAddForeignKey(changeSet, "one_to_one_level2", "one_to_one_level1", "one_to_one_level1", "id");
|
||||
|
||||
assertAddForeignKey(changeSet, "no_id_table", "one_to_one_level2",
|
||||
"one_to_one_level2", "one_to_one_level1");
|
||||
assertAddForeignKey(changeSet, "no_id_table", "one_to_one_level2", "one_to_one_level2", "one_to_one_level1");
|
||||
|
||||
assertAddForeignKey(changeSet, "no_id_table", "additional_one_to_one_level2",
|
||||
"one_to_one_level2", "one_to_one_level1");
|
||||
assertAddForeignKey(changeSet, "no_id_table", "additional_one_to_one_level2", "one_to_one_level2",
|
||||
"one_to_one_level1");
|
||||
|
||||
}
|
||||
|
||||
@Test // GH-1599
|
||||
void createForeignKeyForCircularWithId() {
|
||||
RelationalMappingContext context = new RelationalMappingContext() {
|
||||
@Override
|
||||
public Collection<RelationalPersistentEntity<?>> getPersistentEntities() {
|
||||
return List.of(getPersistentEntity(CircularWithId.class), getPersistentEntity(ParentOfCircularWithId.class));
|
||||
}
|
||||
};
|
||||
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
ChangeSet changeSet = writer.createChangeSet(ChangeSetMetadata.create(), new DatabaseChangeLog());
|
||||
|
||||
assertCreateTable(changeSet, "circular_with_id",
|
||||
Tuple.tuple("id", "INT", true),
|
||||
Tuple.tuple("circular_with_id", "INT", null),
|
||||
Tuple.tuple("parent_of_circular_with_id", "INT", null));
|
||||
|
||||
assertAddForeignKey(changeSet, "circular_with_id", "parent_of_circular_with_id",
|
||||
"parent_of_circular_with_id", "id");
|
||||
|
||||
assertAddForeignKey(changeSet, "circular_with_id", "circular_with_id",
|
||||
"circular_with_id", "id");
|
||||
}
|
||||
|
||||
@Test // GH-1599
|
||||
void createForeignKeyForCircularNoId() {
|
||||
RelationalMappingContext context = new RelationalMappingContext() {
|
||||
@Override
|
||||
public Collection<RelationalPersistentEntity<?>> getPersistentEntities() {
|
||||
return List.of(getPersistentEntity(CircularNoId.class), getPersistentEntity(ParentOfCircularNoId.class));
|
||||
}
|
||||
};
|
||||
|
||||
LiquibaseChangeSetWriter writer = new LiquibaseChangeSetWriter(context);
|
||||
|
||||
ChangeSet changeSet = writer.createChangeSet(ChangeSetMetadata.create(), new DatabaseChangeLog());
|
||||
|
||||
assertCreateTable(changeSet, "circular_no_id",
|
||||
Tuple.tuple("circular_no_id", "INT", true),
|
||||
Tuple.tuple("parent_of_circular_no_id", "INT", null));
|
||||
|
||||
assertAddForeignKey(changeSet, "circular_no_id", "parent_of_circular_no_id",
|
||||
"parent_of_circular_no_id", "id");
|
||||
|
||||
assertAddForeignKey(changeSet, "circular_no_id", "circular_no_id",
|
||||
"circular_no_id", "parent_of_circular_no_id");
|
||||
}
|
||||
|
||||
void assertCreateTable(ChangeSet changeSet, String tableName, Tuple... columnTuples) {
|
||||
Optional<Change> createTableOptional = changeSet.getChanges().stream().filter(change -> {
|
||||
@@ -247,8 +191,8 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
.containsExactly(columnTuples);
|
||||
}
|
||||
|
||||
void assertAddForeignKey(ChangeSet changeSet, String baseTableName, String baseColumnNames, String referencedTableName,
|
||||
String referencedColumnNames) {
|
||||
void assertAddForeignKey(ChangeSet changeSet, String baseTableName, String baseColumnNames,
|
||||
String referencedTableName, String referencedColumnNames) {
|
||||
Optional<Change> addFkOptional = changeSet.getChanges().stream().filter(change -> {
|
||||
return change instanceof AddForeignKeyConstraintChange
|
||||
&& ((AddForeignKeyConstraintChange) change).getBaseTableName().equals(baseTableName)
|
||||
@@ -280,22 +224,19 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class Tables {
|
||||
@Id int id;
|
||||
@MappedCollection
|
||||
Set<OtherTable> tables;
|
||||
@MappedCollection Set<OtherTable> tables;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class SetOfTables {
|
||||
@Id int id;
|
||||
@MappedCollection(idColumn = "set_id")
|
||||
Set<Tables> setOfTables;
|
||||
@MappedCollection(idColumn = "set_id") Set<Tables> setOfTables;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class DifferentTables {
|
||||
@Id int id;
|
||||
@MappedCollection(idColumn = "tables_id")
|
||||
Set<TableWithFkField> tables;
|
||||
@MappedCollection(idColumn = "tables_id") Set<TableWithFkField> tables;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
@@ -311,15 +252,13 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class MapOfNoIdTables {
|
||||
@MappedCollection
|
||||
Map<String, NoIdTable> tables;
|
||||
@MappedCollection Map<String, NoIdTable> tables;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class ListOfMapOfNoIdTables {
|
||||
@Id int id;
|
||||
@MappedCollection(idColumn = "list_id")
|
||||
List<MapOfNoIdTables> listOfTables;
|
||||
@MappedCollection(idColumn = "list_id") List<MapOfNoIdTables> listOfTables;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
@@ -332,33 +271,7 @@ class LiquibaseChangeSetWriterUnitTests {
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class OneToOneLevel2 {
|
||||
NoIdTable table1;
|
||||
@Column("additional_one_to_one_level2")
|
||||
NoIdTable table2;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class ParentOfCircularWithId {
|
||||
@Id int id;
|
||||
CircularWithId circularWithId;
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class CircularWithId {
|
||||
@Id int id;
|
||||
CircularWithId circularWithId;
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class ParentOfCircularNoId {
|
||||
@Id int id;
|
||||
CircularNoId CircularNoId;
|
||||
|
||||
}
|
||||
|
||||
@org.springframework.data.relational.core.mapping.Table
|
||||
static class CircularNoId {
|
||||
CircularNoId CircularNoId;
|
||||
@Column("additional_one_to_one_level2") NoIdTable table2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user