refactor migration creator

This commit is contained in:
wea_ondara
2022-11-23 17:22:08 +01:00
parent f0d3948338
commit 3c85ef2c84
15 changed files with 129 additions and 79 deletions

View File

@@ -31,8 +31,8 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class MigrationBuilderGenerator { public class MigrationBuilderGenerator {
private final List<MigrationOperation> opsUp; private final List<? extends MigrationOperation> opsUp;
private final List<MigrationOperation> opsDown; private final List<? extends MigrationOperation> opsDown;
private final String name; private final String name;
private final String packageName; private final String packageName;

View File

@@ -2,7 +2,6 @@ package jef.model.migration.creator;
import jef.model.DbField; import jef.model.DbField;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.constraints.ForeignKeyConstraint; 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;
@@ -21,10 +20,13 @@ import jef.model.migration.operation.MigrationOperation;
import jef.model.migration.operation.RenameFieldOperation; import jef.model.migration.operation.RenameFieldOperation;
import jef.model.migration.operation.RenameTableOperation; import jef.model.migration.operation.RenameTableOperation;
import jef.model.migration.operation.UpdateFieldOperation; import jef.model.migration.operation.UpdateFieldOperation;
import jef.platform.SqlPlatform;
import jef.platform.base.SqlTypeMapper;
import jef.util.Check; import jef.util.Check;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
@@ -33,57 +35,73 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MigrationCreator { public class MigrationCreator {
public Result createMigration(ModelBuilder from, ModelBuilder to, String name, String packageName, String currentSnapshotJava) { private final SqlPlatform sqlPlatform;
var result = new Result(); private final ModelBuilder from;
private final ModelBuilder to;
private final String name;
private final String packageName;
private final String currentSnapshotJava;
private Result result;
public Result createMigration() {
if (result != null) {
return result;
}
result = new Result();
//create pre-migration model snapshot class //create pre-migration model snapshot class
result = generatePreMigrationSnapshot(name, packageName, currentSnapshotJava, result); result = generatePreMigrationSnapshot();
//create migration //create migration
result = generateMigration(from, to, name, packageName, result); result = generateMigration();
//create current model snapshot class //create current model snapshot class
result = generatePostMigrationSnapshot(to, packageName, result); result = generatePostMigrationSnapshot();
return result; return result;
} }
private Result generatePreMigrationSnapshot(String name, String packageName, String currentSnapshotJava, Result result) { private Result generatePreMigrationSnapshot() {
String preMigrationSnapshotClassName = name + "Snapshot";
String preMigrationSnapshot; String preMigrationSnapshot;
if (currentSnapshotJava == null || currentSnapshotJava.isBlank()) { if (currentSnapshotJava == null || currentSnapshotJava.isBlank()) {
preMigrationSnapshot = generateModelBuilderJava(new ModelBuilder(), name, packageName); preMigrationSnapshot = generateModelBuilderJava(new ModelBuilder(), preMigrationSnapshotClassName, packageName, sqlPlatform.getTypeMapper());
} else { } else {
preMigrationSnapshot = currentSnapshotJava.replace("CurrentSnapshot", name + "Snapshot"); preMigrationSnapshot = currentSnapshotJava.replace("CurrentSnapshot", preMigrationSnapshotClassName);
} }
result.setMigrationSnapshotClassName(preMigrationSnapshotClassName);
result.setMigrationSnapshot(preMigrationSnapshot); result.setMigrationSnapshot(preMigrationSnapshot);
return result; return result;
} }
private Result generatePostMigrationSnapshot(ModelBuilder to, String packageName, Result result) { private Result generatePostMigrationSnapshot() {
result.setCurrentSnapshot(generateModelBuilderJava(to, "Current", packageName)); result.setCurrentSnapshotClassName("CurrentSnapshot");
result.setCurrentSnapshot(generateModelBuilderJava(to, "CurrentSnapshot", packageName, sqlPlatform.getTypeMapper()));
return result; return result;
} }
private String generateModelBuilderJava(ModelBuilder mb, String name, String packageName) { private String generateModelBuilderJava(ModelBuilder mb, String name, String packageName, SqlTypeMapper typeMapper) {
return new ModelBuilderGenerator(mb, name, packageName, new SqlTypeMapper()).generate().getJava();//TODO mapper return new ModelBuilderGenerator(mb, name, packageName, typeMapper).generate().getJava();
} }
private Result generateMigration(ModelBuilder from, ModelBuilder to, String name, String packageName, Result result) { private Result generateMigration() {
//reduce model builders to changes //reduce model builders to changes
var mcd = new ModelChangeDetector(from, to).detect(); var mcd = new ModelChangeDetector(from, to).detect();
var fromReduced = mcd.getFrom(); var fromReduced = mcd.getFrom();
var toReduced = mcd.getTo(); var toReduced = mcd.getTo();
//create migration steps //create migration steps
var migrationUpOps = new ArrayList<MigrationOperation.Builder>(); var migrationUpOps = new ArrayList<MigrationOperation.Builder<?>>();
var migrationDownOps = new ArrayList<MigrationOperation.Builder>(); var migrationDownOps = new ArrayList<MigrationOperation.Builder<?>>();
generateMigrationSteps(fromReduced, toReduced, from, to, migrationUpOps); generateMigrationSteps(fromReduced, toReduced, from, to, migrationUpOps);
generateMigrationSteps(toReduced, fromReduced, to, from, migrationDownOps); generateMigrationSteps(toReduced, fromReduced, to, from, migrationDownOps);
var builtUpOps = migrationUpOps.stream().map(e -> e.build()).toList(); var builtUpOps = migrationUpOps.stream().map(MigrationOperation.Builder::build).toList();
var builtDownOps = migrationDownOps.stream().map(e -> e.build()).toList(); var builtDownOps = migrationDownOps.stream().map(MigrationOperation.Builder::build).toList();
result.setMigrationClassName(name);
result.setMigration(new MigrationBuilderGenerator(builtUpOps, builtDownOps, name, packageName).generate().getJava()); result.setMigration(new MigrationBuilderGenerator(builtUpOps, builtDownOps, name, packageName).generate().getJava());
result.setStepsUp(builtUpOps); result.setStepsUp(builtUpOps);
result.setStepsDown(builtDownOps); result.setStepsDown(builtDownOps);
@@ -91,7 +109,7 @@ public class MigrationCreator {
return result; return result;
} }
private void generateMigrationSteps(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void generateMigrationSteps(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
//key drop //key drop
addForeignKeyDropGeneration(fromReduced, toReduced, from, to, steps); addForeignKeyDropGeneration(fromReduced, toReduced, from, to, steps);
addPrimaryKeyDropGeneration(fromReduced, toReduced, from, to, steps); addPrimaryKeyDropGeneration(fromReduced, toReduced, from, to, steps);
@@ -115,7 +133,7 @@ public class MigrationCreator {
addIndexAddGeneration(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) { private void addTableAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntity(toEntity.getTypeName()); var fromEntity = fromReduced.getEntity(toEntity.getTypeName());
@@ -138,7 +156,7 @@ public class MigrationCreator {
return Optional.ofNullable(e.getSqlType()).or(() -> new SqlTypeMapper().map(e.getTypeName())).orElse(null); return Optional.ofNullable(e.getSqlType()).or(() -> new SqlTypeMapper().map(e.getTypeName())).orElse(null);
} }
private void addTableRenameGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addTableRenameGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntity(toEntity.getTypeName()); var fromEntity = fromReduced.getEntity(toEntity.getTypeName());
// entity added // entity added
@@ -153,7 +171,7 @@ public class MigrationCreator {
} }
} }
private void addTableDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addTableDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var toEntity = toReduced.getEntity(fromEntity.getTypeName()); var toEntity = toReduced.getEntity(fromEntity.getTypeName());
if (toEntity == null) { if (toEntity == null) {
@@ -162,7 +180,7 @@ public class MigrationCreator {
} }
} }
private void addFieldAddRenameUpdateDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addFieldAddRenameUpdateDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var fromEntity = fromReduced.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var fromEntity = fromReduced.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
@@ -239,7 +257,7 @@ public class MigrationCreator {
} }
} }
private void addPrimaryKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addPrimaryKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -255,7 +273,7 @@ public class MigrationCreator {
} }
} }
private void addForeignKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addForeignKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -275,7 +293,7 @@ public class MigrationCreator {
} }
} }
private void addUniqueKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addUniqueKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -292,7 +310,7 @@ public class MigrationCreator {
} }
} }
private void addKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addKeyAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -309,7 +327,7 @@ public class MigrationCreator {
} }
} }
private void addIndexAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addIndexAddGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var toEntity : toReduced.getEntities()) { for (var toEntity : toReduced.getEntities()) {
var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null); var originalEntity = to.getEntities().stream().filter(e -> e.getName().equals(toEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -326,7 +344,7 @@ public class MigrationCreator {
} }
} }
private void addPrimaryKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addPrimaryKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null); var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -348,7 +366,7 @@ public class MigrationCreator {
} }
} }
private void addForeignKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addForeignKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null); var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -373,7 +391,7 @@ public class MigrationCreator {
// } // }
} }
private void addUniqueKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addUniqueKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null); var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -398,7 +416,7 @@ public class MigrationCreator {
// } // }
} }
private void addKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addKeyDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null); var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -423,7 +441,7 @@ public class MigrationCreator {
// } // }
} }
private void addIndexDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder> steps) { private void addIndexDropGeneration(ModelBuilder fromReduced, ModelBuilder toReduced, ModelBuilder from, ModelBuilder to, List<MigrationOperation.Builder<?>> steps) {
for (var fromEntity : fromReduced.getEntities()) { for (var fromEntity : fromReduced.getEntities()) {
var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null); var originalEntity = from.getEntities().stream().filter(e -> e.getName().equals(fromEntity.getName())).findFirst().orElse(null);
Check.notNull(originalEntity, "originalEntity"); //may never be null Check.notNull(originalEntity, "originalEntity"); //may never be null
@@ -452,11 +470,14 @@ public class MigrationCreator {
@Setter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE) @NoArgsConstructor(access = AccessLevel.PACKAGE)
public static class Result { public static class Result {
private List<MigrationOperation> stepsUp = new ArrayList<>(); private List<? extends MigrationOperation> stepsUp = new ArrayList<>();
private List<MigrationOperation> stepsDown = new ArrayList<>(); private List<? extends MigrationOperation> stepsDown = new ArrayList<>();
private String migration = ""; private String migration = "";
private String migrationClassName = "";
private String migrationSnapshot = ""; private String migrationSnapshot = "";
private String migrationSnapshotClassName = "";
private String currentSnapshot = ""; private String currentSnapshot = "";
private String currentSnapshotClassName = "";
} }
@Getter @Getter

View File

@@ -3,7 +3,6 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint; import jef.model.constraints.ForeignKeyConstraint;
@@ -13,6 +12,7 @@ import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation; import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropTableOperation; import jef.model.migration.operation.DropTableOperation;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -31,8 +31,10 @@ public class MigrationCreatorAddEntityTest extends MigrationCreatorTestBase {
ent.field("addedField", int.class.getName()); ent.field("addedField", int.class.getName());
to.getEntity("AddedEntity").setPrimaryKey(new PrimaryKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id")))); to.getEntity("AddedEntity").setPrimaryKey(new PrimaryKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id"))));
to.getEntity("AddedEntity").addForeignKey(new ForeignKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("addedField")), to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id")), ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE)); to.getEntity("AddedEntity").addForeignKey(new ForeignKeyConstraint(to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("addedField")), to.getEntity("AddedEntity"), List.of(to.getEntity("AddedEntity").getField("id")), ForeignKeyConstraint.Action.CASCADE, ForeignKeyConstraint.Action.CASCADE));
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,7 +3,6 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint; import jef.model.constraints.ForeignKeyConstraint;
@@ -11,6 +10,8 @@ import jef.model.migration.operation.AddFieldOperation;
import jef.model.migration.operation.AddForeignKeyOperation; import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropFieldOperation; import jef.model.migration.operation.DropFieldOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -19,7 +20,7 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddFieldTest extends MigrationCreatorTestBase{ public class MigrationCreatorAddFieldTest extends MigrationCreatorTestBase {
@Test @Test
public void test() { public void test() {
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
@@ -27,8 +28,10 @@ public class MigrationCreatorAddFieldTest extends MigrationCreatorTestBase{
var ent = to.getEntity(TestClass2.class); var ent = to.getEntity(TestClass2.class);
ent.getOrCreateField("addedField", int.class.getName()); 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)); 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 platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,12 +3,13 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.constraints.ForeignKeyConstraint; import jef.model.constraints.ForeignKeyConstraint;
import jef.model.migration.operation.AddForeignKeyOperation; import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -24,8 +25,10 @@ public class MigrationCreatorAddForeignKeyTest extends MigrationCreatorTestBase
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.getEntity(TestClass.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)); 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 platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,11 +3,12 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.AddIndexOperation; import jef.model.migration.operation.AddIndexOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -16,15 +17,17 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddIndexTest extends MigrationCreatorTestBase{ public class MigrationCreatorAddIndexTest extends MigrationCreatorTestBase {
@Test @Test
public void test() { public void test() {
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class); var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isIndex(true); ent.field("d", double.class.getName()).isIndex(true);
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,11 +3,12 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.AddKeyOperation; import jef.model.migration.operation.AddKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -16,15 +17,17 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddKeyTest extends MigrationCreatorTestBase{ public class MigrationCreatorAddKeyTest extends MigrationCreatorTestBase {
@Test @Test
public void test() { public void test() {
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class); var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isKey(true); ent.field("d", double.class.getName()).isKey(true);
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,11 +3,12 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.AddUniqueKeyOperation; import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -16,15 +17,17 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorAddUniqueTest extends MigrationCreatorTestBase{ public class MigrationCreatorAddUniqueTest extends MigrationCreatorTestBase {
@Test @Test
public void test() { public void test() {
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class); var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).isUnique(true); ent.field("d", double.class.getName()).isUnique(true);
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,12 +3,13 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.annotations.Index; import jef.model.annotations.Index;
import jef.model.annotations.Key; import jef.model.annotations.Key;
import jef.model.annotations.Unique; import jef.model.annotations.Unique;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -17,13 +18,15 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class MigrationCreatorEmptyTest extends MigrationCreatorTestBase{ public class MigrationCreatorEmptyTest extends MigrationCreatorTestBase {
@Test @Test
public void test() { public void test() {
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "EmptyMigration", "test",new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "EmptyMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
assertEquals(0, res.getStepsUp().size()); assertEquals(0, res.getStepsUp().size());
assertEquals(0, res.getStepsDown().size()); assertEquals(0, res.getStepsDown().size());

View File

@@ -3,7 +3,6 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.AddForeignKeyOperation; import jef.model.migration.operation.AddForeignKeyOperation;
@@ -11,6 +10,7 @@ import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddTableOperation; import jef.model.migration.operation.AddTableOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.DropTableOperation; import jef.model.migration.operation.DropTableOperation;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -24,8 +24,10 @@ public class MigrationCreatorInitialMigrationTest extends MigrationCreatorTestBa
public void test() { public void test() {
var from = new ModelBuilder(List.of()); var from = new ModelBuilder(List.of());
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "InitialMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "InitialMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,13 +3,14 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.AddForeignKeyOperation; import jef.model.migration.operation.AddForeignKeyOperation;
import jef.model.migration.operation.AddPrimaryKeyOperation; import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.RenameTableOperation; import jef.model.migration.operation.RenameTableOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -25,8 +26,10 @@ public class MigrationCreatorRenameEntityTest extends MigrationCreatorTestBase {
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class); var ent = to.entity(TestClass.class);
ent.name("d2"); ent.name("d2");
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,7 +3,6 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.ForeignKey; import jef.model.annotations.ForeignKey;
import jef.model.annotations.Id; import jef.model.annotations.Id;
@@ -17,6 +16,8 @@ import jef.model.migration.operation.AddPrimaryKeyOperation;
import jef.model.migration.operation.AddUniqueKeyOperation; import jef.model.migration.operation.AddUniqueKeyOperation;
import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropConstraintOperation;
import jef.model.migration.operation.RenameFieldOperation; import jef.model.migration.operation.RenameFieldOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -31,8 +32,10 @@ public class MigrationCreatorRenameFieldConstraintsTest extends MigrationCreator
var from = ModelBuilder.from(Ctx.class); var from = ModelBuilder.from(Ctx.class);
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
to.getEntity(TestClass.class).getField("i").setName("i2"); to.getEntity(TestClass.class).getField("i").setName("i2");
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -3,10 +3,11 @@ package jef.model.migration.creator;
import jef.DbSet; import jef.DbSet;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.SqlTypeMapper;
import jef.model.annotations.Clazz; import jef.model.annotations.Clazz;
import jef.model.annotations.Id; import jef.model.annotations.Id;
import jef.model.migration.operation.RenameFieldOperation; import jef.model.migration.operation.RenameFieldOperation;
import jef.platform.base.SqlTypeMapper;
import jef.platform.nul.NullPlatform;
import jef.serializable.SerializableObject; import jef.serializable.SerializableObject;
import lombok.Getter; import lombok.Getter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -22,8 +23,10 @@ public class MigrationCreatorRenameFieldTest extends MigrationCreatorTestBase {
var to = ModelBuilder.from(Ctx.class); var to = ModelBuilder.from(Ctx.class);
var ent = to.entity(TestClass.class); var ent = to.entity(TestClass.class);
ent.field("d", double.class.getName()).name("d2"); ent.field("d", double.class.getName()).name("d2");
var mc = new MigrationCreator(); var platform = new NullPlatform();
var res = mc.createMigration(from, to, "SomeMigration", "test", new ModelBuilderGenerator(from, "Current", "test", new SqlTypeMapper()).generate().getJava());//TODO mapper var mc = new MigrationCreator(platform, from, to, "SomeMigration", "test",
new ModelBuilderGenerator(from, "Current", "test", platform.getTypeMapper()).generate().getJava());
var res = mc.createMigration();
try { try {
validateUp(res); validateUp(res);
validateDown(res); validateDown(res);

View File

@@ -2,7 +2,6 @@ package jef.model.migration.creator;
import jef.model.DbContext; import jef.model.DbContext;
import jef.model.ModelBuilder; import jef.model.ModelBuilder;
import jef.model.ModelBuilderCloneTest;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
@@ -48,7 +47,6 @@ public class MigrationCreatorTestBase {
compile(packageName, className, snapshotJava); compile(packageName, className, snapshotJava);
var clazz = (Class<? extends DbContext>) loadClass(packageName, className); var clazz = (Class<? extends DbContext>) loadClass(packageName, className);
var mb = ModelBuilder.from(clazz); var mb = ModelBuilder.from(clazz);
ModelBuilderCloneTest.debugHelper(from, mb);
assertEquals(from, mb); assertEquals(from, mb);
} catch (AssertionError | RuntimeException e) { } catch (AssertionError | RuntimeException e) {
throw e; throw e;
@@ -88,7 +86,7 @@ public class MigrationCreatorTestBase {
var javac = new File(javaHome, "bin/javac" + (isWindows ? ".exe" : "")); var javac = new File(javaHome, "bin/javac" + (isWindows ? ".exe" : ""));
var process = new ProcessBuilder() var process = new ProcessBuilder()
.command(javac.getAbsolutePath(), .command(javac.getAbsolutePath(),
"-cp", "target/classes" + File.pathSeparator + "target/test-classes", "-cp", "target/classes" + File.pathSeparator + "target/test-classes" + File.pathSeparator + "../core/target/classes",
"-encoding", "UTF8", "-encoding", "UTF8",
"-g", //debug symbols "-g", //debug symbols
"-d", destdir.getPath(), //target "-d", destdir.getPath(), //target

View File

@@ -42,7 +42,7 @@ class ModelChangeDetectorAddPrimaryKeyTest {
mb.entity("TestClass").field("i2", int.class.getName()) mb.entity("TestClass").field("i2", int.class.getName())
.isNotNull(true); .isNotNull(true);
mb.getEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getEntity("TestClass"), mb.getEntity("TestClass").setPrimaryKey(new PrimaryKeyConstraint(mb.getEntity("TestClass"),
List.of(mb.getEntity("TestClass").getField("i")))); List.of(mb.getEntity("TestClass").getField("i"))));
return mb; return mb;
} }
} }