added migration generation
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
package jef.model;
|
package jef.model;
|
||||||
|
|
||||||
public abstract class DbContext {
|
public abstract class DbContext {
|
||||||
|
public void onModelCreate(ModelBuilder mb) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ import jef.model.constraints.ForeignKeyConstraint;
|
|||||||
import jef.model.constraints.IndexConstraint;
|
import jef.model.constraints.IndexConstraint;
|
||||||
import jef.model.constraints.KeyConstraint;
|
import jef.model.constraints.KeyConstraint;
|
||||||
import jef.model.constraints.PrimaryKeyConstraint;
|
import jef.model.constraints.PrimaryKeyConstraint;
|
||||||
import jef.model.constraints.UniqueConstraint;
|
import jef.model.constraints.UniqueKeyConstraint;
|
||||||
import jef.serializable.SerializableFunction;
|
import jef.serializable.SerializableFunction;
|
||||||
import jef.serializable.SerializableObject;
|
import jef.serializable.SerializableObject;
|
||||||
|
import jef.util.Check;
|
||||||
|
import jef.util.Util;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -18,33 +21,66 @@ import java.lang.reflect.Field;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class DbEntity<T extends SerializableObject> {
|
public class DbEntity<T extends SerializableObject> {
|
||||||
private final Class<T> type;
|
private final String typeName;
|
||||||
|
@Setter(value = AccessLevel.PACKAGE)
|
||||||
|
private Class<T> type;
|
||||||
private final List<DbField<?>> fields;
|
private final List<DbField<?>> fields;
|
||||||
private String name;
|
private String name;
|
||||||
private PrimaryKeyConstraint primaryKey;
|
private PrimaryKeyConstraint primaryKey;
|
||||||
private final List<ForeignKeyConstraint> foreignKeys = new ArrayList<>();
|
private final List<ForeignKeyConstraint> foreignKeys = new ArrayList<>();
|
||||||
private final List<UniqueConstraint> uniqueKeys = new ArrayList<>();
|
private final List<UniqueKeyConstraint> uniqueKeys = new ArrayList<>();
|
||||||
private final List<KeyConstraint> keys = new ArrayList<>();
|
private final List<KeyConstraint> keys = new ArrayList<>();
|
||||||
private final List<IndexConstraint> indexes = new ArrayList<>();
|
private final List<IndexConstraint> indexes = new ArrayList<>();
|
||||||
|
|
||||||
DbEntity(Class<T> type) {
|
//only used for migrations
|
||||||
this(type, new ArrayList<>());
|
DbEntity(String typeName) {
|
||||||
|
this.type = (Class) Util.tryGet(() -> Class.forName(typeName)).orElse(null);
|
||||||
|
this.typeName = typeName;
|
||||||
|
this.fields = new ArrayList<>();
|
||||||
|
var split = typeName.split("\\.");
|
||||||
|
this.name = split[split.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
DbEntity(Class<T> type, List<DbField<?>> fields) {
|
DbEntity(Class<T> type) {
|
||||||
this.type = type;
|
this(type, type.getSimpleName());
|
||||||
this.fields = fields;
|
}
|
||||||
this.name = type.getSimpleName();
|
|
||||||
|
DbEntity(Class<T> type, String name) {
|
||||||
|
this(type, name, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
DbEntity(Class<T> type, String name, List<DbField<?>> fields) {
|
||||||
|
this.type = Check.notNull(type, "type");
|
||||||
|
this.typeName = type.getName();
|
||||||
|
this.fields = Check.notNull(fields, "fields");
|
||||||
|
this.name = Check.notNull(name, "name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DbField<?>> getFields() {
|
public List<DbField<?>> getFields() {
|
||||||
return Collections.unmodifiableList(fields);
|
return Collections.unmodifiableList(fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ForeignKeyConstraint> getForeignKeys() {
|
||||||
|
return Collections.unmodifiableList(foreignKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UniqueKeyConstraint> getUniqueKeys() {
|
||||||
|
return Collections.unmodifiableList(uniqueKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<KeyConstraint> getKeys() {
|
||||||
|
return Collections.unmodifiableList(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IndexConstraint> getIndexes() {
|
||||||
|
return Collections.unmodifiableList(indexes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database model for the requested property or null if not present.
|
* Returns the database model for the requested property or null if not present.
|
||||||
*
|
*
|
||||||
@@ -62,6 +98,10 @@ public class DbEntity<T extends SerializableObject> {
|
|||||||
return (DbField<R>) fields.stream().filter(e -> e.getField().equals(field)).findFirst().orElse(null);
|
return (DbField<R>) fields.stream().filter(e -> e.getField().equals(field)).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <R> DbField<R> getField(String name) {
|
||||||
|
return (DbField<R>) fields.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
public <R> DbField<R> getOrCreateField(SerializableFunction<T, R> getter) {
|
public <R> DbField<R> getOrCreateField(SerializableFunction<T, R> getter) {
|
||||||
try {
|
try {
|
||||||
var prop = getField(getter);
|
var prop = getField(getter);
|
||||||
@@ -93,6 +133,19 @@ public class DbEntity<T extends SerializableObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <R> DbField<R> getOrCreateField(String name, String typeName) {
|
||||||
|
try {
|
||||||
|
var prop = (DbField<R>) fields.stream().filter(e -> e.getName().equals(name)).findFirst().orElse(null);
|
||||||
|
if (prop == null) {
|
||||||
|
prop = new DbField<>(this, name, typeName);
|
||||||
|
fields.add(prop);
|
||||||
|
}
|
||||||
|
return prop;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Invalid expression", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public <R> DbField<R> addIfAbsent(DbField<R> field) {
|
public <R> DbField<R> addIfAbsent(DbField<R> field) {
|
||||||
try {
|
try {
|
||||||
var prop = (DbField<R>) fields.stream().filter(e -> e.getName().equals(field.getName())).findFirst().orElse(null);
|
var prop = (DbField<R>) fields.stream().filter(e -> e.getName().equals(field.getName())).findFirst().orElse(null);
|
||||||
@@ -106,6 +159,26 @@ public class DbEntity<T extends SerializableObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean dropField(DbField<?> field) {
|
||||||
|
return this.fields.remove(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dropForeignKey(ForeignKeyConstraint foreignKey) {
|
||||||
|
return this.foreignKeys.remove(foreignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dropUniqueKey(UniqueKeyConstraint uniqueKey) {
|
||||||
|
return this.uniqueKeys.remove(uniqueKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dropKey(KeyConstraint key) {
|
||||||
|
return this.keys.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dropIndex(IndexConstraint index) {
|
||||||
|
return this.indexes.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
private <R> String extractFieldName(SerializableFunction<T, R> getter) {
|
private <R> String extractFieldName(SerializableFunction<T, R> getter) {
|
||||||
try {
|
try {
|
||||||
var expr = new AsmParser(getter).parse();
|
var expr = new AsmParser(getter).parse();
|
||||||
@@ -125,15 +198,9 @@ public class DbEntity<T extends SerializableObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUniqueContstraint(UniqueConstraint uniqueConstraint) {
|
public void addUniqueKey(UniqueKeyConstraint uniqueKeyConstraint) {
|
||||||
if (!uniqueKeys.contains(uniqueConstraint)) {
|
if (!uniqueKeys.contains(uniqueKeyConstraint)) {
|
||||||
uniqueKeys.add(uniqueConstraint);
|
uniqueKeys.add(uniqueKeyConstraint);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addIndex(IndexConstraint index) {
|
|
||||||
if (!indexes.contains(index)) {
|
|
||||||
indexes.add(index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,11 +210,37 @@ public class DbEntity<T extends SerializableObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addIndex(IndexConstraint index) {
|
||||||
|
if (!indexes.contains(index)) {
|
||||||
|
indexes.add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
DbEntity<?> dbEntity = (DbEntity<?>) o;
|
||||||
|
return typeName.equals(dbEntity.typeName)
|
||||||
|
&& fields.equals(dbEntity.fields)
|
||||||
|
&& name.equals(dbEntity.name)
|
||||||
|
&& Objects.equals(primaryKey, dbEntity.primaryKey)
|
||||||
|
&& foreignKeys.equals(dbEntity.foreignKeys)
|
||||||
|
&& uniqueKeys.equals(dbEntity.uniqueKeys)
|
||||||
|
&& keys.equals(dbEntity.keys)
|
||||||
|
&& indexes.equals(dbEntity.indexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(typeName, type, fields, name, primaryKey, foreignKeys, uniqueKeys, keys, indexes);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DbEntity{" +
|
return "DbEntity{" +
|
||||||
"type=" + type +
|
"type=" + type +
|
||||||
", name='" + name + '\'' +
|
", name='" + name + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package jef.model;
|
|||||||
|
|
||||||
import jef.model.constraints.IndexConstraint;
|
import jef.model.constraints.IndexConstraint;
|
||||||
import jef.model.constraints.KeyConstraint;
|
import jef.model.constraints.KeyConstraint;
|
||||||
import jef.model.constraints.UniqueConstraint;
|
import jef.model.constraints.UniqueKeyConstraint;
|
||||||
import jef.serializable.SerializableObject;
|
import jef.serializable.SerializableObject;
|
||||||
|
import jef.util.Check;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@@ -11,28 +13,43 @@ import java.lang.reflect.Field;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class DbField<T> {
|
public class DbField<T> {
|
||||||
private final DbEntity<? extends SerializableObject> entity;
|
private final DbEntity<? extends SerializableObject> entity;
|
||||||
private final Class<T> type;
|
private final String typeName;
|
||||||
private final Field field;
|
@Setter(value = AccessLevel.PACKAGE)
|
||||||
|
private Class<T> type;
|
||||||
|
@Setter(value = AccessLevel.PACKAGE)
|
||||||
|
private Field field;
|
||||||
private boolean isModelField;
|
private boolean isModelField;
|
||||||
private boolean isDatabaseField;
|
private boolean isDatabaseField;
|
||||||
private DbField<?> foreignKeyModelLink;
|
private DbField<?> foreignKeyModelLink;
|
||||||
private String name;
|
private String name;
|
||||||
private boolean notNull = false;
|
private boolean notNull = false;
|
||||||
|
|
||||||
|
DbField(DbEntity<? extends SerializableObject> entity, String name, String typeName) {
|
||||||
|
this.entity = Check.notNull(entity, "entity");
|
||||||
|
this.type = null;
|
||||||
|
this.typeName = Check.notNull(typeName, "typeName");
|
||||||
|
this.field = null;
|
||||||
|
this.name = Check.notNull(name, "name");
|
||||||
|
this.isModelField = false;
|
||||||
|
this.isDatabaseField = true;
|
||||||
|
}
|
||||||
|
|
||||||
DbField(DbEntity<? extends SerializableObject> entity, Class<T> type, Field field) {
|
DbField(DbEntity<? extends SerializableObject> entity, Class<T> type, Field field) {
|
||||||
this(entity, type, field, field.getName());
|
this(entity, type, field, field.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
DbField(DbEntity<? extends SerializableObject> entity, Class<T> type, Field field, String name) {
|
DbField(DbEntity<? extends SerializableObject> entity, Class<T> type, Field field, String name) {
|
||||||
this.entity = entity;
|
this.entity = Check.notNull(entity, "entity");
|
||||||
this.type = type;
|
this.type = Check.notNull(type, "type");
|
||||||
|
this.typeName = type.getName();
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.name = name;
|
this.name = Check.notNull(name, "name");
|
||||||
this.isModelField = field != null;
|
this.isModelField = field != null;
|
||||||
this.isDatabaseField = !Collection.class.isAssignableFrom(type) && !SerializableObject.class.isAssignableFrom(type);
|
this.isDatabaseField = !Collection.class.isAssignableFrom(type) && !SerializableObject.class.isAssignableFrom(type);
|
||||||
}
|
}
|
||||||
@@ -48,9 +65,9 @@ public class DbField<T> {
|
|||||||
public void setUnique(boolean unique) {
|
public void setUnique(boolean unique) {
|
||||||
var constr = entity.getUniqueKeys().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
var constr = entity.getUniqueKeys().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
||||||
if (!constr.isPresent() && unique) {
|
if (!constr.isPresent() && unique) {
|
||||||
entity.getUniqueKeys().add(new UniqueConstraint(entity, new ArrayList<>(List.of(this))));
|
entity.addUniqueKey(new UniqueKeyConstraint(entity, new ArrayList<>(List.of(this))));
|
||||||
} else if (constr.isPresent() && !unique) {
|
} else if (constr.isPresent() && !unique) {
|
||||||
entity.getUniqueKeys().remove(constr.get());
|
entity.dropUniqueKey(constr.get());
|
||||||
} //else do nothing
|
} //else do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,9 +78,9 @@ public class DbField<T> {
|
|||||||
public void setIndex(boolean indexed) {
|
public void setIndex(boolean indexed) {
|
||||||
var constr = entity.getIndexes().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
var constr = entity.getIndexes().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
||||||
if (!constr.isPresent() && indexed) {
|
if (!constr.isPresent() && indexed) {
|
||||||
entity.getIndexes().add(new IndexConstraint(entity, new ArrayList<>(List.of(this))));
|
entity.addIndex(new IndexConstraint(entity, new ArrayList<>(List.of(this))));
|
||||||
} else if (constr.isPresent() && !indexed) {
|
} else if (constr.isPresent() && !indexed) {
|
||||||
entity.getIndexes().remove(constr.get());
|
entity.dropIndex(constr.get());
|
||||||
} //else do nothing
|
} //else do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,18 +91,68 @@ public class DbField<T> {
|
|||||||
public void setKey(boolean keyed) {
|
public void setKey(boolean keyed) {
|
||||||
var constr = entity.getKeys().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
var constr = entity.getKeys().stream().filter(u -> u.getFields().size() == 1 && u.getFields().get(0) == this).findFirst();
|
||||||
if (!constr.isPresent() && keyed) {
|
if (!constr.isPresent() && keyed) {
|
||||||
entity.getKeys().add(new KeyConstraint(entity, new ArrayList<>(List.of(this))));
|
entity.addKey(new KeyConstraint(entity, new ArrayList<>(List.of(this))));
|
||||||
} else if (constr.isPresent() && !keyed) {
|
} else if (constr.isPresent() && !keyed) {
|
||||||
entity.getKeys().remove(constr.get());
|
entity.dropKey(constr.get());
|
||||||
} //else do nothing
|
} //else do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DbField<T> setModelField(boolean modelField) {
|
||||||
|
isModelField = modelField;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbField<T> setDatabaseField(boolean databaseField) {
|
||||||
|
isDatabaseField = databaseField;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbField<T> setNotNull(boolean notNull) {
|
||||||
|
this.notNull = notNull;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!equalsCommon(o)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DbField<?> dbField = (DbField<?>) o;
|
||||||
|
return name.equals(dbField.name);
|
||||||
|
// && Objects.equals(field == null ? null : field.getName(), dbField.field == null ? null : dbField.field.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalsExceptName(Object o) {
|
||||||
|
return equalsCommon(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean equalsCommon(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
DbField<?> dbField = (DbField<?>) o;
|
||||||
|
return isModelField == dbField.isModelField
|
||||||
|
&& isDatabaseField == dbField.isDatabaseField
|
||||||
|
&& notNull == dbField.notNull
|
||||||
|
&& entity.getName().equals(dbField.entity.getName())
|
||||||
|
&& typeName.equals(dbField.typeName)
|
||||||
|
// && Objects.equals(type, dbField.type)
|
||||||
|
&& Objects.equals(foreignKeyModelLink == null ? null : foreignKeyModelLink.getName(),
|
||||||
|
dbField.foreignKeyModelLink == null ? null : dbField.foreignKeyModelLink.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(entity.getName(), typeName, type, field == null ? null : field.getName(), isModelField, isDatabaseField,
|
||||||
|
foreignKeyModelLink == null ? null : foreignKeyModelLink.getName(),
|
||||||
|
name, notNull);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DbField{" +
|
return "DbField{" +
|
||||||
"name=" + name +
|
"name=" + name +
|
||||||
", type=" + type.getSimpleName() + (notNull ? "" : "?") +
|
", typeName=" + typeName + (notNull ? "" : "?") +
|
||||||
", entity=" + entity +
|
", entity=" + entity +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ class EntityInitializer {
|
|||||||
throw new ModelException("DbSet " + ctxfield.getName() + " is missing the " + Clazz.class.getSimpleName() + " annotation");
|
throw new ModelException("DbSet " + ctxfield.getName() + " is missing the " + Clazz.class.getSimpleName() + " annotation");
|
||||||
}
|
}
|
||||||
var dbsetClazz = (Class<? extends SerializableObject>) clazzAnnotation.clazz();
|
var dbsetClazz = (Class<? extends SerializableObject>) clazzAnnotation.clazz();
|
||||||
initEntity(mb, dbsetClazz);
|
initEntity(mb, dbsetClazz, ctxfield.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initEntity(ModelBuilder mb, Class<? extends SerializableObject> clazz) {
|
static void initEntity(ModelBuilder mb, Class<? extends SerializableObject> clazz, String name) {
|
||||||
var entity = mb.getOrCreateEntity(clazz);
|
var entity = mb.getOrCreateEntity(clazz);
|
||||||
|
entity.setName(name);
|
||||||
|
|
||||||
var fields = ReflectionUtil.getFieldsRecursive(clazz);
|
var fields = ReflectionUtil.getFieldsRecursive(clazz);
|
||||||
for (var f : fields) {
|
for (var f : fields) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class ForeignKeyInitializer {
|
|||||||
}
|
}
|
||||||
var otherEntity = mb.getEntity((Class<? extends SerializableObject>) clazzAnnotation.clazz());
|
var otherEntity = mb.getEntity((Class<? extends SerializableObject>) clazzAnnotation.clazz());
|
||||||
if (otherEntity == null) {
|
if (otherEntity == null) {
|
||||||
EntityInitializer.initEntity(mb, (Class<? extends SerializableObject>) clazzAnnotation.clazz());
|
EntityInitializer.initEntity(mb, (Class<? extends SerializableObject>) clazzAnnotation.clazz(), f.getName());
|
||||||
otherEntity = mb.getEntity((Class<? extends SerializableObject>) clazzAnnotation.clazz());
|
otherEntity = mb.getEntity((Class<? extends SerializableObject>) clazzAnnotation.clazz());
|
||||||
PrimaryKeyInitializer.initPrimaryKeys(mb, otherEntity);
|
PrimaryKeyInitializer.initPrimaryKeys(mb, otherEntity);
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ class ForeignKeyInitializer {
|
|||||||
} else if (SerializableObject.class.isAssignableFrom(f.getType())) {
|
} else if (SerializableObject.class.isAssignableFrom(f.getType())) {
|
||||||
var otherEntity = mb.getEntity((Class<? extends SerializableObject>) f.getType());
|
var otherEntity = mb.getEntity((Class<? extends SerializableObject>) f.getType());
|
||||||
if (otherEntity == null) {
|
if (otherEntity == null) {
|
||||||
EntityInitializer.initEntity(mb, (Class<? extends SerializableObject>) f.getType());
|
EntityInitializer.initEntity(mb, (Class<? extends SerializableObject>) f.getType(), f.getName());
|
||||||
otherEntity = mb.getEntity((Class<? extends SerializableObject>) f.getType());
|
otherEntity = mb.getEntity((Class<? extends SerializableObject>) f.getType());
|
||||||
PrimaryKeyInitializer.initPrimaryKeys(mb, otherEntity);
|
PrimaryKeyInitializer.initPrimaryKeys(mb, otherEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,23 @@ import jef.model.annotations.processors.IndexProcessor;
|
|||||||
import jef.model.annotations.processors.KeyProcessor;
|
import jef.model.annotations.processors.KeyProcessor;
|
||||||
import jef.model.annotations.processors.NotNullProcessor;
|
import jef.model.annotations.processors.NotNullProcessor;
|
||||||
import jef.model.annotations.processors.UniqueProcessor;
|
import jef.model.annotations.processors.UniqueProcessor;
|
||||||
|
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 jef.serializable.SerializableObject;
|
||||||
|
import jef.util.Check;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class ModelBuilder {
|
public class ModelBuilder {
|
||||||
private static final List<AnnotationProcessor> annotationProcessors = new ArrayList<>();
|
private static final List<AnnotationProcessor> annotationProcessors = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
static {//TODO move this to a passable config class
|
||||||
annotationProcessors.add(NotNullProcessor.INSTANCE);
|
annotationProcessors.add(NotNullProcessor.INSTANCE);
|
||||||
annotationProcessors.add(UniqueProcessor.INSTANCE);
|
annotationProcessors.add(UniqueProcessor.INSTANCE);
|
||||||
annotationProcessors.add(IndexProcessor.INSTANCE);
|
annotationProcessors.add(IndexProcessor.INSTANCE);
|
||||||
@@ -23,7 +30,13 @@ public class ModelBuilder {
|
|||||||
annotationProcessors.add(ForeignKeyProcessor.INSTANCE);
|
annotationProcessors.add(ForeignKeyProcessor.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModelBuilder from(Class<? extends DbContext> context) {
|
/**
|
||||||
|
* Initializes a ModelBuilder and configures the entities found in the context Class according to annotations.
|
||||||
|
*
|
||||||
|
* @param context the context to use for initialization
|
||||||
|
* @return an initialized ModelBuilder
|
||||||
|
*/
|
||||||
|
public static ModelBuilder from(Class<? extends DbContext> context) { //TODO pass optional config here
|
||||||
try {
|
try {
|
||||||
return from0(context);
|
return from0(context);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -40,15 +53,34 @@ public class ModelBuilder {
|
|||||||
for (AnnotationProcessor processor : annotationProcessors) {
|
for (AnnotationProcessor processor : annotationProcessors) {
|
||||||
processor.apply(mb);
|
processor.apply(mb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var instance = context.getDeclaredConstructor().newInstance();//TODO find constructor, //TODO optionally with config
|
||||||
|
instance.onModelCreate(mb);
|
||||||
|
|
||||||
return mb;
|
return mb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<DbEntity<? extends SerializableObject>> entities;
|
private final List<DbEntity<? extends SerializableObject>> entities;
|
||||||
|
|
||||||
public ModelBuilder(List<DbEntity<? extends SerializableObject>> entities) {
|
/**
|
||||||
this.entities = entities;
|
* Initializes an empty ModelBuilder
|
||||||
|
*/
|
||||||
|
public ModelBuilder() {
|
||||||
|
this(List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new ModelBuilder with the provided entities.
|
||||||
|
*/
|
||||||
|
public ModelBuilder(List<DbEntity<? extends SerializableObject>> entities) {
|
||||||
|
this.entities = new ArrayList<>(entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable List of all entities.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable List of all entities
|
||||||
|
*/
|
||||||
public List<DbEntity<? extends SerializableObject>> getEntities() {
|
public List<DbEntity<? extends SerializableObject>> getEntities() {
|
||||||
return Collections.unmodifiableList(entities);
|
return Collections.unmodifiableList(entities);
|
||||||
}
|
}
|
||||||
@@ -61,22 +93,157 @@ public class ModelBuilder {
|
|||||||
* @return the database model for the requested class or null if not present.
|
* @return the database model for the requested class or null if not present.
|
||||||
*/
|
*/
|
||||||
public <T extends SerializableObject> DbEntity<T> getEntity(Class<T> clazz) {
|
public <T extends SerializableObject> DbEntity<T> getEntity(Class<T> clazz) {
|
||||||
return (DbEntity<T>) entities.stream().filter(e -> e.getType() == clazz).findFirst().orElse(null);
|
Check.notNull(clazz, "clazz");
|
||||||
|
return getEntity(clazz.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database model for the requested class or creates a new one if none exists.
|
* Returns the database model for the requested type name or null if not present.
|
||||||
|
*
|
||||||
|
* @param typeName the class name (including the package name) of the model class
|
||||||
|
* @param <T> the type of model class
|
||||||
|
* @return the database model for the requested class or null if not present.
|
||||||
|
*/
|
||||||
|
public <T extends SerializableObject> DbEntity<T> getEntity(String typeName) {
|
||||||
|
Check.notNull(typeName, "typeName");
|
||||||
|
return (DbEntity<T>) entities.stream().filter(e -> e.getTypeName().equals(typeName)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DbEntity for the requested class or creates a new empty DbEntity if none exists.
|
||||||
*
|
*
|
||||||
* @param clazz the class of the model class
|
* @param clazz the class of the model class
|
||||||
* @param <T> the type of model class
|
* @param <T> the type of model class
|
||||||
* @return the database model for the requested class or the newly created one if none existed.
|
* @return the DbEntity for the requested class or the newly created empty DbEntity if none existed.
|
||||||
*/
|
*/
|
||||||
public <T extends SerializableObject> DbEntity<T> getOrCreateEntity(Class<T> clazz) {
|
public <T extends SerializableObject> DbEntity<T> getOrCreateEntity(Class<T> clazz) {
|
||||||
var entity = getEntity(clazz);
|
Check.notNull(clazz, "clazz");
|
||||||
|
return getOrCreateEntity(clazz.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the DbEntity for the requested class or creates a new empty DbEntity if none exists.
|
||||||
|
*
|
||||||
|
* @param typeName the class name (including package name) of the model class
|
||||||
|
* @param <T> the type of model class
|
||||||
|
* @return the DbEntity for the requested class or the newly created empty DbEntity if none existed.
|
||||||
|
*/
|
||||||
|
public <T extends SerializableObject> DbEntity<T> getOrCreateEntity(String typeName) {
|
||||||
|
Check.notNull(typeName, "typeName");
|
||||||
|
var entity = (DbEntity<T>) getEntity(typeName);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
entity = new DbEntity<>(clazz);
|
entity = new DbEntity<>(typeName);
|
||||||
entities.add(entity);
|
entities.add(entity);
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drops the entity from this ModelBuilder. This function also drops referencing foreign keys.
|
||||||
|
*
|
||||||
|
* @param entity the entity to drop
|
||||||
|
* @param <T> the type of the entity
|
||||||
|
* @return whether the entity was present in this ModelBuilder
|
||||||
|
*/
|
||||||
|
public <T extends SerializableObject> boolean dropEntity(DbEntity<T> entity) {
|
||||||
|
Check.notNull(entity, "entity");
|
||||||
|
var removed = this.entities.remove(entity);
|
||||||
|
if (!removed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (DbEntity<? extends SerializableObject> e : this.entities) {
|
||||||
|
e.getForeignKeys().stream()
|
||||||
|
.filter(fk -> fk.getReferencedEntity() == entity)
|
||||||
|
.toList()
|
||||||
|
.forEach(e::dropForeignKey);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelBuilder clone() {
|
||||||
|
//copy entities
|
||||||
|
var entities = new ArrayList<DbEntity>();
|
||||||
|
for (int i = 0; i < this.entities.size(); i++) {
|
||||||
|
var old = this.entities.get(i);
|
||||||
|
var entity = (DbEntity<?>) new DbEntity(old.getTypeName());
|
||||||
|
entity.setName(old.getName());
|
||||||
|
entity.setType((Class) old.getType());
|
||||||
|
|
||||||
|
//add fields
|
||||||
|
old.getFields().stream().map(e -> {
|
||||||
|
var nf = new DbField(entity, e.getName(), e.getTypeName());
|
||||||
|
nf.setField(e.getField());
|
||||||
|
nf.setType(e.getType());
|
||||||
|
nf.setNotNull(e.isNotNull());
|
||||||
|
nf.setModelField(e.isModelField());
|
||||||
|
nf.setDatabaseField(e.isDatabaseField());
|
||||||
|
return nf;
|
||||||
|
})
|
||||||
|
.forEach(entity::addIfAbsent);
|
||||||
|
|
||||||
|
//apply exposed foreign keys
|
||||||
|
old.getFields().stream().filter(e -> e.getForeignKeyModelLink() != null).forEach(e -> {
|
||||||
|
var nf = entity.getFields().stream().filter(f -> f.getName().equals(e.getName())).findFirst().get(); //get(): should always be there
|
||||||
|
nf.setForeignKeyModelLink(old.getFields().stream().filter(f -> f.getName().equals(e.getForeignKeyModelLink().getName())).findFirst().get()); //get(): should always be there
|
||||||
|
});
|
||||||
|
|
||||||
|
entity.setName(old.getName());
|
||||||
|
if (old.getPrimaryKey() != null) {
|
||||||
|
var newPkFields = old.getPrimaryKey().getFields().stream()
|
||||||
|
.map(pkfield -> entity.getFields().stream().filter(f -> f.getName().equals(pkfield.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
entity.setPrimaryKey(new PrimaryKeyConstraint(entity, (List) newPkFields));
|
||||||
|
}
|
||||||
|
entities.add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
//copy keys
|
||||||
|
for (int i = 0; i < entities.size(); i++) {
|
||||||
|
var entity = entities.get(i);
|
||||||
|
var old = this.entities.get(i);
|
||||||
|
for (ForeignKeyConstraint foreignKey : old.getForeignKeys()) {
|
||||||
|
var fkFields = foreignKey.getFields().stream()
|
||||||
|
.map(fkField -> entity.getFields().stream().filter(f -> ((DbField) f).getName().equals(fkField.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
var refEntity = entities.stream().filter(e -> e.getName().equals(foreignKey.getReferencedEntity().getName())).findFirst().get();//should always be there
|
||||||
|
var fkRefFields = foreignKey.getReferencedFields().stream()
|
||||||
|
.map(fkField -> refEntity.getFields().stream().filter(f -> ((DbField) f).getName().equals(fkField.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
entities.get(i).addForeignKey(new ForeignKeyConstraint(entity, (List) fkFields, refEntity, (List) fkRefFields, foreignKey.getOnUpdate(), foreignKey.getOnDelete()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UniqueKeyConstraint uniqueKey : old.getUniqueKeys()) {
|
||||||
|
var newUkFields = uniqueKey.getFields().stream()
|
||||||
|
.map(ukField -> entity.getFields().stream().filter(f -> ((DbField) f).getName().equals(ukField.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
entity.addUniqueKey(new UniqueKeyConstraint(entity, (List) newUkFields));
|
||||||
|
}
|
||||||
|
for (KeyConstraint key : old.getKeys()) {
|
||||||
|
var newKFields = key.getFields().stream()
|
||||||
|
.map(kField -> entity.getFields().stream().filter(f -> ((DbField) f).getName().equals(kField.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
entity.addKey(new KeyConstraint(entity, (List) newKFields));
|
||||||
|
}
|
||||||
|
for (IndexConstraint index : old.getIndexes()) {
|
||||||
|
var newIFields = index.getFields().stream()
|
||||||
|
.map(iField -> entity.getFields().stream().filter(f -> ((DbField) f).getName().equals(iField.getName())).findFirst().get()) //get(): should always be there
|
||||||
|
.toList();
|
||||||
|
entity.addIndex(new IndexConstraint(entity, (List) newIFields));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ModelBuilder((List) entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ModelBuilder that = (ModelBuilder) o;
|
||||||
|
return entities.equals(that.entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(entities);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package jef.model.annotations.processors;
|
|||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import jef.model.annotations.Unique;
|
import jef.model.annotations.Unique;
|
||||||
import jef.model.constraints.UniqueConstraint;
|
import jef.model.constraints.UniqueKeyConstraint;
|
||||||
import jef.serializable.SerializableObject;
|
import jef.serializable.SerializableObject;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class UniqueProcessor extends KeyProcessorBase<UniqueConstraint, Unique> {
|
public class UniqueProcessor extends KeyProcessorBase<UniqueKeyConstraint, Unique> {
|
||||||
public static final UniqueProcessor INSTANCE = new UniqueProcessor();
|
public static final UniqueProcessor INSTANCE = new UniqueProcessor();
|
||||||
|
|
||||||
private UniqueProcessor() {
|
private UniqueProcessor() {
|
||||||
@@ -17,13 +17,13 @@ public class UniqueProcessor extends KeyProcessorBase<UniqueConstraint, Unique>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UniqueConstraint initConstraint(DbEntity<? extends SerializableObject> entity, List<DbField<?>> fields) {
|
protected UniqueKeyConstraint initConstraint(DbEntity<? extends SerializableObject> entity, List<DbField<?>> fields) {
|
||||||
return new UniqueConstraint(entity, fields);
|
return new UniqueKeyConstraint(entity, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addConstraint(UniqueConstraint constr) {
|
protected void addConstraint(UniqueKeyConstraint constr) {
|
||||||
constr.getEntity().addUniqueContstraint(constr);
|
constr.getEntity().addUniqueKey(constr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
37
src/main/java/jef/model/constraints/ConstraintBase.java
Normal file
37
src/main/java/jef/model/constraints/ConstraintBase.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package jef.model.constraints;
|
||||||
|
|
||||||
|
import jef.model.DbEntity;
|
||||||
|
import jef.model.DbField;
|
||||||
|
import jef.util.Check;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public abstract class ConstraintBase implements Constraint {
|
||||||
|
protected final DbEntity<?> entity;
|
||||||
|
protected final List<DbField<?>> fields;
|
||||||
|
|
||||||
|
public ConstraintBase(DbEntity<?> entity, List<DbField<?>> fields) {
|
||||||
|
this.entity = Check.notNull(entity, "entity");
|
||||||
|
this.fields = Check.notNull(fields, "fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
ConstraintBase that = (ConstraintBase) o;
|
||||||
|
|
||||||
|
//only compare names
|
||||||
|
return entity.getName().equals(that.entity.getName())
|
||||||
|
&& fields.stream().map(DbField::getName).toList().equals(that.fields.stream().map(DbField::getName).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
//only hash names
|
||||||
|
return Objects.hash(entity.getName(), fields.stream().map(DbField::getName).toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,24 +2,47 @@ package jef.model.constraints;
|
|||||||
|
|
||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
public class ForeignKeyConstraint extends ConstraintBase {
|
||||||
@EqualsAndHashCode
|
|
||||||
public class ForeignKeyConstraint implements Constraint {
|
|
||||||
private final DbEntity<?> entity;
|
|
||||||
private final List<DbField<?>> fields;
|
|
||||||
private final DbEntity<?> referencedEntity;
|
private final DbEntity<?> referencedEntity;
|
||||||
private final List<DbField<?>> referencedFields;
|
private final List<DbField<?>> referencedFields;
|
||||||
private final Action onUpdate;
|
private final Action onUpdate;
|
||||||
private final Action onDelete;
|
private final Action onDelete;
|
||||||
|
|
||||||
|
public ForeignKeyConstraint(DbEntity<?> entity, List<DbField<?>> fields, DbEntity<?> referencedEntity, List<DbField<?>> referencedFields, Action onUpdate, Action onDelete) {
|
||||||
|
super(entity, fields);
|
||||||
|
this.referencedEntity = referencedEntity;
|
||||||
|
this.referencedFields = referencedFields;
|
||||||
|
this.onUpdate = onUpdate;
|
||||||
|
this.onDelete = onDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
ForeignKeyConstraint that = (ForeignKeyConstraint) o;
|
||||||
|
|
||||||
|
//only compare names
|
||||||
|
return referencedEntity.getName().equals(that.referencedEntity.getName())
|
||||||
|
&& referencedFields.stream().map(DbField::getName).toList().equals(that.referencedFields.stream().map(DbField::getName).toList())
|
||||||
|
&& onUpdate == that.onUpdate
|
||||||
|
&& onDelete == that.onDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
//only hash names
|
||||||
|
return Objects.hash(super.hashCode(), referencedEntity.getName(), referencedFields.stream().map(DbField::getName).toList(), onUpdate, onDelete);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "FK_" + entity.getName() + "_" + referencedEntity.getName() + "_" + fields.stream().map(DbField::getName).collect(Collectors.joining("_"));
|
return "FK_" + entity.getName() + "_" + referencedEntity.getName() + "_" + fields.stream().map(DbField::getName).collect(Collectors.joining("_"));
|
||||||
@@ -28,7 +51,7 @@ public class ForeignKeyConstraint implements Constraint {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CONSTRAINT " + getName() + " FOREIGN KEY (" + fields.stream().map(DbField::getName).collect(Collectors.joining(", ")) + ") "
|
return "CONSTRAINT " + getName() + " FOREIGN KEY (" + fields.stream().map(DbField::getName).collect(Collectors.joining(", ")) + ") "
|
||||||
+ "REFERENCES " + referencedEntity.getName() + "(" + referencedFields.stream().map(DbField::getName).collect(Collectors.joining(", ")) + ")";
|
+ "REFERENCES " + referencedEntity.getName() + "(" + referencedFields.stream().map(DbField::getName).collect(Collectors.joining(", ")) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Action {
|
public enum Action {
|
||||||
@@ -36,5 +59,6 @@ public class ForeignKeyConstraint implements Constraint {
|
|||||||
RESTRICT,
|
RESTRICT,
|
||||||
SET_NULL,
|
SET_NULL,
|
||||||
NO_ACTION,
|
NO_ACTION,
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package jef.model.constraints;
|
|||||||
|
|
||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -10,11 +9,11 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@EqualsAndHashCode
|
public class IndexConstraint extends ConstraintBase {
|
||||||
public class IndexConstraint implements Constraint {
|
public IndexConstraint(DbEntity<?> entity, List<DbField<?>> fields) {
|
||||||
private final DbEntity<?> entity;
|
super(entity, fields);
|
||||||
private final List<DbField<?>> fields;
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package jef.model.constraints;
|
|||||||
|
|
||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -10,11 +9,11 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@EqualsAndHashCode
|
public class KeyConstraint extends ConstraintBase {
|
||||||
public class KeyConstraint implements Constraint {
|
public KeyConstraint(DbEntity<?> entity, List<DbField<?>> fields) {
|
||||||
private final DbEntity<?> entity;
|
super(entity, fields);
|
||||||
private final List<DbField<?>> fields;
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package jef.model.constraints;
|
|||||||
|
|
||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -10,11 +9,11 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@EqualsAndHashCode
|
public class PrimaryKeyConstraint extends ConstraintBase {
|
||||||
public class PrimaryKeyConstraint implements Constraint {
|
public PrimaryKeyConstraint(DbEntity<?> entity, List<DbField<?>> fields) {
|
||||||
private final DbEntity<?> entity;
|
super(entity, fields);
|
||||||
private final List<DbField<?>> fields;
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package jef.model.constraints;
|
|||||||
|
|
||||||
import jef.model.DbEntity;
|
import jef.model.DbEntity;
|
||||||
import jef.model.DbField;
|
import jef.model.DbField;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -10,11 +9,11 @@ import java.util.List;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@EqualsAndHashCode
|
public class UniqueKeyConstraint extends ConstraintBase {
|
||||||
public class UniqueConstraint implements Constraint {
|
public UniqueKeyConstraint(DbEntity<?> entity, List<DbField<?>> fields) {
|
||||||
private final DbEntity<?> entity;
|
super(entity, fields);
|
||||||
private final List<DbField<?>> fields;
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
7
src/main/java/jef/model/migration/Migration.java
Normal file
7
src/main/java/jef/model/migration/Migration.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package jef.model.migration;
|
||||||
|
|
||||||
|
public interface Migration {
|
||||||
|
void up(MigrationBuilder migrationBuilder);
|
||||||
|
|
||||||
|
void down(MigrationBuilder migrationBuilder);
|
||||||
|
}
|
||||||
102
src/main/java/jef/model/migration/MigrationBuilder.java
Normal file
102
src/main/java/jef/model/migration/MigrationBuilder.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package jef.model.migration;
|
||||||
|
|
||||||
|
import jef.model.constraints.ForeignKeyConstraint;
|
||||||
|
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 java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MigrationBuilder {
|
||||||
|
private final List<MigrationOperation.Builder<?>> operations = new ArrayList<>();
|
||||||
|
|
||||||
|
public AddTableOperation.Builder addTable(String table, List<AddFieldOperation.Builder> fields) {
|
||||||
|
var op = new AddTableOperation.Builder(table, fields);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenameTableOperation.Builder renameTable(String oldName, String newName) {
|
||||||
|
var op = new RenameTableOperation.Builder(oldName, newName);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropTableOperation.Builder dropTable(String table) {
|
||||||
|
var op = new DropTableOperation.Builder(table);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddFieldOperation.Builder addField(String table, String field) {
|
||||||
|
var op = new AddFieldOperation.Builder(table, field);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenameFieldOperation.Builder renameField(String table, String oldName, String newName) {
|
||||||
|
var op = new RenameFieldOperation.Builder(table, oldName, newName);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateFieldOperation.Builder updateField(String table, String field) {
|
||||||
|
var op = new UpdateFieldOperation.Builder(table, field);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropFieldOperation.Builder dropField(String table, String field) {
|
||||||
|
var op = new DropFieldOperation.Builder(table, field);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddPrimaryKeyOperation.Builder addPrimaryKey(String name, String table, List<String> fields) {
|
||||||
|
var op = new AddPrimaryKeyOperation.Builder(name, table, fields);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddForeignKeyOperation.Builder addForeignKey(String name, String table, List<String> fields, String referencedTable, List<String> referencedFields, ForeignKeyConstraint.Action onUpdate, ForeignKeyConstraint.Action onDelete) {
|
||||||
|
var op = new AddForeignKeyOperation.Builder(name, table, fields, referencedTable, referencedFields, onUpdate, onDelete);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddUniqueKeyOperation.Builder addUniqueKey(String name, String table, List<String> fields) {
|
||||||
|
var op = new AddUniqueKeyOperation.Builder(name, table, fields);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddKeyOperation.Builder addKey(String name, String table, List<String> fields) {
|
||||||
|
var op = new AddKeyOperation.Builder(name, table, fields);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddIndexOperation.Builder addIndex(String name, String table, List<String> fields) {
|
||||||
|
var op = new AddIndexOperation.Builder(name, table, fields);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropConstraintOperation.Builder dropConstraint(String name, String table) {
|
||||||
|
var op = new DropConstraintOperation.Builder(name, table);
|
||||||
|
operations.add(op);
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
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 java = "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"
|
||||||
|
+ "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() + ");";
|
||||||
|
}
|
||||||
|
}
|
||||||
487
src/main/java/jef/model/migration/creator/MigrationCreator.java
Normal file
487
src/main/java/jef/model/migration/creator/MigrationCreator.java
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.model.DbField;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
import jef.model.ModelException;
|
||||||
|
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.stream.Collectors;
|
||||||
|
|
||||||
|
public class MigrationCreator {
|
||||||
|
private static final String ILLEGAL_CHARACTERS = "\"'`,.";//TODO also validate this in modelbuilder/dbentity/dbfield
|
||||||
|
|
||||||
|
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).generate().getJava();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result generateMigration(ModelBuilder from, ModelBuilder to, String name, String packageName, Result result) {
|
||||||
|
//check for illegal characters
|
||||||
|
for (var entity : to.getEntities()) {
|
||||||
|
if (entity.getName().matches("[" + ILLEGAL_CHARACTERS + "]")) {
|
||||||
|
throw new ModelException("Entity " + entity.getType().getSimpleName() + " has illegal characters in its name: " + entity.getName());
|
||||||
|
}
|
||||||
|
for (var field : entity.getFields()) {
|
||||||
|
if (field.getName().matches("[" + ILLEGAL_CHARACTERS + "]")) {
|
||||||
|
throw new ModelException("Field " + entity.getType().getSimpleName() + "::" + field.getField().getName() + " has illegal characters in its name: " + entity.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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("TODO"))
|
||||||
|
.toList()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.DbEntity;
|
||||||
|
import jef.model.DbField;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ModelBuilderGenerator {
|
||||||
|
private final ModelBuilder mb;
|
||||||
|
private final String name;
|
||||||
|
private final String packageName;
|
||||||
|
|
||||||
|
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(DbEntity.class);
|
||||||
|
var java = ""
|
||||||
|
+ "public class " + name + "Snapshot extends DbContext {\n"
|
||||||
|
+ " @Override\n"
|
||||||
|
+ " public void onModelCreate(ModelBuilder mb) {\n"
|
||||||
|
+ indent + "DbEntity entity;\n"
|
||||||
|
+ indent + "DbEntity referencedEntity;\n";
|
||||||
|
for (DbEntity<? extends SerializableObject> entity : mb.getEntities()) {
|
||||||
|
java += indent + "entity = mb.getOrCreateEntity(\"" + entity.getTypeName() + "\");\n"
|
||||||
|
+ indent + "entity.setName(\"" + entity.getName() + "\");\n";
|
||||||
|
for (DbField<?> field : entity.getFields()) {
|
||||||
|
java += indent + "entity.getOrCreateField(\"" + field.getName() + "\", \"" + field.getTypeName() + "\")"
|
||||||
|
+ (field.isNotNull() ? "\n" + indent + " .setNotNull(true)" : "")
|
||||||
|
+ "\n" + indent + " .setDatabaseField(" + field.isDatabaseField() + ")"
|
||||||
|
+ "\n" + indent + " .setModelField(" + field.isModelField() + ")"
|
||||||
|
+ ";\n";
|
||||||
|
}
|
||||||
|
if (entity.getPrimaryKey() != null) {
|
||||||
|
imports.add(List.class);
|
||||||
|
imports.add(PrimaryKeyConstraint.class);
|
||||||
|
java += indent + "entity.setPrimaryKey(new PrimaryKeyConstraint(entity, List.of(\n"
|
||||||
|
+ indent + " " + entity.getPrimaryKey().getFields().stream().map(f -> "entity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n ")) + "\n"
|
||||||
|
+ indent + " )));\n";
|
||||||
|
}
|
||||||
|
java += "\n";
|
||||||
|
}
|
||||||
|
for (DbEntity<? extends SerializableObject> entity : mb.getEntities()) {
|
||||||
|
if (entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty() && entity.getForeignKeys().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
java += indent + "entity = mb.getOrCreateEntity(\"" + entity.getTypeName() + "\");\n";
|
||||||
|
for (ForeignKeyConstraint foreignKey : entity.getForeignKeys()) {
|
||||||
|
imports.add(List.class);
|
||||||
|
imports.add(ForeignKeyConstraint.class);
|
||||||
|
imports.add(ForeignKeyConstraint.Action.class);
|
||||||
|
java += indent + "referencedEntity = mb.getEntity(\"" + foreignKey.getReferencedEntity().getTypeName() + "\");\n"
|
||||||
|
+ indent + "entity.addForeignKey(new ForeignKeyConstraint(entity, List.of(\n"
|
||||||
|
+ indent + " " + foreignKey.getFields().stream().map(f -> "entity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n " + indent)) + "\n"
|
||||||
|
+ indent + " ),\n"
|
||||||
|
+ indent + " referencedEntity, List.of(\n"
|
||||||
|
+ indent + " " + foreignKey.getReferencedFields().stream().map(f -> "referencedEntity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n " + indent)) + "\n"
|
||||||
|
+ indent + " ),\n"
|
||||||
|
+ indent + " ForeignKeyConstraint.Action." + foreignKey.getOnUpdate().name() + ", ForeignKeyConstraint.Action." + foreignKey.getOnDelete().name() + "));\n";
|
||||||
|
}
|
||||||
|
for (UniqueKeyConstraint uniqueKey : entity.getUniqueKeys()) {
|
||||||
|
imports.add(List.class);
|
||||||
|
imports.add(UniqueKeyConstraint.class);
|
||||||
|
java += indent + "entity.addUniqueKey(new UniqueKeyConstraint(entity, List.of(\n"
|
||||||
|
+ indent + " " + uniqueKey.getFields().stream().map(f -> "entity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n " + indent)) + "\n"
|
||||||
|
+ indent + " )));\n";
|
||||||
|
}
|
||||||
|
for (KeyConstraint key : entity.getKeys()) {
|
||||||
|
imports.add(List.class);
|
||||||
|
imports.add(KeyConstraint.class);
|
||||||
|
java += indent + "entity.addKey(new KeyConstraint(entity, List.of(\n"
|
||||||
|
+ indent + " " + key.getFields().stream().map(f -> "entity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n " + indent)) + "\n"
|
||||||
|
+ indent + " )));\n";
|
||||||
|
}
|
||||||
|
for (IndexConstraint index : entity.getIndexes()) {
|
||||||
|
imports.add(List.class);
|
||||||
|
imports.add(IndexConstraint.class);
|
||||||
|
java += indent + "entity.addIndex(new IndexConstraint(entity, List.of(\n"
|
||||||
|
+ indent + " " + index.getFields().stream().map(f -> "entity.getField(\"" + f.getName() + "\")").collect(Collectors.joining(",\n " + indent)) + "\n"
|
||||||
|
+ indent + " )));\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 = "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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AddFieldOperation implements MigrationOperation {
|
||||||
|
protected final String table;
|
||||||
|
protected final String field;
|
||||||
|
protected final String sqlType;
|
||||||
|
protected final boolean notNull;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<AddFieldOperation> {
|
||||||
|
protected final String table;
|
||||||
|
protected final String field;
|
||||||
|
protected String sqlType;
|
||||||
|
protected boolean notNull;
|
||||||
|
|
||||||
|
public Builder(String table, String field) {
|
||||||
|
this.table = table;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder sqlType(String sqlType) {
|
||||||
|
this.sqlType = sqlType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder notNull(boolean notNull) {
|
||||||
|
this.notNull = notNull;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddFieldOperation build() {
|
||||||
|
return new AddFieldOperation(table, field, sqlType, notNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import jef.model.constraints.ForeignKeyConstraint;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AddForeignKeyOperation implements MigrationOperation {
|
||||||
|
private final String name;
|
||||||
|
private final String table;
|
||||||
|
private final List<String> fields;
|
||||||
|
private final String referencedTable;
|
||||||
|
private final List<String> referencedFields;
|
||||||
|
private final ForeignKeyConstraint.Action onUpdate;
|
||||||
|
private final ForeignKeyConstraint.Action onDelete;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<AddForeignKeyOperation> {
|
||||||
|
private final String name;
|
||||||
|
private final String table;
|
||||||
|
private final List<String> fields;
|
||||||
|
private final String referencedTable;
|
||||||
|
private final List<String> referencedFields;
|
||||||
|
private final ForeignKeyConstraint.Action onUpdate;
|
||||||
|
private final ForeignKeyConstraint.Action onDelete;
|
||||||
|
|
||||||
|
public Builder(String name, String table, List<String> fields, String referencedTable, List<String> referencedFields, ForeignKeyConstraint.Action onUpdate, ForeignKeyConstraint.Action onDelete) {
|
||||||
|
this.name = name;
|
||||||
|
this.table = table;
|
||||||
|
this.fields = fields;
|
||||||
|
this.referencedTable = referencedTable;
|
||||||
|
this.referencedFields = referencedFields;
|
||||||
|
this.onUpdate = onUpdate;
|
||||||
|
this.onDelete = onDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddForeignKeyOperation build() {
|
||||||
|
return new AddForeignKeyOperation(name, table, fields, referencedTable, referencedFields, onUpdate, onDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class AddIndexOperation extends AddKeyOperationBase {
|
||||||
|
public AddIndexOperation(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AddKeyOperationBase.Builder<AddIndexOperation> {
|
||||||
|
public Builder(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddIndexOperation build() {
|
||||||
|
return new AddIndexOperation(name, table, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class AddKeyOperation extends AddKeyOperationBase {
|
||||||
|
public AddKeyOperation(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AddKeyOperationBase.Builder<AddKeyOperation> {
|
||||||
|
public Builder(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddKeyOperation build() {
|
||||||
|
return new AddKeyOperation(name, table, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public abstract class AddKeyOperationBase implements MigrationOperation {
|
||||||
|
protected final String name;
|
||||||
|
protected final String table;
|
||||||
|
protected final List<String> fields;
|
||||||
|
|
||||||
|
public abstract static class Builder<T extends AddKeyOperationBase> implements MigrationOperation.Builder<T> {
|
||||||
|
protected final String name;
|
||||||
|
protected final String table;
|
||||||
|
protected final List<String> fields;
|
||||||
|
|
||||||
|
public Builder(String name, String table, List<String> fields) {
|
||||||
|
this.name = name;
|
||||||
|
this.table = table;
|
||||||
|
this.fields = fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class AddPrimaryKeyOperation extends AddKeyOperationBase {
|
||||||
|
public AddPrimaryKeyOperation(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AddKeyOperationBase.Builder<AddPrimaryKeyOperation> {
|
||||||
|
public Builder(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddPrimaryKeyOperation build() {
|
||||||
|
return new AddPrimaryKeyOperation(name, table, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AddTableOperation implements MigrationOperation {
|
||||||
|
private final String table;
|
||||||
|
private final List<AddFieldOperation.Builder> fields;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<AddTableOperation> {
|
||||||
|
private final String table;
|
||||||
|
private final List<AddFieldOperation.Builder> fields;
|
||||||
|
|
||||||
|
public Builder(String table, List<AddFieldOperation.Builder> fields) {
|
||||||
|
this.table = table;
|
||||||
|
this.fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddTableOperation build() {
|
||||||
|
return new AddTableOperation(table, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class AddUniqueKeyOperation extends AddKeyOperationBase {
|
||||||
|
public AddUniqueKeyOperation(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AddKeyOperationBase.Builder<AddUniqueKeyOperation> {
|
||||||
|
public Builder(String name, String table, List<String> fields) {
|
||||||
|
super(name, table, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddUniqueKeyOperation build() {
|
||||||
|
return new AddUniqueKeyOperation(name, table, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DropConstraintOperation implements MigrationOperation {
|
||||||
|
private final String name;
|
||||||
|
private final String table;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<DropConstraintOperation> {
|
||||||
|
private final String name;
|
||||||
|
private final String table;
|
||||||
|
|
||||||
|
public Builder(String name, String table) {
|
||||||
|
this.name = name;
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropConstraintOperation build() {
|
||||||
|
return new DropConstraintOperation(name, table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DropFieldOperation implements MigrationOperation {
|
||||||
|
private final String table;
|
||||||
|
private final String field;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<DropFieldOperation> {
|
||||||
|
private final String table;
|
||||||
|
private final String field;
|
||||||
|
|
||||||
|
public Builder(String table, String field) {
|
||||||
|
this.table = table;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropFieldOperation build() {
|
||||||
|
return new DropFieldOperation(table, field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class DropTableOperation implements MigrationOperation {
|
||||||
|
private final String table;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<DropTableOperation> {
|
||||||
|
private final String table;
|
||||||
|
|
||||||
|
public Builder(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DropTableOperation build() {
|
||||||
|
return new DropTableOperation(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
public interface MigrationOperation {
|
||||||
|
public interface Builder<T extends MigrationOperation> {
|
||||||
|
T build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RenameFieldOperation implements MigrationOperation {
|
||||||
|
private final String table;
|
||||||
|
private final String oldName;
|
||||||
|
private final String newName;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<RenameFieldOperation> {
|
||||||
|
private final String table;
|
||||||
|
private final String oldName;
|
||||||
|
private final String newName;
|
||||||
|
|
||||||
|
public Builder(String table, String oldName, String newName) {
|
||||||
|
this.table = table;
|
||||||
|
this.oldName = oldName;
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenameFieldOperation build() {
|
||||||
|
return new RenameFieldOperation(table, oldName, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RenameTableOperation implements MigrationOperation {
|
||||||
|
private final String oldName;
|
||||||
|
private final String newName;
|
||||||
|
|
||||||
|
public static class Builder implements MigrationOperation.Builder<RenameTableOperation> {
|
||||||
|
private final String oldName;
|
||||||
|
private final String newName;
|
||||||
|
|
||||||
|
public Builder(String oldName, String newName) {
|
||||||
|
this.oldName = oldName;
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenameTableOperation build() {
|
||||||
|
return new RenameTableOperation(oldName, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package jef.model.migration.operation;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class UpdateFieldOperation extends AddFieldOperation {
|
||||||
|
private final String newName;
|
||||||
|
|
||||||
|
public UpdateFieldOperation(String table, String field, String newName, String sqlType, boolean notNull) {
|
||||||
|
super(table, field, sqlType, notNull);
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder extends AddFieldOperation.Builder {
|
||||||
|
private String newName;
|
||||||
|
|
||||||
|
public Builder(String table, String field) {
|
||||||
|
super(table, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder newName(String newName) {
|
||||||
|
this.newName = newName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateFieldOperation build() {
|
||||||
|
return new UpdateFieldOperation(table, field, newName, sqlType, notNull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/java/jef/util/Check.java
Normal file
10
src/main/java/jef/util/Check.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package jef.util;
|
||||||
|
|
||||||
|
public abstract class Check {
|
||||||
|
public static <T> T notNull(T t, String name) {
|
||||||
|
if (t == null) {
|
||||||
|
throw new IllegalArgumentException(name + " must be not null");
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/jef/util/Util.java
Normal file
18
src/main/java/jef/util/Util.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package jef.util;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public abstract class Util {
|
||||||
|
public static <T> Optional<T> tryGet(ThrowableSupplier<T> s) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(s.get());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ThrowableSupplier<T> {
|
||||||
|
T get() throws Throwable;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ class DbContextSimpleTest {
|
|||||||
public void test() {
|
public void test() {
|
||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertEquals(5, mb.getEntity(TestClass.class).getFields().size());
|
assertEquals(5, mb.getEntity(TestClass.class).getFields().size());
|
||||||
assertEquals(1, mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).count());
|
assertEquals(1, mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).count());
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class EntityInitializerMultiple1To1RelationTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(2, mb.getEntities().size());
|
assertEquals(2, mb.getEntities().size());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ class ForeignKeyInitializerNToNRelationTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(3, mb.getEntities().size());
|
assertEquals(3, mb.getEntities().size());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
assertEquals(Mapping.class.getSimpleName(), mb.getEntity(Mapping.class).getName());
|
assertEquals("rels", mb.getEntity(Mapping.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(Mapping.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(Mapping.class)));
|
assertTrue(mb.getEntity(Mapping.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(Mapping.class)));
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ class ForeignKeyInitializerNestedList2LayerTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(3, mb.getEntities().size());
|
assertEquals(3, mb.getEntities().size());
|
||||||
assertEquals(TestClass3.class.getSimpleName(), mb.getEntity(TestClass3.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass3.class).getName());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("nested2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("nested", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass3.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass3.class)));
|
assertTrue(mb.getEntity(TestClass3.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass3.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class ForeignKeyInitializerNestedListSimpleTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(2, mb.getEntities().size());
|
assertEquals(2, mb.getEntities().size());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("nested", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ class ForeignKeyInitializerNestedObject2LayerTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(3, mb.getEntities().size());
|
assertEquals(3, mb.getEntities().size());
|
||||||
assertEquals(TestClass3.class.getSimpleName(), mb.getEntity(TestClass3.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass3.class).getName());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("nested2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("nested", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass3.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass3.class)));
|
assertTrue(mb.getEntity(TestClass3.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass3.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
@@ -57,14 +57,14 @@ class ForeignKeyInitializerNestedObject2LayerTest {
|
|||||||
assertEquals(mb.getEntity(TestClass3.class), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getEntity());
|
assertEquals(mb.getEntity(TestClass3.class), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getEntity());
|
||||||
assertEquals(mb.getEntity(TestClass2.class), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getReferencedEntity());
|
assertEquals(mb.getEntity(TestClass2.class), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getReferencedEntity());
|
||||||
assertEquals(mb.getEntity(TestClass3.class).getFields().stream().filter(e -> e.getName().equals("nested2I")).toList(),
|
assertEquals(mb.getEntity(TestClass3.class).getFields().stream().filter(e -> e.getName().equals("nested2I")).toList(),
|
||||||
mb.getEntity(TestClass3.class).getForeignKeys().get(0).getFields());
|
mb.getEntity(TestClass3.class).getForeignKeys().get(0).getFields());
|
||||||
assertEquals(mb.getEntity(TestClass2.class).getPrimaryKey().getFields(), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getReferencedFields());
|
assertEquals(mb.getEntity(TestClass2.class).getPrimaryKey().getFields(), mb.getEntity(TestClass3.class).getForeignKeys().get(0).getReferencedFields());
|
||||||
|
|
||||||
//refs TestClass2, TestClass
|
//refs TestClass2, TestClass
|
||||||
assertEquals(mb.getEntity(TestClass2.class), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getEntity());
|
assertEquals(mb.getEntity(TestClass2.class), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getEntity());
|
||||||
assertEquals(mb.getEntity(TestClass.class), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getReferencedEntity());
|
assertEquals(mb.getEntity(TestClass.class), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getReferencedEntity());
|
||||||
assertEquals(mb.getEntity(TestClass2.class).getFields().stream().filter(e -> e.getName().equals("nestedI")).toList(),
|
assertEquals(mb.getEntity(TestClass2.class).getFields().stream().filter(e -> e.getName().equals("nestedI")).toList(),
|
||||||
mb.getEntity(TestClass2.class).getForeignKeys().get(0).getFields());
|
mb.getEntity(TestClass2.class).getForeignKeys().get(0).getFields());
|
||||||
assertEquals(mb.getEntity(TestClass.class).getPrimaryKey().getFields(), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getReferencedFields());
|
assertEquals(mb.getEntity(TestClass.class).getPrimaryKey().getFields(), mb.getEntity(TestClass2.class).getForeignKeys().get(0).getReferencedFields());
|
||||||
// /keys ------------------------
|
// /keys ------------------------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class ForeignKeyInitializerNestedObjectSimpleTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(2, mb.getEntities().size());
|
assertEquals(2, mb.getEntities().size());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass2.class).getName());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("nested", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class ForeignKeyInitializerRecursive1To1RelationTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ForeignKeyInitializerRecursive1ToNRelationTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class ForeignKeyInitializerRecursiveWithParent1ToNRelationTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|
||||||
|
|||||||
258
src/test/java/jef/model/ModelBuilderCloneTest.java
Normal file
258
src/test/java/jef/model/ModelBuilderCloneTest.java
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
package jef.model;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
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 java.util.Objects;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class ModelBuilderCloneTest {
|
||||||
|
@Test
|
||||||
|
public void testClone() {
|
||||||
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
var copy = mb.clone();
|
||||||
|
|
||||||
|
debugHelper(mb, copy);
|
||||||
|
|
||||||
|
//true check
|
||||||
|
assertEquals(mb, copy);
|
||||||
|
|
||||||
|
//proper clone reference checks
|
||||||
|
for (int i = 0; i < mb.getEntities().size(); i++) {
|
||||||
|
assertTrue(mb.getEntities().get(i) != copy.getEntities().get(i));
|
||||||
|
for (int j = 0; j < mb.getEntities().get(0).getFields().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getFields().get(j) != copy.getEntities().get(i).getFields().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getFields().get(j).getEntity() != copy.getEntities().get(i).getFields().get(j).getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(mb.getEntities().get(i).getPrimaryKey() != copy.getEntities().get(i).getPrimaryKey());
|
||||||
|
assertTrue(mb.getEntities().get(i).getPrimaryKey().getEntity() != copy.getEntities().get(i).getPrimaryKey().getEntity());
|
||||||
|
|
||||||
|
for (int j = 0; j < mb.getEntities().get(i).getPrimaryKey().getFields().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getPrimaryKey().getFields().get(j) != copy.getEntities().get(i).getPrimaryKey().getFields().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getPrimaryKey().getFields().get(j).getEntity() != copy.getEntities().get(i).getPrimaryKey().getFields().get(j).getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < mb.getEntities().get(i).getForeignKeys().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j) != copy.getEntities().get(i).getForeignKeys().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getEntity() != copy.getEntities().get(i).getForeignKeys().get(j).getEntity());
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getReferencedEntity() != copy.getEntities().get(i).getForeignKeys().get(j).getReferencedEntity());
|
||||||
|
|
||||||
|
for (int k = 0; k < mb.getEntities().get(i).getForeignKeys().get(j).getFields().size(); k++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getFields().get(k) != copy.getEntities().get(i).getForeignKeys().get(j).getFields().get(k));
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getFields().get(k).getEntity() != copy.getEntities().get(i).getForeignKeys().get(j).getFields().get(k).getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int k = 0; k < mb.getEntities().get(i).getForeignKeys().get(j).getReferencedFields().size(); k++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getReferencedFields().get(k) != copy.getEntities().get(i).getForeignKeys().get(j).getReferencedFields().get(k));
|
||||||
|
assertTrue(mb.getEntities().get(i).getForeignKeys().get(j).getReferencedFields().get(k).getEntity() != copy.getEntities().get(i).getForeignKeys().get(j).getReferencedFields().get(k).getEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < mb.getEntities().get(i).getUniqueKeys().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getUniqueKeys().get(j) != copy.getEntities().get(i).getUniqueKeys().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getUniqueKeys().get(j).getEntity() != copy.getEntities().get(i).getUniqueKeys().get(j).getEntity());
|
||||||
|
|
||||||
|
for (int k = 0; k < mb.getEntities().get(i).getUniqueKeys().get(j).getFields().size(); k++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getUniqueKeys().get(j).getFields().get(k) != copy.getEntities().get(i).getUniqueKeys().get(j).getFields().get(k));
|
||||||
|
assertTrue(mb.getEntities().get(i).getUniqueKeys().get(j).getFields().get(k).getEntity() != copy.getEntities().get(i).getUniqueKeys().get(j).getFields().get(k).getEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < mb.getEntities().get(i).getKeys().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getKeys().get(j) != copy.getEntities().get(i).getKeys().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getKeys().get(j).getEntity() != copy.getEntities().get(i).getKeys().get(j).getEntity());
|
||||||
|
|
||||||
|
for (int k = 0; k < mb.getEntities().get(i).getKeys().get(j).getFields().size(); k++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getKeys().get(j).getFields().get(k) != copy.getEntities().get(i).getKeys().get(j).getFields().get(k));
|
||||||
|
assertTrue(mb.getEntities().get(i).getKeys().get(j).getFields().get(k).getEntity() != copy.getEntities().get(i).getKeys().get(j).getFields().get(k).getEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < mb.getEntities().get(i).getIndexes().size(); j++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getIndexes().get(j) != copy.getEntities().get(i).getIndexes().get(j));
|
||||||
|
assertTrue(mb.getEntities().get(i).getIndexes().get(j).getEntity() != copy.getEntities().get(i).getIndexes().get(j).getEntity());
|
||||||
|
|
||||||
|
for (int k = 0; k < mb.getEntities().get(i).getIndexes().get(j).getFields().size(); k++) {
|
||||||
|
assertTrue(mb.getEntities().get(i).getIndexes().get(j).getFields().get(k) != copy.getEntities().get(i).getIndexes().get(j).getFields().get(k));
|
||||||
|
assertTrue(mb.getEntities().get(i).getIndexes().get(j).getFields().get(k).getEntity() != copy.getEntities().get(i).getIndexes().get(j).getFields().get(k).getEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void debugHelper(ModelBuilder expected, ModelBuilder actual) {
|
||||||
|
//debug helpers
|
||||||
|
assertEquals(expected.getEntities().size(), actual.getEntities().size());
|
||||||
|
for (int i = 0; i < expected.getEntities().size(); i++) {
|
||||||
|
var o = expected.getEntities().get(i);
|
||||||
|
var c = actual.getEntities().get(i);
|
||||||
|
if (!o.getTypeName().equals(c.getTypeName())) {
|
||||||
|
System.out.println("typenames differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + o.getTypeName());
|
||||||
|
System.out.println("ac: " + c.getTypeName());
|
||||||
|
}
|
||||||
|
if (!Objects.equals(o.getType(), c.getType())) {
|
||||||
|
System.out.println("types differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + o.getType());
|
||||||
|
System.out.println("ac: " + c.getType());
|
||||||
|
}
|
||||||
|
if (!o.getName().equals(c.getName())) {
|
||||||
|
System.out.println("names differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + o.getName());
|
||||||
|
System.out.println("ac: " + c.getName());
|
||||||
|
}
|
||||||
|
if (!Objects.equals(o.getPrimaryKey(), c.getPrimaryKey())) {
|
||||||
|
System.out.println("primary keys differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + o.getPrimaryKey());
|
||||||
|
System.out.println("ac: " + c.getPrimaryKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(o.getForeignKeys().size(), c.getForeignKeys().size());
|
||||||
|
for (int j = 0; j < o.getForeignKeys().size(); j++) {
|
||||||
|
var ok = o.getForeignKeys().get(j);
|
||||||
|
var ck = c.getForeignKeys().get(j);
|
||||||
|
if (!Objects.equals(ok, ck)) {
|
||||||
|
System.out.println("foreign keys differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + ok);
|
||||||
|
System.out.println("ac: " + ck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(o.getUniqueKeys().size(), c.getUniqueKeys().size());
|
||||||
|
for (int j = 0; j < o.getUniqueKeys().size(); j++) {
|
||||||
|
var ok = o.getUniqueKeys().get(j);
|
||||||
|
var ck = c.getUniqueKeys().get(j);
|
||||||
|
if (!Objects.equals(ok, ck)) {
|
||||||
|
System.out.println("unique keys differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + ok);
|
||||||
|
System.out.println("ac: " + ck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(o.getKeys().size(), c.getKeys().size());
|
||||||
|
for (int j = 0; j < o.getKeys().size(); j++) {
|
||||||
|
var ok = o.getKeys().get(j);
|
||||||
|
var ck = c.getKeys().get(j);
|
||||||
|
if (!Objects.equals(ok, ck)) {
|
||||||
|
System.out.println("keys differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + ok);
|
||||||
|
System.out.println("ac: " + ck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(o.getIndexes().size(), c.getIndexes().size());
|
||||||
|
for (int j = 0; j < o.getIndexes().size(); j++) {
|
||||||
|
var ok = o.getIndexes().get(j);
|
||||||
|
var ck = c.getIndexes().get(j);
|
||||||
|
if (!Objects.equals(ok, ck)) {
|
||||||
|
System.out.println("indexes differ: entity " + o.getName());
|
||||||
|
System.out.println("ex: " + ok);
|
||||||
|
System.out.println("ac: " + ck);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(o.getFields().size(), c.getFields().size());
|
||||||
|
for (int j = 0; j < o.getIndexes().size(); j++) {
|
||||||
|
var of = o.getFields().get(j);
|
||||||
|
var cf = c.getFields().get(j);
|
||||||
|
|
||||||
|
if (of.isModelField() != cf.isModelField()) {
|
||||||
|
System.out.println("is model fields differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.isModelField());
|
||||||
|
System.out.println("ac: " + cf.isModelField());
|
||||||
|
}
|
||||||
|
if (of.isDatabaseField() != cf.isDatabaseField()) {
|
||||||
|
System.out.println("is database fields differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.isDatabaseField());
|
||||||
|
System.out.println("ac: " + cf.isDatabaseField());
|
||||||
|
}
|
||||||
|
if (of.isNotNull() != cf.isNotNull()) {
|
||||||
|
System.out.println("is notnull differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.isNotNull());
|
||||||
|
System.out.println("ac: " + cf.isNotNull());
|
||||||
|
}
|
||||||
|
if (!of.getEntity().getName().equals(cf.getEntity().getName())) {
|
||||||
|
System.out.println("entities differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.getEntity().getName());
|
||||||
|
System.out.println("ac: " + cf.getEntity().getName());
|
||||||
|
}
|
||||||
|
if (!of.getTypeName().equals(cf.getTypeName())) {
|
||||||
|
System.out.println("typenames differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.getTypeName());
|
||||||
|
System.out.println("ac: " + cf.getTypeName());
|
||||||
|
}
|
||||||
|
if (!Objects.equals(of.getType(), cf.getType())) {
|
||||||
|
System.out.println("types differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.getType());
|
||||||
|
System.out.println("ac: " + cf.getType());
|
||||||
|
}
|
||||||
|
if (!Objects.equals(of.getField() == null ? null : of.getField().getName(), cf.getField() == null ? null : cf.getField().getName())) {
|
||||||
|
System.out.println("fields differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.getField());
|
||||||
|
System.out.println("ac: " + cf.getField());
|
||||||
|
}
|
||||||
|
if (!Objects.equals(of.getForeignKeyModelLink() == null ? null : of.getForeignKeyModelLink().getName(),
|
||||||
|
cf.getForeignKeyModelLink() == null ? null : cf.getForeignKeyModelLink().getName())) {
|
||||||
|
System.out.println("fk model links differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + (of.getForeignKeyModelLink() == null ? null : of.getForeignKeyModelLink().getName()));
|
||||||
|
System.out.println("ac: " + (cf.getForeignKeyModelLink() == null ? null : cf.getForeignKeyModelLink().getName()));
|
||||||
|
}
|
||||||
|
if (!of.getName().equals(cf.getName())) {
|
||||||
|
System.out.println("names differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
System.out.println("ex: " + of.getName());
|
||||||
|
System.out.println("ac: " + cf.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!Objects.equals(of, cf)) {
|
||||||
|
// System.out.println("fields differ: entity " + o.getName() + ", field " + of.getName());
|
||||||
|
// System.out.println("ex: " + of);
|
||||||
|
// System.out.println("ac: " + cf);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects2;
|
||||||
|
@Clazz(clazz = TestClass.class)
|
||||||
|
private DbSet<TestClass> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
public Object o = new Object();
|
||||||
|
@Key
|
||||||
|
public double d;
|
||||||
|
@Index
|
||||||
|
public float f;
|
||||||
|
@Unique
|
||||||
|
public long l;
|
||||||
|
private TestClass previous;
|
||||||
|
private TestClass next;
|
||||||
|
@Clazz(clazz = TestClass.class)
|
||||||
|
private List<TestClass> children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(clazz = TestClass.class)
|
||||||
|
public TestClass o;
|
||||||
|
public TestClass o2;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/test/java/jef/model/ModelBuilderSimpleTest.java
Normal file
43
src/test/java/jef/model/ModelBuilderSimpleTest.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package jef.model;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
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;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class ModelBuilderSimpleTest {
|
||||||
|
@Test
|
||||||
|
public void testClone() {
|
||||||
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
|
assertEquals(1, mb.getEntities().size());
|
||||||
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass.class)
|
||||||
|
private DbSet<TestClass> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@ class ForeignKeyProcessorExposeTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(2, mb.getEntities().size());
|
assertEquals(2, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ForeignKeyProcessorSelfReferenceTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ class ForeignKeyProcessorSimpleTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(2, mb.getEntities().size());
|
assertEquals(2, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
assertEquals(TestClass2.class.getSimpleName(), mb.getEntity(TestClass2.class).getName());
|
assertEquals("objects2", mb.getEntity(TestClass2.class).getName());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
assertTrue(mb.getEntity(TestClass2.class).getFields().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass2.class)));
|
||||||
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
assertTrue(mb.getEntity(TestClass.class).getForeignKeys().stream().allMatch(e -> e.getEntity() == mb.getEntity(TestClass.class)));
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class IndexProcessorClassTest {
|
|||||||
var mb = ModelBuilder.from(CtxIndexOnClass.class);
|
var mb = ModelBuilder.from(CtxIndexOnClass.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isIndex());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isIndex());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isIndex());
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isIndex());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class IndexProcessorFieldTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isIndex());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isIndex());
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isIndex());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isIndex());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class KeyProcessorClassTest {
|
|||||||
var mb = ModelBuilder.from(CtxKeyOnClass.class);
|
var mb = ModelBuilder.from(CtxKeyOnClass.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isKey());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isKey());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isKey());
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isKey());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class KeyProcessorFieldTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isKey());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isKey());
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isKey());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isKey());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class NotNullProcessorTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isNotNull());
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isNotNull());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isNotNull());
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isNotNull());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class UniqueProcessorClassTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isUnique());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isUnique());
|
||||||
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isUnique());
|
assertTrue(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isUnique());
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class UniqueProcessorFieldTest {
|
|||||||
var mb = ModelBuilder.from(Ctx.class);
|
var mb = ModelBuilder.from(Ctx.class);
|
||||||
|
|
||||||
assertEquals(1, mb.getEntities().size());
|
assertEquals(1, mb.getEntities().size());
|
||||||
assertEquals(TestClass.class.getSimpleName(), mb.getEntity(TestClass.class).getName());
|
assertEquals("objects1", mb.getEntity(TestClass.class).getName());
|
||||||
|
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isUnique());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("i")).findFirst().get().isUnique());
|
||||||
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isUnique());
|
assertFalse(mb.getEntity(TestClass.class).getFields().stream().filter(e -> e.getName().equals("d")).findFirst().get().isUnique());
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getOrCreateEntity("AddedEntity");
|
||||||
|
ent.getOrCreateField("id", int.class.getName());
|
||||||
|
ent.getOrCreateField("addedField", int.class.getName());
|
||||||
|
ent.setPrimaryKey(new PrimaryKeyConstraint(ent, List.of(ent.getField("id"))));
|
||||||
|
ent.addForeignKey(new ForeignKeyConstraint(ent, List.of(ent.getField("addedField")), ent, List.of(ent.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").generate().getJava());
|
||||||
|
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(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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").generate().getJava());
|
||||||
|
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(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& o.getReferencedTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("FK_nested_nested_i2"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getEntity(TestClass.class);
|
||||||
|
ent.getField("d").setIndex(true);
|
||||||
|
var mc = new MigrationCreator();
|
||||||
|
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("I_nested_d"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getEntity(TestClass.class);
|
||||||
|
ent.getField("d").setKey(true);
|
||||||
|
var mc = new MigrationCreator();
|
||||||
|
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("K_nested_d"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getEntity(TestClass.class);
|
||||||
|
ent.getField("d").setUnique(true);
|
||||||
|
var mc = new MigrationCreator();
|
||||||
|
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("U_nested_d"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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").generate().getJava());
|
||||||
|
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(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("FK_nested_objects1_nestedI"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& 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("nested"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropTableOperation o
|
||||||
|
&& o.getTable().equals("objects1"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getEntity(TestClass.class);
|
||||||
|
ent.setName("d2");
|
||||||
|
var mc = new MigrationCreator();
|
||||||
|
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& o.getName().equals("FK_nested_objects1_nestedI"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("PRIMARY"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof RenameTableOperation o
|
||||||
|
&& o.getOldName().equals("nested")
|
||||||
|
&& 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("nested"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof AddPrimaryKeyOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& o.getName().equals("FK_nested_nested_iFk"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("PRIMARY"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("U_nested_i"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("K_nested_i"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("I_nested_i"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof RenameFieldOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getOldName().equals("i")
|
||||||
|
&& o.getNewName().equals("i2"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsUp().stream()
|
||||||
|
.filter(e -> e instanceof AddPrimaryKeyOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getReferencedTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getName().equals("FK_nested_nested_iFk"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("PRIMARY"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("U_nested_i2"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("K_nested_i2"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof DropConstraintOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getName().equals("I_nested_i2"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof RenameFieldOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& o.getOldName().equals("i2")
|
||||||
|
&& o.getNewName().equals("i"))
|
||||||
|
.count());
|
||||||
|
assertEquals(1, res.getStepsDown().stream()
|
||||||
|
.filter(e -> e instanceof AddPrimaryKeyOperation o
|
||||||
|
&& o.getTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getReferencedTable().equals("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getFields().size() == 1
|
||||||
|
&& o.getFields().get(0).equals("i"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package jef.model.migration.creator;
|
||||||
|
|
||||||
|
import jef.DbSet;
|
||||||
|
import jef.model.DbContext;
|
||||||
|
import jef.model.ModelBuilder;
|
||||||
|
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.getEntity(TestClass.class);
|
||||||
|
ent.getField("d").setName("d2");
|
||||||
|
var mc = new MigrationCreator();
|
||||||
|
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test").generate().getJava());
|
||||||
|
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("nested")
|
||||||
|
&& 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("nested")
|
||||||
|
&& o.getOldName().equals("d2")
|
||||||
|
&& o.getNewName().equals("d"))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Ctx extends DbContext {
|
||||||
|
@Clazz(clazz = TestClass2.class)
|
||||||
|
private DbSet<TestClass2> objects1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public static class TestClass2 extends SerializableObject {
|
||||||
|
@Id
|
||||||
|
public int i = 1;
|
||||||
|
@Clazz(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
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.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/jef-tests/sources");
|
||||||
|
private static final File CLASS_FILES_DIR = new File("target/jef-tests/classes");
|
||||||
|
|
||||||
|
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 process = new ProcessBuilder()
|
||||||
|
.command("javac", //TODO use javac for current jdk
|
||||||
|
"-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass2");
|
||||||
|
mb.getOrCreateEntity("TestClass2").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass3");
|
||||||
|
mb.getOrCreateEntity("TestClass3").getOrCreateField("i3", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i3", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
var ent = mb.getOrCreateEntity("TestClass");
|
||||||
|
ent.getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
ent.getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
ent.addForeignKey(new ForeignKeyConstraint(ent, List.of(ent.getField("i2")),
|
||||||
|
ent, List.of(ent.getField("i")),
|
||||||
|
ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setIndex(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setKey(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getOrCreateEntity("TestClass"),
|
||||||
|
List.of(mb.getOrCreateEntity("TestClass").getField("i"))));
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setUnique(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass2");
|
||||||
|
mb.getOrCreateEntity("TestClass2").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass3");
|
||||||
|
mb.getOrCreateEntity("TestClass3").getOrCreateField("i3", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i3", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
ent.getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
ent.getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
ent.addForeignKey(new ForeignKeyConstraint(ent, List.of(ent.getField("i2")),
|
||||||
|
ent, List.of(ent.getField("i")),
|
||||||
|
ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setIndex(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setKey(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getOrCreateEntity("TestClass"),
|
||||||
|
List.of(mb.getOrCreateEntity("TestClass").getField("i"))));
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName()).setUnique(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
var mb = new ModelBuilder();
|
||||||
|
mb.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.getOrCreateEntity("TestClass");
|
||||||
|
mb.getOrCreateEntity("TestClass").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass2");
|
||||||
|
mb.getOrCreateEntity("TestClass2").getOrCreateField("i", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
mb.getOrCreateEntity("TestClass2").getOrCreateField("i2", int.class.getName())
|
||||||
|
.setNotNull(true);
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModelBuilder createTo() {
|
||||||
|
return createFrom();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user