diff --git a/core/src/main/java/jef/platform/base/DatabaseOptions.java b/core/src/main/java/jef/platform/base/DatabaseOptions.java index 20c989a..05423df 100644 --- a/core/src/main/java/jef/platform/base/DatabaseOptions.java +++ b/core/src/main/java/jef/platform/base/DatabaseOptions.java @@ -12,11 +12,12 @@ public class DatabaseOptions { protected final String password; protected final String migrationsPackage; + protected final String migrationsTableName; protected final String host; protected final String database; - public DatabaseOptions(String url, String user, String password, String migrationsPackage) { + public DatabaseOptions(String url, String user, String password, String migrationsPackage, String migrationsTableName) { this.url = url; this.user = user; this.password = password; @@ -24,6 +25,7 @@ public class DatabaseOptions { host = extractHost(url); database = extractDatabase(url); this.migrationsPackage = migrationsPackage; + this.migrationsTableName = migrationsTableName == null || migrationsTableName.isBlank() ? "__jef_migration_log" : migrationsTableName; } private static String extractHost(String url) { diff --git a/core/src/main/java/jef/platform/base/migration/M00010101000000_MigrationsLogTableMigration.java b/core/src/main/java/jef/platform/base/migration/M00010101000000_MigrationsLogTableMigration.java new file mode 100644 index 0000000..5efbca5 --- /dev/null +++ b/core/src/main/java/jef/platform/base/migration/M00010101000000_MigrationsLogTableMigration.java @@ -0,0 +1,32 @@ +package jef.platform.base.migration; + +import jef.model.migration.Migration; +import jef.model.migration.MigrationBuilder; +import jef.model.migration.operation.AddFieldOperation; +import jef.platform.base.SqlTypeMapper; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@AllArgsConstructor +@EqualsAndHashCode//needed for test +public class M00010101000000_MigrationsLogTableMigration implements Migration { + private final SqlTypeMapper typeMapper; + private final String tableName; + + @Override + public void up(MigrationBuilder migrationBuilder) {//TODO add timestamp later + migrationBuilder.addTable(tableName, List.of( + new AddFieldOperation.Builder(tableName, "migration").notNull(true).sqlType(typeMapper.map(String.class.getName()).orElseThrow()), + new AddFieldOperation.Builder(tableName, "version").notNull(true).sqlType(typeMapper.map(String.class.getName()).orElseThrow()) + )); + migrationBuilder.addUniqueKey("U_" + tableName + "_migration", tableName, List.of("migration")); + } + + @Override + public void down(MigrationBuilder migrationBuilder) { + migrationBuilder.dropConstraint("U_" + tableName + "_migration", tableName); + migrationBuilder.dropTable(tableName); + } +} diff --git a/core/src/main/java/jef/platform/base/migration/MigrationApplier.java b/core/src/main/java/jef/platform/base/migration/MigrationApplier.java index fdbb974..a29c895 100644 --- a/core/src/main/java/jef/platform/base/migration/MigrationApplier.java +++ b/core/src/main/java/jef/platform/base/migration/MigrationApplier.java @@ -121,7 +121,9 @@ public abstract class MigrationApplier { protected abstract boolean migrationsTableExists() throws SQLException; - protected abstract void createMigrationsTable() throws SQLException;//TODO use a hardcoded migration + protected void createMigrationsTable() throws MigrationException { + applyMigration(new M00010101000000_MigrationsLogTableMigration(sqlPlatform.getTypeMapper(), options.getMigrationsTableName())); + } protected abstract List getAppliedMigrations() throws SQLException;//TODO dbset to load later diff --git a/core/src/main/java/jef/platform/nul/migration/NullMigrationApplier.java b/core/src/main/java/jef/platform/nul/migration/NullMigrationApplier.java index 1838362..a8b7785 100644 --- a/core/src/main/java/jef/platform/nul/migration/NullMigrationApplier.java +++ b/core/src/main/java/jef/platform/nul/migration/NullMigrationApplier.java @@ -29,7 +29,7 @@ public class NullMigrationApplier extends MigrationApplier { } @Override - protected void createMigrationsTable() throws SQLException { + protected void createMigrationsTable() throws MigrationException { } @Override diff --git a/core/src/test/java/jef/platform/base/migration/MigrationApplierTest.java b/core/src/test/java/jef/platform/base/migration/MigrationApplierTest.java index 37f2c90..30c0ac8 100644 --- a/core/src/test/java/jef/platform/base/migration/MigrationApplierTest.java +++ b/core/src/test/java/jef/platform/base/migration/MigrationApplierTest.java @@ -6,6 +6,7 @@ import jef.model.migration.MigrationBuilder; import jef.model.migration.operation.MigrationOperation; import jef.platform.SqlPlatform; import jef.platform.base.DatabaseOptions; +import jef.platform.base.SqlTypeMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -347,5 +348,52 @@ class MigrationApplierTest { //assert + }//TODO after function rewrite + + @Test + void createMigrationsTable_success() throws MigrationException { + //setup + var mapper = mock(SqlTypeMapper.class); + doReturn(mapper).when(platform).getTypeMapper(); + + var migrationTableName = "migrationtable"; + doReturn(migrationTableName).when(options).getMigrationsTableName(); + doNothing().when(applier).applyMigration(new M00010101000000_MigrationsLogTableMigration(mapper, migrationTableName)); + + //test + applier.createMigrationsTable(); + + //assert + verify(applier, times(1)).createMigrationsTable(); + verify(platform, times(1)).getTypeMapper(); + verify(options, times(1)).getMigrationsTableName(); + verify(applier, times(1)).applyMigration(new M00010101000000_MigrationsLogTableMigration(mapper, migrationTableName)); + verifyNoMoreInteractions(allMocks); + } + + @Test + void createMigrationsTable_applyMigrationThrowsMigrationException() throws MigrationException { + //setup + var mapper = mock(SqlTypeMapper.class); + doReturn(mapper).when(platform).getTypeMapper(); + + var migrationTableName = "migrationtable"; + doReturn(migrationTableName).when(options).getMigrationsTableName(); + + var exception = new MigrationException("reason"); + doThrow(exception).when(applier).applyMigration(new M00010101000000_MigrationsLogTableMigration(mapper, migrationTableName)); + + //test + var thrown = assertThrows(MigrationException.class, () -> applier.createMigrationsTable()); + + //assert + assertSame(exception, thrown); + + verify(applier, times(1)).createMigrationsTable(); + verify(platform, times(1)).getTypeMapper(); + verify(options, times(1)).getMigrationsTableName(); + verify(applier, times(1)).applyMigration(new M00010101000000_MigrationsLogTableMigration(mapper, migrationTableName)); + verifyNoMoreInteractions(allMocks); + } } \ No newline at end of file diff --git a/core/src/test/java/jef/platform/nul/migration/NullMigrationApplierTest.java b/core/src/test/java/jef/platform/nul/migration/NullMigrationApplierTest.java index f725829..86a4c56 100644 --- a/core/src/test/java/jef/platform/nul/migration/NullMigrationApplierTest.java +++ b/core/src/test/java/jef/platform/nul/migration/NullMigrationApplierTest.java @@ -44,7 +44,7 @@ class NullMigrationApplierTest { } @Test - void createMigrationsTable() throws SQLException { + void createMigrationsTable() throws MigrationException { NullMigrationApplier.INSTANCE.createMigrationsTable(); } diff --git a/mysql/src/main/java/jef/platform/mysql/migration/MysqlMigrationApplier.java b/mysql/src/main/java/jef/platform/mysql/migration/MysqlMigrationApplier.java index 9a546ef..b93579d 100644 --- a/mysql/src/main/java/jef/platform/mysql/migration/MysqlMigrationApplier.java +++ b/mysql/src/main/java/jef/platform/mysql/migration/MysqlMigrationApplier.java @@ -1,12 +1,8 @@ package jef.platform.mysql.migration; -import jef.platform.base.DatabaseOptions; import jef.model.migration.Migration; -import jef.model.migration.operation.AddFieldOperation; -import jef.model.migration.operation.AddTableOperation; -import jef.model.migration.operation.AddUniqueKeyOperation; -import jef.model.migration.operation.MigrationOperation; import jef.platform.SqlPlatform; +import jef.platform.base.DatabaseOptions; import jef.platform.base.migration.MigrationApplier; import java.sql.Connection; @@ -21,7 +17,7 @@ public class MysqlMigrationApplier extends MigrationApplier { @Override protected void insertMigrationLog(Migration m) throws SQLException { - try (var stmt = connection.prepareStatement("INSERT INTO `__jef_migration_log` (`name`, `version`) VALUES (?, ?)")) {//TODO configurable log table name + try (var stmt = connection.prepareStatement("INSERT INTO `" + options.getMigrationsTableName() + "` (`name`, `version`) VALUES (?, ?)")) {//TODO configurable log table name stmt.setString(1, m.getClass().getSimpleName()); stmt.setString(2, "0.1"); //TODO insert actual library version stmt.executeUpdate(); @@ -33,7 +29,7 @@ public class MysqlMigrationApplier extends MigrationApplier { try (var stmt = connection.prepareStatement("SHOW TABLES"); var res = stmt.executeQuery()) { while (res.next()) { - if (res.getString(1).equals("__jef_migration_log")) { + if (res.getString(1).equals(options.getMigrationsTableName())) { return true; } } @@ -41,23 +37,6 @@ public class MysqlMigrationApplier extends MigrationApplier { return false; } - @Override - protected void createMigrationsTable() throws SQLException { - var table = "__jef_migration_log"; - var ops = List.of( - new AddTableOperation.Builder(table, List.of( - new AddFieldOperation.Builder(table, "name").notNull(true).sqlType("VARCHAR(255)"), - new AddFieldOperation.Builder(table, "version").notNull(true).sqlType("VARCHAR(255)") - )), - new AddUniqueKeyOperation.Builder("U_" + table + "_name", table, List.of("name")) - ); - for (MigrationOperation.Builder e : ops) { - try (var stmt = sqlPlatform.getTranslator().translate(connection, e.build())) { - stmt.executeUpdate(); - } - } - } - @Override protected List getAppliedMigrations() throws SQLException { var ret = new ArrayList(); @@ -65,11 +44,11 @@ public class MysqlMigrationApplier extends MigrationApplier { return ret; } - try (var stmt = connection.prepareStatement("SELECT `name` FROM `__jef_migration_log`"); + try (var stmt = connection.prepareStatement("SELECT `migration` FROM `" + options.getMigrationsTableName() + "`"); var res = stmt.executeQuery()) { while (res.next()) { - if (res.getString(1).equals("__jef_migration_log")) { - ret.add(res.getString("name")); + if (!res.getString(1).equals(options.getMigrationsTableName())) { + ret.add(res.getString("migration")); } } } diff --git a/mysql/src/test/java/jef/platform/mysql/migration/MysqlMigrationTest.java b/mysql/src/test/java/jef/platform/mysql/migration/MysqlMigrationTest.java index 36fec12..320b9e5 100644 --- a/mysql/src/test/java/jef/platform/mysql/migration/MysqlMigrationTest.java +++ b/mysql/src/test/java/jef/platform/mysql/migration/MysqlMigrationTest.java @@ -46,7 +46,7 @@ public class MysqlMigrationTest { generateInitialMigration(); compileInitialMigration(); Class.forName("com.mysql.cj.jdbc.Driver").getDeclaredConstructor().newInstance(); - var dboptions = new DatabaseOptions("jdbc:mysql://localhost/test", "test", "password", getClass().getSimpleName()); + var dboptions = new DatabaseOptions("jdbc:mysql://localhost/test", "test", "password", getClass().getSimpleName(), null); var ctxoptions = new DbContextOptions(dboptions); var conn = DriverManager.getConnection(dboptions.getUrl(), dboptions.getUser(), dboptions.getPassword()); var sqlPlatform = new MysqlPlatform();