move migration creator to seperate module

This commit is contained in:
wea_ondara
2022-11-23 16:31:25 +01:00
parent 481280ed88
commit 1b8d9f94d8
32 changed files with 27 additions and 0 deletions

27
migration-creator/pom.xml Normal file
View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jef</artifactId>
<groupId>jef</groupId>
<version>0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>migration-creator</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>jef</groupId>
<artifactId>core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,196 @@
package jef.model.migration.creator;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.migration.Migration;
import jef.model.migration.MigrationBuilder;
import jef.model.migration.operation.AddFieldOperation;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddIndexOperation;
import jef.model.migration.operation.AddKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropFieldOperation;
import jef.model.migration.operation.DropTableOperation;
import jef.model.migration.operation.MigrationOperation;
import jef.model.migration.operation.RenameFieldOperation;
import jef.model.migration.operation.RenameTableOperation;
import jef.model.migration.operation.UpdateFieldOperation;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MigrationBuilderGenerator {
private final List<MigrationOperation> opsUp;
private final List<MigrationOperation> opsDown;
private final String name;
private final String packageName;
private final Set<Class<?>> imports = new HashSet<>();
@Getter
private String java = null;
public MigrationBuilderGenerator generate() {
if (java == null) {
java = generateMigrationBuilderJava();
}
return this;
}
private String generateMigrationBuilderJava() {
imports.add(Migration.class);
imports.add(MigrationBuilder.class);
//generate java for migration step and concat
var migrationUp = String.join("\n\n", opsUp.stream().map(this::getMigrationJava).toList());
var migrationDown = String.join("\n\n", opsDown.stream().map(this::getMigrationJava).toList());
//generate migration class file
var normalImports = imports.stream().filter(e -> !e.getName().startsWith("java")).sorted(Comparator.comparing(Class::getName, String.CASE_INSENSITIVE_ORDER)).toList();
var javaImports = imports.stream().filter(e -> e.getName().startsWith("java")).sorted(Comparator.comparing(Class::getName, String.CASE_INSENSITIVE_ORDER)).toList();
var normalImportsString = normalImports.stream().map(e -> "import " + e.getName().replace("$", ".") + ";").collect(Collectors.joining("\n"));
var javaImportsString = javaImports.stream().map(e -> "import " + e.getName().replace("$", ".") + ";").collect(Collectors.joining("\n"));
var java = (packageName != null ? "package " + packageName + ";\n\n" : "")
+ normalImportsString + (normalImportsString.length() > 0 ? "\n\n" : "")
+ javaImportsString + (javaImportsString.length() > 0 ? "\n\n" : "")
+ "public class " + name + " implements Migration {\n"
+ " public void up(MigrationBuilder mb) {\n"
+ " " + migrationUp.replace("\n", "\n ") + "\n"
+ " }\n"
+ "\n"
+ " public void down(MigrationBuilder mb) {\n"
+ " " + migrationDown.replace("\n", "\n ") + "\n"
+ " }\n"
+ "}\n";
return java;
}
//mapper stuff
private final Map<Class<? extends MigrationOperation>, Function<? extends MigrationOperation, String>> OP_TO_STRING_MAPPERS = initMapper();
private final Function<MigrationOperation, String> UNSUPPORTED_MIGRATION_OPERATION_FUNCTION = (MigrationOperation i) -> {
throw new RuntimeException(new UnsupportedOperationException("Unsupported migration operation: " + i.getClass().getSimpleName()));
};
private Map<Class<? extends MigrationOperation>, Function<? extends MigrationOperation, String>> initMapper() {
Map<Class<? extends MigrationOperation>, Function<? extends MigrationOperation, String>> map = new HashMap<>();
map.put(AddFieldOperation.class, (AddFieldOperation op) -> addFieldOp(op));
map.put(AddForeignKeyOperation.class, (AddForeignKeyOperation op) -> addForeignKeyOp(op));
map.put(AddIndexOperation.class, (AddIndexOperation op) -> addIndexOp(op));
map.put(AddKeyOperation.class, (AddKeyOperation op) -> addKeyOp(op));
map.put(AddPrimaryKeyOperation.class, (AddPrimaryKeyOperation op) -> addPrimaryKeyOp(op));
map.put(AddTableOperation.class, (AddTableOperation op) -> addTableOp(op));
map.put(AddUniqueKeyOperation.class, (AddUniqueKeyOperation op) -> addUniqueKeyOp(op));
map.put(DropConstraintOperation.class, (DropConstraintOperation op) -> dropConstraintOp(op));
map.put(DropFieldOperation.class, (DropFieldOperation op) -> dropFieldOp(op));
map.put(DropTableOperation.class, (DropTableOperation op) -> dropTableOp(op));
map.put(RenameFieldOperation.class, (RenameFieldOperation op) -> renameFieldOp(op));
map.put(RenameTableOperation.class, (RenameTableOperation op) -> renameTableOp(op));
map.put(UpdateFieldOperation.class, (UpdateFieldOperation op) -> updateField(op));
return map;
}
private String getMigrationJava(MigrationOperation migrationOperation) {
var mapper = (Function<MigrationOperation, String>) OP_TO_STRING_MAPPERS.getOrDefault(migrationOperation.getClass(), UNSUPPORTED_MIGRATION_OPERATION_FUNCTION);
return mapper.apply(migrationOperation);
}
private String addFieldOp(AddFieldOperation op) {
return "mb.addField(\"" + op.getTable() + "\", \"" + op.getField() + "\")" + addFieldOpOptional(op) + ";";
}
private String addFieldOpOptional(AddFieldOperation op) {
return "\n"
+ " .notNull(" + op.isNotNull() + ")\n"
+ " .sqlType(\"" + op.getSqlType() + "\")";
}
private String addForeignKeyOp(AddForeignKeyOperation op) {
imports.add(List.class);
imports.add(ForeignKeyConstraint.class);
imports.add(ForeignKeyConstraint.Action.class);
return "mb.addForeignKey(\"" + op.getName() + "\",\n"
+ " \"" + op.getTable() + "\",\n"
+ " List.of(" + op.getFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "),\n"
+ " \"" + op.getReferencedTable() + "\",\n"
+ " List.of(" + op.getReferencedFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "),\n"
+ " ForeignKeyConstraint.Action." + op.getOnUpdate().name() + ",\n"
+ " ForeignKeyConstraint.Action." + op.getOnDelete().name() + ");";
}
private String addIndexOp(AddIndexOperation op) {
imports.add(List.class);
return "mb.addIndex(\"" + op.getName() + "\",\n"
+ " \"" + op.getTable() + "\",\n"
+ " List.of(" + op.getFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "));";
}
private String addKeyOp(AddKeyOperation op) {
imports.add(List.class);
return "mb.addKey(\"" + op.getName() + "\",\n"
+ " \"" + op.getTable() + "\",\n"
+ " List.of(" + op.getFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "));";
}
private String addPrimaryKeyOp(AddPrimaryKeyOperation op) {
imports.add(List.class);
return "mb.addPrimaryKey(\"" + op.getName() + "\",\n"
+ " \"" + op.getTable() + "\",\n"
+ " List.of(" + op.getFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "));";
}
private String addTableOp(AddTableOperation op) {
imports.add(List.class);
imports.add(AddFieldOperation.class);
imports.add(AddFieldOperation.Builder.class);
return "mb.addTable(\"" + op.getTable() + "\", List.of(\n"
+ op.getFields().stream()
/**/.map(f -> " new AddFieldOperation.Builder(\"" + op.getTable() + "\", \"" + f.build().getField() + "\")" + addFieldOpOptional(f.build()).replace("\n", "\n "))
/**/.collect(Collectors.joining(",\n")) + "\n"
+ "));";
}
private String addUniqueKeyOp(AddUniqueKeyOperation op) {
imports.add(List.class);
return "mb.addUniqueKey(\"" + op.getName() + "\",\n"
+ " \"" + op.getTable() + "\",\n"
+ " List.of(" + op.getFields().stream().map(e -> "\"" + e + "\"").collect(Collectors.joining(", ")) + "));";
}
private String dropConstraintOp(DropConstraintOperation op) {
return "mb.dropConstraint(\"" + op.getTable() + "\", \"" + op.getName() + "\");";
}
private String dropFieldOp(DropFieldOperation op) {
return "mb.dropField(\"" + op.getTable() + "\", \"" + op.getField() + "\");";
}
private String dropTableOp(DropTableOperation op) {
return "mb.dropTable(\"" + op.getTable() + "\");";
}
private String renameFieldOp(RenameFieldOperation op) {
return "mb.renameField(\"" + op.getTable() + "\", \"" + op.getOldName() + "\", \"" + op.getNewName() + "\");";
}
private String renameTableOp(RenameTableOperation op) {
return "mb.renameTable(\"" + op.getOldName() + "\", \"" + op.getNewName() + "\");";
}
private String updateField(UpdateFieldOperation op) {
return "mb.updateField(\"" + op.getTable() + "\", \"" + op.getField() + "\")\n"
+ (op.getNewName() != null ? " .newName(\"" + op.getNewName() + "\")\n" : "")
+ " .notNull(" + op.isNotNull() + ")\n"
+ " .sqlType(" + op.getSqlType() + ");";
}
}

View File

@@ -0,0 +1,478 @@
package jef.model.migration.creator;
import jef.model.DbField;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.constraints.IndexConstraint;
import jef.model.constraints.KeyConstraint;
import jef.model.constraints.UniqueKeyConstraint;
import jef.model.migration.operation.AddFieldOperation;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddIndexOperation;
import jef.model.migration.operation.AddKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropFieldOperation;
import jef.model.migration.operation.DropTableOperation;
import jef.model.migration.operation.MigrationOperation;
import jef.model.migration.operation.RenameFieldOperation;
import jef.model.migration.operation.RenameTableOperation;
import jef.model.migration.operation.UpdateFieldOperation;
import jef.util.Check;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class MigrationCreator {
public Result createMigration(ModelBuilder from, ModelBuilder to, String name, String packageName, String currentSnapshotJava) {
var result = new Result();
//create pre-migration model snapshot class
result = generatePreMigrationSnapshot(name, packageName, currentSnapshotJava, result);
//create migration
result = generateMigration(from, to, name, packageName, result);
//create current model snapshot class
result = generatePostMigrationSnapshot(to, packageName, result);
return result;
}
private Result generatePreMigrationSnapshot(String name, String packageName, String currentSnapshotJava, Result result) {
String preMigrationSnapshot;
if (currentSnapshotJava == null || currentSnapshotJava.isBlank()) {
preMigrationSnapshot = generateModelBuilderJava(new ModelBuilder(), name, packageName);
} else {
preMigrationSnapshot = currentSnapshotJava.replace("CurrentSnapshot", name + "Snapshot");
}
result.setMigrationSnapshot(preMigrationSnapshot);
return result;
}
private Result generatePostMigrationSnapshot(ModelBuilder to, String packageName, Result result) {
result.setCurrentSnapshot(generateModelBuilderJava(to, "Current", packageName));
return result;
}
private String generateModelBuilderJava(ModelBuilder mb, String name, String packageName) {
return new ModelBuilderGenerator(mb, name, packageName, new SqlTypeMapper()).generate().getJava();//TODO mapper
}
private Result generateMigration(ModelBuilder from, ModelBuilder to, String name, String packageName, Result result) {
//reduce model builders to changes
var mcd = new ModelChangeDetector(from, to).detect();
var fromReduced = mcd.getFrom();
var toReduced = mcd.getTo();
//create migration steps
var migrationUpOps = new ArrayList<MigrationOperation.Builder>();
var migrationDownOps = new ArrayList<MigrationOperation.Builder>();
generateMigrationSteps(fromReduced, toReduced, from, to, migrationUpOps);
generateMigrationSteps(toReduced, fromReduced, to, from, migrationDownOps);
var builtUpOps = migrationUpOps.stream().map(e -> e.build()).toList();
var builtDownOps = migrationDownOps.stream().map(e -> e.build()).toList();
result.setMigration(new MigrationBuilderGenerator(builtUpOps, builtDownOps, name, packageName).generate().getJava());
result.setStepsUp(builtUpOps);
result.setStepsDown(builtDownOps);
return result;
}
private void generateMigrationSteps(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
//key drop
addForeignKeyDropGeneration(fromReduced, toReduced, from, to, steps);
addPrimaryKeyDropGeneration(fromReduced, toReduced, from, to, steps);
addUniqueKeyDropGeneration(fromReduced, toReduced, from, to, steps);
addKeyDropGeneration(fromReduced, toReduced, from, to, steps);
addIndexDropGeneration(fromReduced, toReduced, from, to, steps);
//table
addTableDropGeneration(fromReduced, toReduced, from, to, steps);
addTableRenameGeneration(fromReduced, toReduced, from, to, steps);
addTableAddGeneration(fromReduced, toReduced, from, to, steps);
//fields
addFieldAddRenameUpdateDropGeneration(fromReduced, toReduced, from, to, steps);
//key add
addPrimaryKeyAddGeneration(fromReduced, toReduced, from, to, steps);
addForeignKeyAddGeneration(fromReduced, toReduced, from, to, steps);
addUniqueKeyAddGeneration(fromReduced, toReduced, from, to, steps);
addKeyAddGeneration(fromReduced, toReduced, from, to, steps);
addIndexAddGeneration(fromReduced, toReduced, from, to, steps);
}
private void addTableAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntity(toEntity.getTypeName());
//new entity
if (fromEntity == null) {
steps.add(new AddTableOperation.Builder(
toEntity.getName(),
toEntity.getFields().stream()
.filter(DbField::isDatabaseField)
.map(e -> new AddFieldOperation.Builder(toEntity.getName(), e.getName())
.notNull(e.isNotNull())
.sqlType(getSqlType(e)))
.toList()
));
}
}
}
private String getSqlType(DbField<?> e) {
return Optional.ofNullable(e.getSqlType()).or(() -> new SqlTypeMapper().map(e.getTypeName())).orElse(null);
}
private void addTableRenameGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntity(toEntity.getTypeName());
// entity added
if (fromEntity == null) {
continue;
}
//entity rename
if (!fromEntity.getName().equals(toEntity.getName())) {
steps.add(new RenameTableOperation.Builder(fromEntity.getName(), toEntity.getName()));
}
}
}
private void addTableDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var toEntity = toReduced.getEntity(fromEntity.getTypeName());
if (toEntity == null) {
steps.add(new DropTableOperation.Builder(fromEntity.getName()));
}
}
}
private void addFieldAddRenameUpdateDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
//entity added -> nothing to do here
if (fromEntity == null) {
continue;
}
var remainingFromFields = new ArrayList<>(fromEntity.getFields());
var remainingToFields = new ArrayList<>(toEntity.getFields());
var handledFrom = new ArrayList<DbField<?>>();
var handledTo = new ArrayList<DbField<?>>();
//fields with same name but different type parameters
for (DbField<?> toField : toEntity.getFields()) {
var fromField = fromEntity.getFields().stream().filter(e -> e.getName().equals(toField.getName())).findFirst().orElse(null);
if (fromField != null) {
handledFrom.add(fromField);
handledTo.add(toField);
//this assumes the reduced ModelBuilders exclude exactly matching entities
steps.add(new UpdateFieldOperation.Builder(toField.getEntity().getName(), toField.getName())
.notNull(toField.isNotNull()));
}
}
//fields with different name but same type parameters
remainingFromFields.removeAll(handledFrom);
remainingToFields.removeAll(handledTo);
var map = new ArrayList<FieldCompare>();
for (DbField<?> toField : remainingToFields) {
for (DbField<?> FromField : remainingFromFields) {
map.add(new FieldCompare(FromField, toField));
}
}
map.removeIf(e -> e.getSimilarity() <= 0);
map.sort(Comparator.comparingInt(FieldCompare::getSimilarity).reversed());
for (FieldCompare compare : map) {
var toField = compare.getTo();
var fromField = compare.getFrom();
if (handledFrom.contains(fromField) || handledTo.contains(toField)) {
continue;
}
handledFrom.add(fromField);
handledTo.add(toField);
steps.add(new RenameFieldOperation.Builder(toField.getEntity().getName(), fromField.getName(), toField.getName()));
}
//drop
remainingFromFields.removeAll(handledFrom);
remainingToFields.removeAll(handledTo);
for (DbField<?> fromField : remainingFromFields) {
var toField = remainingToFields.stream().filter(e -> e.getName().equals(fromField.getName())).findFirst().orElse(null);
if (toField == null) {
handledFrom.add(fromField);
steps.add(new DropFieldOperation.Builder(fromField.getEntity().getName(), fromField.getName()));
}
}
//add
remainingFromFields.removeAll(handledFrom);
remainingToFields.removeAll(handledTo);
for (DbField<?> toField : remainingToFields) {
var fromField = remainingFromFields.stream().filter(e -> e.getName().equals(toField.getName())).findFirst().orElse(null);
if (fromField == null) {
handledTo.add(toField);
steps.add(new AddFieldOperation.Builder(toField.getEntity().getName(), toField.getName())
.notNull(toField.isNotNull()));
}
}
}
}
private void addPrimaryKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = toEntity.getFields();
var involvedForeignKeys = originalEntity.getPrimaryKey() != null
&& originalEntity.getPrimaryKey().getFields().stream().anyMatch(involvedFields::contains);
if (involvedForeignKeys) {
steps.add(new AddPrimaryKeyOperation.Builder(
originalEntity.getPrimaryKey().getName(),
originalEntity.getPrimaryKey().getEntity().getName(),
originalEntity.getPrimaryKey().getFields().stream().map(DbField::getName).collect(Collectors.toList())));
}
}
}
private void addForeignKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = toEntity.getFields();
var involvedForeignKeys = originalEntity.getForeignKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || toEntity.getForeignKeys().contains(e))
.toList();
for (ForeignKeyConstraint foreignKey : involvedForeignKeys) {
steps.add(new AddForeignKeyOperation.Builder(
foreignKey.getName(),
foreignKey.getEntity().getName(),
foreignKey.getFields().stream().map(DbField::getName).collect(Collectors.toList()),
foreignKey.getReferencedEntity().getName(),
foreignKey.getReferencedFields().stream().map(DbField::getName).collect(Collectors.toList()),
foreignKey.getOnUpdate(), foreignKey.getOnDelete()));
}
}
}
private void addUniqueKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = toEntity.getFields();
var involvedUniqueKeys = originalEntity.getUniqueKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || toEntity.getUniqueKeys().contains(e))
.toList();
for (UniqueKeyConstraint uniqueKey : involvedUniqueKeys) {
steps.add(new AddUniqueKeyOperation.Builder(
uniqueKey.getName(),
uniqueKey.getEntity().getName(),
uniqueKey.getFields().stream().map(DbField::getName).collect(Collectors.toList())));
}
}
}
private void addKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = toEntity.getFields();
var involvedKeys = originalEntity.getKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || toEntity.getKeys().contains(e))
.toList();
for (KeyConstraint key : involvedKeys) {
steps.add(new AddKeyOperation.Builder(
key.getName(),
key.getEntity().getName(),
key.getFields().stream().map(DbField::getName).collect(Collectors.toList())));
}
}
}
private void addIndexAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = toEntity.getFields();
var involvedIndexes = originalEntity.getIndexes().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || toEntity.getIndexes().contains(e))
.toList();
for (IndexConstraint index : involvedIndexes) {
steps.add(new AddIndexOperation.Builder(
index.getName(),
index.getEntity().getName(),
index.getFields().stream().map(DbField::getName).collect(Collectors.toList())));
}
}
}
private void addPrimaryKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = fromEntity.getFields();
if (originalEntity.getPrimaryKey() == null) {
continue;
}
var isPrimaryKeyInvolved = originalEntity.getPrimaryKey().getFields().stream().anyMatch(involvedFields::contains);
if (isPrimaryKeyInvolved) {
//drop all referencing foreign keys
from.getEntities().stream().flatMap(e -> e.getForeignKeys().stream())
.filter(foreignKey -> foreignKey.getReferencedEntity() == fromEntity
&& foreignKey.getReferencedFields().stream().anyMatch(involvedFields::contains))
.forEach(foreignKey -> steps.add(new DropConstraintOperation.Builder(foreignKey.getName(), fromEntity.getName())));
//drop primary
steps.add(new DropConstraintOperation.Builder(originalEntity.getPrimaryKey().getName(), fromEntity.getName()));
}
}
}
private void addForeignKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = fromEntity.getFields();
var involvedForeignKeys = originalEntity.getForeignKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || fromEntity.getForeignKeys().contains(e))
.toList();
for (ForeignKeyConstraint foreignKey : involvedForeignKeys) {
steps.add(new DropConstraintOperation.Builder(foreignKey.getName(), fromEntity.getName()));
}
}
// for (var fromEntity : from.getEntities()) {
// var toEntity = to.getEntity(fromEntity.getType());
//
// //foreign keys
// for (var foreignKey : fromEntity.getForeignKeys()) {
// if (toEntity == null || toEntity.getForeignKeys().stream().noneMatch(fk -> compareForeignKey(foreignKey, fk))) {
// migrationUpOps.add(new DropConstraintOperation.Builder(foreignKey.getName(), fromEntity.getName()));
// }
// }
// }
}
private void addUniqueKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = fromEntity.getFields();
var involvedForeignKeys = originalEntity.getUniqueKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || fromEntity.getUniqueKeys().contains(e))
.toList();
for (UniqueKeyConstraint uniqueKey : involvedForeignKeys) {
steps.add(new DropConstraintOperation.Builder(uniqueKey.getName(), fromEntity.getName()));
}
}
// for (var fromEntity : from.getEntities()) {
// var toEntity = to.getEntity(fromEntity.getType());
//
// //unique keys
// for (var uniqueKey : fromEntity.getUniqueKeys()) {
// if (toEntity == null || toEntity.getUniqueKeys().stream().noneMatch(uk -> compareConstraint(uniqueKey, uk))) {
// steps.add(new DropConstraintOperation.Builder(uniqueKey.getName(), fromEntity.getName()));
// }
// }
// }
}
private void addKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = fromEntity.getFields();
var involvedForeignKeys = originalEntity.getKeys().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || fromEntity.getKeys().contains(e))
.toList();
for (KeyConstraint key : involvedForeignKeys) {
steps.add(new DropConstraintOperation.Builder(key.getName(), fromEntity.getName()));
}
}
// for (var fromEntity : from.getEntities()) {
// var toEntity = to.getEntity(fromEntity.getType());
//
// //keys
// for (var key : fromEntity.getKeys()) {
// if (toEntity == null || toEntity.getKeys().stream().noneMatch(k -> compareConstraint(key, k))) {
// migrationUpOps.add(new DropConstraintOperation.Builder(key.getName(), fromEntity.getName()));
// }
// }
// }
}
private void addIndexDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) {
for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null
var involvedFields = fromEntity.getFields();
var involvedForeignKeys = originalEntity.getIndexes().stream()
.filter(e -> e.getFields().stream().anyMatch(involvedFields::contains) || fromEntity.getIndexes().contains(e))
.toList();
for (IndexConstraint foreignKey : involvedForeignKeys) {
steps.add(new DropConstraintOperation.Builder(foreignKey.getName(), fromEntity.getName()));
}
}
// for (var fromEntity : from.getEntities()) {
// var toEntity = to.getEntity(fromEntity.getType());
//
// //indexes
// for (var index : fromEntity.getIndexes()) {
// if (toEntity == null || toEntity.getIndexes().stream().noneMatch(i -> compareConstraint(index, i))) {
// steps.add(new DropConstraintOperation.Builder(index.getName(), fromEntity.getName()));
// }
// }
// }
}
@Getter
@Setter(AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public static class Result {
private List<MigrationOperation> stepsUp = new ArrayList<>();
private List<MigrationOperation> stepsDown = new ArrayList<>();
private String migration = "";
private String migrationSnapshot = "";
private String currentSnapshot = "";
}
@Getter
private class FieldCompare {
private final DbField<?> from;
private final DbField<?> to;
private final int similarity;
public FieldCompare(DbField<?> from, DbField<?> to) {
this.from = from;
this.to = to;
this.similarity = compute();
}
private int compute() {
return from.equalsExceptName(to) ? 1 : 0;
}
}
}

View File

@@ -0,0 +1,122 @@
package jef.model.migration.creator;
import jef.model.DbContext;
import jef.model.DbEntity;
import jef.model.DbEntityBuilder;
import jef.model.DbField;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.constraints.IndexConstraint;
import jef.model.constraints.KeyConstraint;
import jef.model.constraints.PrimaryKeyConstraint;
import jef.model.constraints.UniqueKeyConstraint;
import jef.serializable.SerializableObject;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class ModelBuilderGenerator {
private final ModelBuilder mb;
private final String name;
private final String packageName;
private final SqlTypeMapper sqlTypeMapper;
private final Set<Class<?>> imports = new HashSet<>();
@Getter
private String java = null;
public ModelBuilderGenerator generate() {
if (java == null) {
java = generateModelBuilderJava();
}
return this;
}
private String generateModelBuilderJava() {
var indent = " ";
imports.add(DbContext.class);
imports.add(ModelBuilder.class);
imports.add(DbEntityBuilder.class);
var java = ""
+ "public class " + name + "Snapshot extends DbContext {\n"
+ " @Override\n"
+ " public void onModelCreate(ModelBuilder mb) {\n"
+ indent + "DbEntityBuilder entity;\n"
+ indent + "DbEntityBuilder referencedEntity;\n";
for (DbEntity<? extends SerializableObject> entity : mb.getEntities()) {
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .name(\"" + entity.getName() + "\");\n";
for (DbField<?> field : entity.getFields()) {
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .field(\"" + field.getName() + "\", \"" + field.getTypeName() + "\")"
+ "\n" + indent + " .sqlType(" + getSqlType(field) + ")"
+ (field.isNotNull() ? "\n" + indent + " .isNotNull()" : "")
+ "\n" + indent + " .isDatabaseField(" + field.isDatabaseField() + ")"
+ "\n" + indent + " .isModelField(" + field.isModelField() + ");\n";
}
if (entity.getPrimaryKey() != null) {
imports.add(List.class);
imports.add(PrimaryKeyConstraint.class);
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .hasOne(" + entity.getPrimaryKey().getFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", ")) + ")\n"
+ indent + " .isPrimaryKey();\n";
}
java += "\n";
}
for (DbEntity<? extends SerializableObject> entity : mb.getEntities()) {
if (entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty()) {
continue;
}
for (ForeignKeyConstraint foreignKey : entity.getForeignKeys()) {
imports.add(ForeignKeyConstraint.class);
//TODO hasOne/hasMany/withOne/WithMany
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .hasOne(" + foreignKey.getFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", " + indent)) + ")\n"
+ indent + " .withOne(\"" + foreignKey.getReferencedEntity().getTypeName() + "\", " + foreignKey.getReferencedFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", ")) + ")\n"
+ indent + " .onUpdate(ForeignKeyConstraint.Action." + foreignKey.getOnUpdate().name() + ")\n"
+ indent + " .onDelete(ForeignKeyConstraint.Action." + foreignKey.getOnDelete().name() + ");\n";
}
for (UniqueKeyConstraint uniqueKey : entity.getUniqueKeys()) {
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .hasOne(" + uniqueKey.getFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", ")) + ")\n"
+ indent + " .isUnique();\n";
}
for (KeyConstraint key : entity.getKeys()) {
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .hasOne(" + key.getFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", ")) + ")\n"
+ indent + " .isKey();\n";
}
for (IndexConstraint index : entity.getIndexes()) {
java += indent + "mb.entity(\"" + entity.getTypeName() + "\")\n"
+ indent + " .hasOne(" + index.getFields().stream().map(f -> "\"" + f.getName() + "\"").collect(Collectors.joining(", ")) + ")\n"
+ indent + " .isIndex();\n";
}
}
java += " }\n"
+ "}\n";
//imports
var normalImports = imports.stream().filter(e -> !e.getName().startsWith("java")).sorted(Comparator.comparing(Class::getName, String.CASE_INSENSITIVE_ORDER)).toList();
var javaImports = imports.stream().filter(e -> e.getName().startsWith("java")).sorted(Comparator.comparing(Class::getName, String.CASE_INSENSITIVE_ORDER)).toList();
//finalize
java = (packageName != null ? "package " + packageName + ";\n\n" : "")
+ normalImports.stream().map(e -> "import " + e.getName().replace("$", ".") + ";").collect(Collectors.joining("\n")) + "\n\n"
+ javaImports.stream().map(e -> "import " + e.getName().replace("$", ".") + ";").collect(Collectors.joining("\n")) + "\n\n"
+ java;
return java;
}
private String getSqlType(DbField<?> f) {
return Optional.ofNullable(f.getSqlType()).or(() -> sqlTypeMapper.map(f.getTypeName())).map(e -> "\"" + e + "\"").orElse(null);
}
}

View File

@@ -0,0 +1,116 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import jef.util.Check;
import lombok.Getter;
import java.util.Objects;
@Getter
public class ModelChangeDetector {
private final ModelBuilder from;
private final ModelBuilder to;
public ModelChangeDetector(ModelBuilder from, ModelBuilder to) {
this.from = Check.notNull(from, "from").clone();
this.to = Check.notNull(to, "to").clone();
}
public ModelChangeDetector detect() {
extractChanges();
return this;
}
private void extractChanges() {
extractChangesFromTo(from, to);
extractChangesFromTo(to, from);
for (int i = 0; i < to.getEntities().size(); i++) {
var toEntity = to.getEntities().get(i);
var fromEntity = from.getEntities().stream().filter(e -> e.getTypeName().equals(toEntity.getTypeName())).findFirst().orElse(null);
if (fromEntity != null) {
//entity empty
if (toEntity.getName().equals(fromEntity.getName())
&& toEntity.getFields().isEmpty()
&& toEntity.getPrimaryKey() == null
&& toEntity.getForeignKeys().isEmpty()
&& toEntity.getUniqueKeys().isEmpty()
&& toEntity.getKeys().isEmpty()
&& toEntity.getIndexes().isEmpty()
&& fromEntity.getFields().isEmpty()
&& fromEntity.getPrimaryKey() == null
&& fromEntity.getForeignKeys().isEmpty()
&& fromEntity.getUniqueKeys().isEmpty()
&& fromEntity.getKeys().isEmpty()
&& fromEntity.getIndexes().isEmpty()) {
to.dropEntity(toEntity);
from.dropEntity(fromEntity);
i--;
}
}
}
}
private void extractChangesFromTo(ModelBuilder from, ModelBuilder to) {
for (int i = 0; i < to.getEntities().size(); i++) {
var toEntity = to.getEntities().get(i);
var fromEntity = from.getEntities().stream().filter(e -> e.getTypeName().equals(toEntity.getTypeName())).findFirst().orElse(null);
if (fromEntity != null) {
for (int j = 0; j < toEntity.getFields().size(); j++) {
var toField = toEntity.getFields().get(j);
var fromField = fromEntity.getFields().stream().filter(e -> e.equals(toField)).findFirst().orElse(null);
if (fromField != null) {
toEntity.dropField(toField);
fromEntity.dropField(fromField);
j--;
}
}
if (Objects.equals(fromEntity.getPrimaryKey(), toEntity.getPrimaryKey())) {
fromEntity.setPrimaryKey(null);
toEntity.setPrimaryKey(null);
}
for (int j = 0; j < toEntity.getForeignKeys().size(); j++) {
var toFk = toEntity.getForeignKeys().get(j);
var fromFk = fromEntity.getForeignKeys().stream().filter(e -> e.equals(toFk)).findFirst().orElse(null);
if (fromFk != null) {
toEntity.dropForeignKey(toFk);
fromEntity.dropForeignKey(fromFk);
j--;
}
}
for (int j = 0; j < toEntity.getUniqueKeys().size(); j++) {
var toUnique = toEntity.getUniqueKeys().get(j);
var fromUnique = fromEntity.getUniqueKeys().stream().filter(e -> e.equals(toUnique)).findFirst().orElse(null);
if (fromUnique != null) {
toEntity.dropUniqueKey(toUnique);
fromEntity.dropUniqueKey(fromUnique);
j--;
}
}
for (int j = 0; j < toEntity.getKeys().size(); j++) {
var toKey = toEntity.getKeys().get(j);
var fromKey = fromEntity.getKeys().stream().filter(e -> e.equals(toKey)).findFirst().orElse(null);
if (fromKey != null) {
toEntity.dropKey(toKey);
fromEntity.dropKey(fromKey);
j--;
}
}
for (int j = 0; j < toEntity.getIndexes().size(); j++) {
var toIx = toEntity.getIndexes().get(j);
var fromIx = fromEntity.getIndexes().stream().filter(e -> e.equals(toIx)).findFirst().orElse(null);
if (fromIx != null) {
toEntity.dropIndex(toIx);
fromEntity.dropIndex(fromIx);
j--;
}
}
}
}
}
}

View File

@@ -0,0 +1,112 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.constraints.PrimaryKeyConstraint;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropTableOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddEntityTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity("AddedEntity");
ent.field("id", int.class.getName());
ent.field("addedField", int.class.getName());
to.getEntity("AddedEntity").setPrimaryKey(new PrimaryKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id"))));
to.getEntity("AddedEntity").addForeignKey(new ForeignKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("addedField")), to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id")), ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(3, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddTableOperation o
&& o.getTable().equals("AddedEntity")
&& o.getFields().size() == 2
&& o.getFields().stream().filter(f -> f.build().getField().equals("id")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("addedField")).count() == 1)
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("AddedEntity")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("id"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("AddedEntity")
&& o.getReferencedTable().equals("AddedEntity")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("addedField")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("id"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(3, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("AddedEntity")
&& o.getName().equals("FK_AddedEntity_AddedEntity_addedField"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("AddedEntity")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropTableOperation o
&& o.getTable().equals("AddedEntity"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,96 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.migration.operation.AddFieldOperation;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropFieldOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddFieldTest extends MigrationCreatorTestBase{
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.getEntity(TestClass2.class);
ent.getOrCreateField("addedField", int.class.getName());
ent.addForeignKey(new ForeignKeyConstraint(ent, List.of(ent.getField("addedField")), ent, List.of(ent.getField("i")), ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(2, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddFieldOperation o
&& o.getTable().equals("objects1")
&& o.getField().equals("addedField"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("objects1")
&& o.getReferencedTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("addedField")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(2, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("objects1")
&& o.getName().equals("FK_objects1_objects1_addedField"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropFieldOperation o
&& o.getTable().equals("objects1")
&& o.getField().equals("addedField"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,84 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddForeignKeyTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.getEntity(TestClass.class);
ent.addForeignKey(new ForeignKeyConstraint(ent, List.of(ent.getField("i2")), ent, List.of(ent.getField("i")), ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(1, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getReferencedTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i2")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(1, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("FK_TestClass_TestClass_i2"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public int i2 = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,79 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.AddIndexOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddIndexTest extends MigrationCreatorTestBase{
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isIndex(true);
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(1, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddIndexOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("d"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(1, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("I_TestClass_d"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,79 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.AddKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddKeyTest extends MigrationCreatorTestBase{
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isKey(true);
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(1, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("d"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(1, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("K_TestClass_d"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,79 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddUniqueTest extends MigrationCreatorTestBase{
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isUnique(true);
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(1, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddUniqueKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("d"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(1, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("U_TestClass_d"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,62 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.annotations.Index;
import jef.model.annotations.Key;
import jef.model.annotations.Unique;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorEmptyTest extends MigrationCreatorTestBase{
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "EmptyMigration", "test",new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
assertEquals(0, res.getStepsUp().size());
assertEquals(0, res.getStepsDown().size());
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
@Index
public double d;
@Unique
public float f;
@Key
public long l;
}
}

View File

@@ -0,0 +1,131 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropTableOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorInitialMigrationTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = new ModelBuilder(List.of());
var to = ModelBuilder.from(Ctx.class);
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "InitialMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(5, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddTableOperation o
&& o.getTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).build().getField().equals("i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddTableOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 6
&& o.getFields().stream().filter(f -> f.build().getField().equals("d")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("f")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("i")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("l")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("o")).count() == 1
&& o.getFields().stream().filter(f -> f.build().getField().equals("nestedI")).count() == 1)
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getReferencedTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("nestedI")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(5, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("FK_TestClass_objects1_nestedI"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("objects1")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropTableOperation o
&& o.getTable().equals("TestClass"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropTableOperation o
&& o.getTable().equals("objects1"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,130 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.RenameTableOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorRenameEntityTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class);
ent.name("d2");
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(5, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("FK_TestClass_objects1_nestedI"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof RenameTableOperation o
&& o.getOldName().equals("TestClass")
&& o.getNewName().equals("d2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("d2")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("d2")
&& o.getReferencedTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("nestedI")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(5, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("d2")
&& o.getName().equals("FK_d2_objects1_nestedI"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("d2")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof RenameTableOperation o
&& o.getOldName().equals("d2")
&& o.getNewName().equals("TestClass"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getReferencedTable().equals("objects1")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("nestedI")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,209 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.ForeignKey;
import jef.model.annotations.Id;
import jef.model.annotations.Index;
import jef.model.annotations.Key;
import jef.model.annotations.Unique;
import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddIndexOperation;
import jef.model.migration.operation.AddKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.RenameFieldOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorRenameFieldConstraintsTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
to.getEntity(TestClass.class).getField("i").setName("i2");
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(11, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("FK_TestClass_TestClass_iFk"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("U_TestClass_i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("K_TestClass_i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("I_TestClass_i"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof RenameFieldOperation o
&& o.getTable().equals("TestClass")
&& o.getOldName().equals("i")
&& o.getNewName().equals("i2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getReferencedTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("iFk")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddUniqueKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i2"))
.count());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof AddIndexOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i2"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(11, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("FK_TestClass_TestClass_iFk"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("PRIMARY"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("U_TestClass_i2"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("K_TestClass_i2"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof DropConstraintOperation o
&& o.getTable().equals("TestClass")
&& o.getName().equals("I_TestClass_i2"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof RenameFieldOperation o
&& o.getTable().equals("TestClass")
&& o.getOldName().equals("i2")
&& o.getNewName().equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddPrimaryKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddForeignKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getReferencedTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("iFk")
&& o.getReferencedFields().size() == 1
&& o.getReferencedFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddUniqueKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddKeyOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof AddIndexOperation o
&& o.getTable().equals("TestClass")
&& o.getFields().size() == 1
&& o.getFields().get(0).equals("i"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
@Index
@Unique
@Key
public int i = 1;
@ForeignKey(entity = TestClass.class, getterOrField = "i")
public int iFk = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,79 @@
package jef.model.migration.creator;
import jef.DbSet;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz;
import jef.model.annotations.Id;
import jef.model.migration.operation.RenameFieldOperation;
import jef.serializable.SerializableObject;
import lombok.Getter;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorRenameFieldTest extends MigrationCreatorTestBase {
@Test
public void test() {
var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).name("d2");
var mc = new MigrationCreator();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper
try {
validateUp(res);
validateDown(res);
} catch (Throwable t) {
System.out.println(res.getMigration());
throw t;
}
validateMigration(res, from, to);
}
private void validateUp(MigrationCreator.Result res) {
assertEquals(1, res.getStepsUp().size());
assertEquals(1, res.getStepsUp().stream()
.filter(e -> e instanceof RenameFieldOperation o
&& o.getTable().equals("TestClass")
&& o.getOldName().equals("d")
&& o.getNewName().equals("d2"))
.count());
}
private void validateDown(MigrationCreator.Result res) {
assertEquals(1, res.getStepsDown().size());
assertEquals(1, res.getStepsDown().stream()
.filter(e -> e instanceof RenameFieldOperation o
&& o.getTable().equals("TestClass")
&& o.getOldName().equals("d2")
&& o.getNewName().equals("d"))
.count());
}
public static class Ctx extends DbContext {
@Clazz(TestClass2.class)
private DbSet<TestClass2> objects1;
}
@Getter
public static class TestClass2 extends SerializableObject {
@Id
public int i = 1;
@Clazz(TestClass.class)
public List<TestClass> nested;
}
@Getter
public static class TestClass extends SerializableObject {
@Id
public int i = 1;
public Object o = new Object();
public double d;
public float f;
public long l;
}
}

View File

@@ -0,0 +1,147 @@
package jef.model.migration.creator;
import jef.model.DbContext;
import jef.model.ModelBuilder;
import jef.model.ModelBuilderCloneTest;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorTestBase {
private static final File JAVA_FILES_DIR = new File("target/test-generated-migrations/src");//TODO move tot a TESTUTil class or smth
private static final File CLASS_FILES_DIR = new File("target/test-generated-migrations/target");
public void validateMigration(MigrationCreator.Result result, ModelBuilder from, ModelBuilder to) {
validateMigrationJava(result.getMigration());
validatePreMigrationSnapshotJava(result.getMigrationSnapshot(), from);
validatePostMigrationSnapshotJava(result.getCurrentSnapshot(), to);
}
public void validateMigrationJava(String migrationJava) {
try {
var packageName = findPackageName(migrationJava);
var className = findClassName(migrationJava);
compile(packageName, className, migrationJava);
var clazz = loadClass(packageName, className);
//for migration just test if it's compiling
} catch (AssertionError | RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException("Failed to load generated class", t);
}
}
public void validatePreMigrationSnapshotJava(String snapshotJava, ModelBuilder from) {
try {
var packageName = findPackageName(snapshotJava);
var className = findClassName(snapshotJava);
compile(packageName, className, snapshotJava);
var clazz = (Class<? extends DbContext>) loadClass(packageName, className);
var mb = ModelBuilder.from(clazz);
ModelBuilderCloneTest.debugHelper(from, mb);
assertEquals(from, mb);
} catch (AssertionError | RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException("Failed to load generated class", t);
}
}
public void validatePostMigrationSnapshotJava(String snapshotJava, ModelBuilder to) {
try {
var packageName = findPackageName(snapshotJava);
var className = findClassName(snapshotJava);
compile(packageName, className, snapshotJava);
var clazz = (Class<? extends DbContext>) loadClass(packageName, className);
var mb = ModelBuilder.from(clazz);
assertEquals(to, mb);
} catch (AssertionError | RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException("Failed to load generated class", t);
}
}
private File compile(String packageName, String className, String java) {
try {//src
File srcdir = new File(getSourcesFilesDir(), packageName.replace(".", File.separator));
srcdir.mkdirs();
File srcf = new File(srcdir, className + ".java");
Files.writeString(srcf.toPath(), java, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
//dest
File destdir = getClassFilesDir();
var javaHome = System.getProperty("java.home");
var isWindows = System.getProperty("os.name").toLowerCase(Locale.ROOT).equals("win");
var javac = new File(javaHome, "bin/javac" + (isWindows ? ".exe" : ""));
var process = new ProcessBuilder()
.command(javac.getAbsolutePath(),
"-cp", "target/classes" + File.pathSeparator + "target/test-classes",
"-encoding", "UTF8",
"-g", //debug symbols
"-d", destdir.getPath(), //target
srcf.getPath()
)
.inheritIO()
.start();
process.waitFor(10, TimeUnit.SECONDS);
var exitCode = process.exitValue();
assertEquals(0, exitCode, "Compilation failed");
return new File(new File(destdir, packageName.replace(".", File.separator)), srcf.getName().replace(".java", ".class"));
} catch (AssertionError | RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException("Error while compiling generated class", t);
}
}
private Class<?> loadClass(String packageName, String className) {
try {
var cl = new URLClassLoader(new URL[]{getClassFilesDir().toURL()});
return cl.loadClass(packageName + "." + className);
} catch (AssertionError | RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new RuntimeException("Failed to load generated class", t);
}
}
private String findPackageName(String java) {
Pattern p = Pattern.compile("package ([^;]+);");
Matcher m = p.matcher(java);
m.find();
return m.group(1);
}
private String findClassName(String java) {
Pattern p = Pattern.compile("public class ([^ ]+)");
Matcher m = p.matcher(java);
m.find();
return m.group(1);
}
private File getSourcesFilesDir() {
File srcdir = new File(JAVA_FILES_DIR, getClass().getSimpleName());
srcdir.mkdirs();
return srcdir;
}
private File getClassFilesDir() {
File destdir = new File(CLASS_FILES_DIR, getClass().getSimpleName());
destdir.mkdirs();
return destdir;
}
}

View File

@@ -0,0 +1,45 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddEntityTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(0, cd.getFrom().getEntities().size());
assertEquals(2, cd.getTo().getEntities().size());
assertEquals(1, cd.getTo().getEntities().get(0).getFields().size());
assertEquals(1, cd.getTo().getEntities().get(1).getFields().size());
assertEquals("i2", cd.getTo().getEntities().get(0).getFields().get(0).getName());
assertEquals("i3", cd.getTo().getEntities().get(1).getFields().get(0).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass2");
mb.entity("TestClass2").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass3");
mb.entity("TestClass3").field("i3", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddFieldTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(0, cd.getFrom().getEntities().get(0).getFields().size());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(2, cd.getTo().getEntities().get(0).getFields().size());
assertEquals("i2", cd.getTo().getEntities().get(0).getFields().get(0).getName());
assertEquals("i3", cd.getTo().getEntities().get(0).getFields().get(1).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i3", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,48 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import jef.model.constraints.ForeignKeyConstraint;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddForeignKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(0, cd.getFrom().getEntities().get(0).getForeignKeys().size());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(1, cd.getTo().getEntities().get(0).getForeignKeys().size());
assertEquals("FK_TestClass_TestClass_i2", cd.getTo().getEntities().get(0).getForeignKeys().get(0).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
var ent = mb.entity("TestClass");
ent.field("i", int.class.getName())
.isNotNull(true);
ent.field("i2", int.class.getName())
.isNotNull(true);
mb.getEntity("TestClass").addForeignKey(new ForeignKeyConstraint(mb.getEntity("TestClass"), List.of(mb.getEntity("TestClass").getField("i2")),
mb.getEntity("TestClass"), List.of(mb.getEntity("TestClass").getField("i")),
ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddIndexTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(0, cd.getFrom().getEntities().get(0).getIndexes().size());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(1, cd.getTo().getEntities().get(0).getIndexes().size());
assertEquals("I_TestClass_i", cd.getTo().getEntities().get(0).getIndexes().get(0).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isIndex(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(0, cd.getFrom().getEntities().get(0).getKeys().size());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(1, cd.getTo().getEntities().get(0).getKeys().size());
assertEquals("K_TestClass_i", cd.getTo().getEntities().get(0).getKeys().get(0).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isKey(true);
return mb;
}
}

View File

@@ -0,0 +1,48 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import jef.model.constraints.PrimaryKeyConstraint;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
class ModelChangeDetectorAddPrimaryKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertNull(cd.getFrom().getEntities().get(0).getPrimaryKey());
assertEquals(1, cd.getTo().getEntities().size());
assertNotNull(cd.getTo().getEntities().get(0).getPrimaryKey());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.getEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getEntity("TestClass"),
List.of(mb.getEntity("TestClass").getField("i"))));
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorAddUniqueTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(0, cd.getFrom().getEntities().get(0).getUniqueKeys().size());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(1, cd.getTo().getEntities().get(0).getUniqueKeys().size());
assertEquals("U_TestClass_i", cd.getTo().getEntities().get(0).getUniqueKeys().get(0).getName());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isUnique(true);
return mb;
}
}

View File

@@ -0,0 +1,45 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropEntityTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(2, cd.getFrom().getEntities().size());
assertEquals(1, cd.getFrom().getEntities().get(0).getFields().size());
assertEquals(1, cd.getFrom().getEntities().get(1).getFields().size());
assertEquals("i2", cd.getFrom().getEntities().get(0).getFields().get(0).getName());
assertEquals("i3", cd.getFrom().getEntities().get(1).getFields().get(0).getName());
assertEquals(0, cd.getTo().getEntities().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass2");
mb.entity("TestClass2").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass3");
mb.entity("TestClass3").field("i3", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropFieldTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(2, cd.getFrom().getEntities().get(0).getFields().size());
assertEquals("i2", cd.getFrom().getEntities().get(0).getFields().get(0).getName());
assertEquals("i3", cd.getFrom().getEntities().get(0).getFields().get(1).getName());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(0, cd.getTo().getEntities().get(0).getFields().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i3", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,48 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import jef.model.constraints.ForeignKeyConstraint;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropForeignKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(1, cd.getFrom().getEntities().get(0).getForeignKeys().size());
assertEquals("FK_TestClass_TestClass_i2", cd.getFrom().getEntities().get(0).getForeignKeys().get(0).getName());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(0, cd.getTo().getEntities().get(0).getForeignKeys().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
var ent = mb.entity("TestClass");
ent.field("i", int.class.getName())
.isNotNull(true);
ent.field("i2", int.class.getName())
.isNotNull(true);
mb.getEntity("TestClass").addForeignKey(new ForeignKeyConstraint(mb.getEntity("TestClass"), List.of(mb.getEntity("TestClass").getField("i2")),
mb.getEntity("TestClass"), List.of(mb.getEntity("TestClass").getField("i")),
ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropIndexTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(1, cd.getFrom().getEntities().get(0).getIndexes().size());
assertEquals("I_TestClass_i", cd.getFrom().getEntities().get(0).getIndexes().get(0).getName());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(0, cd.getTo().getEntities().get(0).getIndexes().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isIndex(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(1, cd.getFrom().getEntities().get(0).getKeys().size());
assertEquals("K_TestClass_i", cd.getFrom().getEntities().get(0).getKeys().get(0).getName());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(0, cd.getTo().getEntities().get(0).getKeys().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isKey(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,48 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import jef.model.constraints.PrimaryKeyConstraint;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
class ModelChangeDetectorDropPrimaryKeyTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertNotNull(cd.getFrom().getEntities().get(0).getPrimaryKey());
assertEquals(1, cd.getTo().getEntities().size());
assertNull(cd.getTo().getEntities().get(0).getPrimaryKey());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.getEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getEntity("TestClass"),
List.of(mb.getEntity("TestClass").getField("i"))));
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,43 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ModelChangeDetectorDropUniqueTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertEquals(1, cd.getFrom().getEntities().size());
assertEquals(1, cd.getFrom().getEntities().get(0).getUniqueKeys().size());
assertEquals("U_TestClass_i", cd.getFrom().getEntities().get(0).getUniqueKeys().get(0).getName());
assertEquals(1, cd.getTo().getEntities().size());
assertEquals(0, cd.getTo().getEntities().get(0).getUniqueKeys().size());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i", int.class.getName()).isUnique(true);
return mb;
}
private ModelBuilder createTo() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
}

View File

@@ -0,0 +1,34 @@
package jef.model.migration.creator;
import jef.model.ModelBuilder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ModelChangeDetectorNoChangeTest {
@Test
public void test() {
var from = createFrom();
var to = createTo();
var cd = new ModelChangeDetector(from, to).detect();
assertTrue(cd.getFrom().getEntities().isEmpty());
assertTrue(cd.getTo().getEntities().isEmpty());
}
private ModelBuilder createFrom() {
var mb = new ModelBuilder();
mb.entity("TestClass");
mb.entity("TestClass").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass2");
mb.entity("TestClass2").field("i", int.class.getName())
.isNotNull(true);
mb.entity("TestClass2").field("i2", int.class.getName())
.isNotNull(true);
return mb;
}
private ModelBuilder createTo() {
return createFrom();
}
}