Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe
Commits:
-
68742cce
by Tony Chemit at 2022-10-27T14:54:14+02:00
12 changed files:
- core/persistence/test/src/test/java/org/nuiton/topia/persistence/jdbc/JdbcHelperH2Test.java
- core/persistence/test/src/test/java/org/nuiton/topia/persistence/jdbc/JdbcSecurityHelperH2Test.java
- core/persistence/test/src/test/java/org/nuiton/topia/persistence/security/SecurityScriptHelperTest.java
- toolkit/persistence/src/main/java/org/nuiton/topia/persistence/jdbc/JdbcHelper.java
- toolkit/persistence/src/main/java/org/nuiton/topia/persistence/jdbc/JdbcSecurityHelper.java
- toolkit/persistence/src/main/java/org/nuiton/topia/persistence/jdbc/JdbcSecurityHelperH2.java
- toolkit/persistence/src/main/java/org/nuiton/topia/persistence/jdbc/JdbcSecurityHelperPostgres.java
- toolkit/persistence/src/main/java/org/nuiton/topia/service/migration/TopiaMigrationServiceContext.java
- toolkit/persistence/src/main/java/org/nuiton/topia/service/migration/TopiaMigrationServiceImpl.java
- toolkit/persistence/src/main/java/org/nuiton/topia/service/migration/version/MigrationServiceSqlHelper.java
- toolkit/persistence/src/main/java/org/nuiton/topia/service/migration/version/TMSVersion.java
- toolkit/persistence/src/main/java/org/nuiton/topia/service/sql/internal/consumer/AddVersionTableConsumer.java
Changes:
| ... | ... | @@ -30,6 +30,7 @@ import org.junit.Assert; |
| 30 | 30 | import org.junit.Before;
|
| 31 | 31 | import org.junit.ClassRule;
|
| 32 | 32 | import org.junit.Test;
|
| 33 | +import org.nuiton.topia.service.migration.version.MigrationServiceSqlHelper;
|
|
| 33 | 34 | |
| 34 | 35 | import java.sql.SQLException;
|
| 35 | 36 | |
| ... | ... | @@ -54,20 +55,17 @@ public class JdbcHelperH2Test extends PersistenceTestSupportWrite { |
| 54 | 55 | |
| 55 | 56 | @Test
|
| 56 | 57 | public void isTableExist() throws SQLException {
|
| 57 | - boolean actual = jdbcHelper.isTableExist("Public", "Tms_version");
|
|
| 58 | - Assert.assertTrue(actual);
|
|
| 58 | + Assert.assertTrue(jdbcHelper.isTableExist(MigrationServiceSqlHelper.CURRENT.schemaName(), MigrationServiceSqlHelper.CURRENT.tableName()));
|
|
| 59 | + Assert.assertTrue(jdbcHelper.isTableExist(MigrationServiceSqlHelper.CURRENT.schemaName().toUpperCase(), MigrationServiceSqlHelper.CURRENT.tableName()));
|
|
| 60 | + Assert.assertTrue(jdbcHelper.isTableExist(MigrationServiceSqlHelper.CURRENT.schemaName().toUpperCase(), MigrationServiceSqlHelper.CURRENT.tableName().toUpperCase()));
|
|
| 59 | 61 | |
| 60 | - actual = jdbcHelper.isTableExist("PUBLIC", "tms_version-fake");
|
|
| 61 | - Assert.assertFalse(actual);
|
|
| 62 | + Assert.assertFalse(jdbcHelper.isTableExist(MigrationServiceSqlHelper.CURRENT.schemaName(), MigrationServiceSqlHelper.CURRENT.tableName()+"-Fake"));
|
|
| 62 | 63 | }
|
| 63 | 64 | |
| 64 | 65 | @Test
|
| 65 | 66 | public void isSchemaExist() throws SQLException {
|
| 66 | - boolean actual = jdbcHelper.isSchemaExist("Public");
|
|
| 67 | - Assert.assertTrue(actual);
|
|
| 68 | - |
|
| 69 | - actual = jdbcHelper.isSchemaExist("PUBLIC-fake");
|
|
| 70 | - Assert.assertFalse(actual);
|
|
| 67 | + Assert.assertTrue(jdbcHelper.isSchemaExist("Public"));
|
|
| 68 | + Assert.assertFalse(jdbcHelper.isSchemaExist("PUBLIC-fake"));
|
|
| 71 | 69 | }
|
| 72 | 70 | |
| 73 | 71 | } |
| ... | ... | @@ -31,6 +31,7 @@ import org.junit.Assert; |
| 31 | 31 | import org.junit.Before;
|
| 32 | 32 | import org.junit.ClassRule;
|
| 33 | 33 | import org.junit.Test;
|
| 34 | +import org.nuiton.topia.service.migration.version.MigrationServiceSqlHelper;
|
|
| 34 | 35 | |
| 35 | 36 | import java.util.List;
|
| 36 | 37 | import java.util.Set;
|
| ... | ... | @@ -62,10 +63,9 @@ public class JdbcSecurityHelperH2Test extends PersistenceTestSupportWrite { |
| 62 | 63 | Assert.assertNotNull(actual);
|
| 63 | 64 | Assert.assertEquals(0, actual.size());
|
| 64 | 65 | |
| 65 | - actual = securityHelper.getTables(Set.of("PUbLIC"), Set.of());
|
|
| 66 | + actual = securityHelper.getTables(Set.of(MigrationServiceSqlHelper.CURRENT.schemaName()), Set.of());
|
|
| 66 | 67 | Assert.assertNotNull(actual);
|
| 67 | - Assert.assertEquals(1, actual.size());
|
|
| 68 | - Assert.assertEquals(List.of(Pair.of("PUBLIC", "TMS_VERSION")), actual);
|
|
| 68 | + Assert.assertTrue(actual.contains(Pair.of(MigrationServiceSqlHelper.CURRENT.schemaName().toUpperCase(), MigrationServiceSqlHelper.CURRENT.tableName().toUpperCase())));
|
|
| 69 | 69 | }
|
| 70 | 70 | |
| 71 | 71 | @Test
|
| ... | ... | @@ -90,7 +90,7 @@ public class JdbcSecurityHelperH2Test extends PersistenceTestSupportWrite { |
| 90 | 90 | |
| 91 | 91 | @Test
|
| 92 | 92 | public void getTablePrivileges() {
|
| 93 | - Set<String> actual = securityHelper.getTablePrivileges("PUbLIC", "Tms_VERSION");
|
|
| 93 | + Set<String> actual = securityHelper.getTablePrivileges(MigrationServiceSqlHelper.CURRENT.schemaName(), MigrationServiceSqlHelper.CURRENT.tableName());
|
|
| 94 | 94 | Assert.assertNotNull(actual);
|
| 95 | 95 | Assert.assertEquals(0, actual.size());
|
| 96 | 96 | }
|
| ... | ... | @@ -37,6 +37,7 @@ import org.junit.ClassRule; |
| 37 | 37 | import org.junit.Test;
|
| 38 | 38 | import org.nuiton.topia.persistence.jdbc.JdbcHelper;
|
| 39 | 39 | import org.nuiton.topia.persistence.jdbc.JdbcSecurityHelper;
|
| 40 | +import org.nuiton.topia.service.migration.version.MigrationServiceSqlHelper;
|
|
| 40 | 41 | |
| 41 | 42 | import java.sql.SQLException;
|
| 42 | 43 | import java.util.Map;
|
| ... | ... | @@ -92,7 +93,7 @@ public class SecurityScriptHelperTest extends PersistenceTestSupportWrite { |
| 92 | 93 | SecurityScriptHelper securityScriptHelper = localTestMethodResource.getTopiaApplicationContext().newSecurityScriptHelper();
|
| 93 | 94 | securityScriptHelper.applySecurity(users);
|
| 94 | 95 | |
| 95 | - Set<String> actual = securityHelper.getTablePrivileges("PUBLIC", "TMS_VERSION");
|
|
| 96 | + Set<String> actual = securityHelper.getTablePrivileges(MigrationServiceSqlHelper.CURRENT.schemaName().toUpperCase(), MigrationServiceSqlHelper.CURRENT.tableName().toUpperCase());
|
|
| 96 | 97 | Assert.assertNotNull(actual);
|
| 97 | 98 | Assert.assertEquals(4, actual.size());
|
| 98 | 99 | Assert.assertEquals(Set.of("DELETE", "INSERT", "UPDATE", "SELECT"), actual);
|
| ... | ... | @@ -34,6 +34,8 @@ import java.sql.DriverManager; |
| 34 | 34 | import java.sql.PreparedStatement;
|
| 35 | 35 | import java.sql.ResultSet;
|
| 36 | 36 | import java.sql.SQLException;
|
| 37 | +import java.util.LinkedList;
|
|
| 38 | +import java.util.List;
|
|
| 37 | 39 | import java.util.Objects;
|
| 38 | 40 | |
| 39 | 41 | /**
|
| ... | ... | @@ -116,17 +118,38 @@ public abstract class JdbcHelper { |
| 116 | 118 | }
|
| 117 | 119 | |
| 118 | 120 | public String runSelectOnString(String sql) throws SQLException {
|
| 119 | - return runSelect(sql, resultSet -> resultSet.next() ? resultSet.getString(1) : null);
|
|
| 121 | + return runSelect(sql, resultSet -> resultSet.getString(1));
|
|
| 120 | 122 | }
|
| 121 | 123 | |
| 122 | 124 | public <T> T runSelect(String sql, SqlFunction<ResultSet, T> function) throws SQLException {
|
| 123 | 125 | try (Connection connection = openConnection()) {
|
| 124 | 126 | try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
|
| 125 | 127 | try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
| 126 | - return function.apply(resultSet);
|
|
| 128 | + if (resultSet.next()) {
|
|
| 129 | + return function.apply(resultSet);
|
|
| 130 | + }
|
|
| 131 | + return null;
|
|
| 132 | + }
|
|
| 133 | + }
|
|
| 134 | + }
|
|
| 135 | + }
|
|
| 136 | + |
|
| 137 | + public <T> List<T> runMultipleSelect(String sql, SqlFunction<ResultSet, T> function) throws SQLException {
|
|
| 138 | + List<T> result = new LinkedList<>();
|
|
| 139 | + try (Connection connection = openConnection()) {
|
|
| 140 | + try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
|
|
| 141 | + try (ResultSet resultSet = preparedStatement.executeQuery()) {
|
|
| 142 | + while (resultSet.next()) {
|
|
| 143 | + |
|
| 144 | + T row = function.apply(resultSet);
|
|
| 145 | + if (row != null) {
|
|
| 146 | + result.add(row);
|
|
| 147 | + }
|
|
| 148 | + }
|
|
| 127 | 149 | }
|
| 128 | 150 | }
|
| 129 | 151 | }
|
| 152 | + return result;
|
|
| 130 | 153 | }
|
| 131 | 154 | |
| 132 | 155 | public <T> T runOnMetadata(SqlFunction<DatabaseMetaData, T> function) throws SQLException {
|
| ... | ... | @@ -161,14 +161,14 @@ public interface JdbcSecurityHelper { |
| 161 | 161 | return getLegacyVersion();
|
| 162 | 162 | }
|
| 163 | 163 | try {
|
| 164 | - return MigrationServiceSqlHelper.DEFAULT.getVersion(jdbcHelper()).map(TMSVersion::toVersion).orElse(Version.VZERO);
|
|
| 164 | + return MigrationServiceSqlHelper.DEFAULT.getVersion(jdbcHelper()).map(TMSVersion::getVersion).orElse(Version.VZERO);
|
|
| 165 | 165 | } catch (Exception e) {
|
| 166 | - // try on legacy
|
|
| 166 | + // try on legacy (migration may not been applied)
|
|
| 167 | 167 | return getLegacyVersion();
|
| 168 | 168 | }
|
| 169 | 169 | }
|
| 170 | 170 | |
| 171 | 171 | private Version getLegacyVersion() {
|
| 172 | - return MigrationServiceSqlHelper.LEGACY.getVersion(jdbcHelper()).map(TMSVersion::toVersion).orElse(Version.VZERO);
|
|
| 172 | + return MigrationServiceSqlHelper.LEGACY.getVersion(jdbcHelper()).map(TMSVersion::getVersion).orElse(Version.VZERO);
|
|
| 173 | 173 | }
|
| 174 | 174 | } |
| ... | ... | @@ -31,7 +31,6 @@ import org.nuiton.topia.persistence.security.SecurityScriptHelper; |
| 31 | 31 | |
| 32 | 32 | import java.sql.ResultSet;
|
| 33 | 33 | import java.sql.SQLException;
|
| 34 | -import java.util.ArrayList;
|
|
| 35 | 34 | import java.util.Collection;
|
| 36 | 35 | import java.util.Collections;
|
| 37 | 36 | import java.util.HashSet;
|
| ... | ... | @@ -162,24 +161,21 @@ public class JdbcSecurityHelperH2 implements JdbcSecurityHelper { |
| 162 | 161 | Set<String> safeExtraTables = extraTables.stream().map(String::toLowerCase).collect(Collectors.toSet());
|
| 163 | 162 | try {
|
| 164 | 163 | |
| 165 | - return jdbcHelper.runSelect("SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'TABLE'", resultSet -> {
|
|
| 166 | - List<Pair<String, String>> result = new ArrayList<>();
|
|
| 167 | - while (resultSet.next()) {
|
|
| 168 | - String schemaName = resultSet.getString(1);
|
|
| 169 | - String tableName = resultSet.getString(2);
|
|
| 170 | - if (!safeExtraTables.contains(tableName.toLowerCase())) {
|
|
| 171 | - // if (POSTGIS_TABLES.contains(tableName)) {
|
|
| 172 | - // continue;
|
|
| 173 | - // }
|
|
| 174 | - if (schemaName == null || !safeSchemas.contains(schemaName.toLowerCase())) {
|
|
| 175 | - continue;
|
|
| 176 | - }
|
|
| 164 | + List<Pair<String, String>> pairs = jdbcHelper.runMultipleSelect("SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'TABLE'", resultSet -> {
|
|
| 165 | + String schemaName = resultSet.getString(1);
|
|
| 166 | + String tableName = resultSet.getString(2);
|
|
| 167 | + if (!safeExtraTables.contains(tableName.toLowerCase())) {
|
|
| 168 | + // if (POSTGIS_TABLES.contains(tableName)) {
|
|
| 169 | + // continue;
|
|
| 170 | + // }
|
|
| 171 | + if (schemaName == null || !safeSchemas.contains(schemaName.toLowerCase())) {
|
|
| 172 | + return null;
|
|
| 177 | 173 | }
|
| 178 | - result.add(Pair.of(schemaName, tableName));
|
|
| 179 | 174 | }
|
| 180 | - Collections.sort(result);
|
|
| 181 | - return result;
|
|
| 175 | + return Pair.of(schemaName, tableName);
|
|
| 182 | 176 | });
|
| 177 | + Collections.sort(pairs);
|
|
| 178 | + return pairs;
|
|
| 183 | 179 | } catch (Exception e) {
|
| 184 | 180 | throw new TopiaException(e);
|
| 185 | 181 | }
|
| ... | ... | @@ -188,14 +184,8 @@ public class JdbcSecurityHelperH2 implements JdbcSecurityHelper { |
| 188 | 184 | @Override
|
| 189 | 185 | public Set<String> getRoles() {
|
| 190 | 186 | try {
|
| 191 | - return jdbcHelper.runSelect("SELECT name FROM INFORMATION_SCHEMA.USERS;", resultSet -> {
|
|
| 192 | - Set<String> users = new LinkedHashSet<>();
|
|
| 193 | - while (resultSet.next()) {
|
|
| 194 | - String name = resultSet.getString(1);
|
|
| 195 | - users.add(name);
|
|
| 196 | - }
|
|
| 197 | - return users;
|
|
| 198 | - });
|
|
| 187 | + List<String> roles = jdbcHelper.runMultipleSelect("SELECT name FROM INFORMATION_SCHEMA.USERS;", resultSet -> resultSet.getString(1));
|
|
| 188 | + return Set.copyOf(roles);
|
|
| 199 | 189 | } catch (SQLException e) {
|
| 200 | 190 | throw new TopiaException(e);
|
| 201 | 191 | }
|
| ... | ... | @@ -204,7 +194,7 @@ public class JdbcSecurityHelperH2 implements JdbcSecurityHelper { |
| 204 | 194 | @Override
|
| 205 | 195 | public boolean isOwner() {
|
| 206 | 196 | try {
|
| 207 | - return jdbcHelper.runSelect("SELECT t.* FROM INFORMATION_SCHEMA.SCHEMATA t WHERE SCHEMA_NAME = 'PUBLIC' AND SCHEMA_OWNER = CURRENT_USER", ResultSet::next);
|
|
| 197 | + return jdbcHelper.runSelect("SELECT t.* FROM INFORMATION_SCHEMA.SCHEMATA t WHERE SCHEMA_NAME = 'PUBLIC' AND SCHEMA_OWNER = CURRENT_USER", r-> true);
|
|
| 208 | 198 | } catch (SQLException e) {
|
| 209 | 199 | throw new TopiaException(e);
|
| 210 | 200 | }
|
| ... | ... | @@ -213,7 +203,7 @@ public class JdbcSecurityHelperH2 implements JdbcSecurityHelper { |
| 213 | 203 | @Override
|
| 214 | 204 | public boolean isSuperUser() {
|
| 215 | 205 | try {
|
| 216 | - return jdbcHelper.runSelect("SELECT admin FROM INFORMATION_SCHEMA.USERS WHERE name = CURRENT_USER", resultSet -> resultSet.next() && resultSet.getBoolean(1));
|
|
| 206 | + return jdbcHelper.runSelect("SELECT admin FROM INFORMATION_SCHEMA.USERS WHERE name = CURRENT_USER", resultSet -> resultSet.getBoolean(1));
|
|
| 217 | 207 | } catch (SQLException e) {
|
| 218 | 208 | throw new TopiaException(e);
|
| 219 | 209 | }
|
| ... | ... | @@ -253,7 +253,7 @@ public class JdbcSecurityHelperPostgres implements JdbcSecurityHelper { |
| 253 | 253 | @Override
|
| 254 | 254 | public boolean isOwner() {
|
| 255 | 255 | try {
|
| 256 | - return jdbcHelper.runSelect("SELECT pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d WHERE d.datname = (SELECT current_database())", resultSet -> resultSet.next() && Objects.equals(jdbcHelper.getJdbcConnectionUser(), resultSet.getString(1)));
|
|
| 256 | + return jdbcHelper.runSelect("SELECT pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d WHERE d.datname = (SELECT current_database())", resultSet -> Objects.equals(jdbcHelper.getJdbcConnectionUser(), resultSet.getString(1)));
|
|
| 257 | 257 | } catch (SQLException e) {
|
| 258 | 258 | throw new TopiaException(e);
|
| 259 | 259 | }
|
| ... | ... | @@ -262,7 +262,7 @@ public class JdbcSecurityHelperPostgres implements JdbcSecurityHelper { |
| 262 | 262 | @Override
|
| 263 | 263 | public boolean isSuperUser() {
|
| 264 | 264 | try {
|
| 265 | - return jdbcHelper.runSelect("SELECT usesuper FROM pg_user WHERE usename = CURRENT_USER", resultSet -> resultSet.next() && resultSet.getBoolean(1));
|
|
| 265 | + return jdbcHelper.runSelect("SELECT usesuper FROM pg_user WHERE usename = CURRENT_USER", resultSet -> resultSet.getBoolean(1));
|
|
| 266 | 266 | } catch (SQLException e) {
|
| 267 | 267 | throw new TopiaException(e);
|
| 268 | 268 | }
|
| ... | ... | @@ -275,14 +275,8 @@ public class JdbcSecurityHelperPostgres implements JdbcSecurityHelper { |
| 275 | 275 | " FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)" +
|
| 276 | 276 | " WHERE ns.nspname = 'public' AND p.proname ILIKE '%s%%';", functionPattern);
|
| 277 | 277 | try {
|
| 278 | - return jdbcHelper.runSelect(sql, resultSet -> {
|
|
| 279 | - Set<String> result = new LinkedHashSet<>();
|
|
| 280 | - while (resultSet.next()) {
|
|
| 281 | - String functionPrototype = resultSet.getString(1);
|
|
| 282 | - result.add(functionPrototype);
|
|
| 283 | - }
|
|
| 284 | - return result;
|
|
| 285 | - });
|
|
| 278 | + List<String> result = jdbcHelper.runMultipleSelect(sql, resultSet -> resultSet.getString(1));
|
|
| 279 | + return Set.copyOf(result);
|
|
| 286 | 280 | } catch (SQLException e) {
|
| 287 | 281 | throw new TopiaException(e);
|
| 288 | 282 | }
|
| ... | ... | @@ -38,6 +38,9 @@ import org.nuiton.topia.service.migration.version.TMSVersion; |
| 38 | 38 | import java.io.IOException;
|
| 39 | 39 | import java.nio.file.Files;
|
| 40 | 40 | import java.nio.file.Path;
|
| 41 | +import java.util.Date;
|
|
| 42 | +import java.util.List;
|
|
| 43 | +import java.util.Objects;
|
|
| 41 | 44 | import java.util.Optional;
|
| 42 | 45 | |
| 43 | 46 | /**
|
| ... | ... | @@ -56,11 +59,10 @@ public class TopiaMigrationServiceContext { |
| 56 | 59 | * Service configuration.
|
| 57 | 60 | */
|
| 58 | 61 | protected final TopiaMigrationServiceConfiguration configuration;
|
| 59 | - protected final MigrationServiceSqlHelper sqlHelper;
|
|
| 60 | 62 | /**
|
| 61 | - * Jdbc helper used to perform some sql code.
|
|
| 63 | + * Migration sql helper (could be legacy or default).
|
|
| 62 | 64 | */
|
| 63 | - private final JdbcHelper jdbcHelper;
|
|
| 65 | + protected final MigrationServiceSqlHelper sqlHelper;
|
|
| 64 | 66 | /**
|
| 65 | 67 | * Available migration resources found in class-path.
|
| 66 | 68 | */
|
| ... | ... | @@ -74,17 +76,25 @@ public class TopiaMigrationServiceContext { |
| 74 | 76 | */
|
| 75 | 77 | protected final boolean dbNotVersioned;
|
| 76 | 78 | /**
|
| 77 | - * Is legacy TMSVersion table exists?
|
|
| 79 | + * Is legacy migration table exists? (only used with default mode)
|
|
| 78 | 80 | */
|
| 79 | 81 | protected final boolean legacyVersionTableExist;
|
| 80 | 82 | /**
|
| 81 | - * Is TMSVersion schema exists?
|
|
| 83 | + * Is default migration schema exists?
|
|
| 84 | + */
|
|
| 85 | + protected final boolean versionSchemaExist;
|
|
| 86 | + /**
|
|
| 87 | + * Is default migration table exists?
|
|
| 82 | 88 | */
|
| 83 | - protected boolean versionSchemaExist;
|
|
| 89 | + protected final boolean versionTableExist;
|
|
| 84 | 90 | /**
|
| 85 | - * Is TMSVersion table exists?
|
|
| 91 | + * Can we apply migration versions?
|
|
| 86 | 92 | */
|
| 87 | - protected boolean versionTableExist;
|
|
| 93 | + protected final boolean canApplyMigrationVersions;
|
|
| 94 | + /**
|
|
| 95 | + * Migration versions to apply.
|
|
| 96 | + */
|
|
| 97 | + protected final List<Version> versionsToApply;
|
|
| 88 | 98 | /**
|
| 89 | 99 | * Current database version.
|
| 90 | 100 | */
|
| ... | ... | @@ -114,10 +124,11 @@ public class TopiaMigrationServiceContext { |
| 114 | 124 | try {
|
| 115 | 125 | versionTableExist = sqlHelper.isTableExist(jdbcHelper);
|
| 116 | 126 | if (versionTableExist) {
|
| 127 | + log.info("Detected standard migration table {}.", sqlHelper.gav());
|
|
| 117 | 128 | versionSchemaExist = true;
|
| 118 | 129 | Optional<TMSVersion> tmsVersion = sqlHelper.getVersion(jdbcHelper);
|
| 119 | 130 | if (tmsVersion.isPresent()) {
|
| 120 | - v = tmsVersion.get().toVersion();
|
|
| 131 | + v = tmsVersion.get().getVersion();
|
|
| 121 | 132 | }
|
| 122 | 133 | if (v == null) {
|
| 123 | 134 | log.warn(String.format("Version not found on table %s", sqlHelper.gav()));
|
| ... | ... | @@ -126,9 +137,10 @@ public class TopiaMigrationServiceContext { |
| 126 | 137 | versionSchemaExist = sqlHelper.isSchemaExist(jdbcHelper);
|
| 127 | 138 | legacyVersionTableExist = legacySqlHelper.isTableExist(jdbcHelper);
|
| 128 | 139 | if (legacyVersionTableExist) {
|
| 140 | + log.info("Detected legacy migration table {}.", sqlHelper.gav());
|
|
| 129 | 141 | Optional<TMSVersion> tmsVersion = legacySqlHelper.getVersion(jdbcHelper);
|
| 130 | 142 | if (tmsVersion.isPresent()) {
|
| 131 | - v = tmsVersion.get().toVersion();
|
|
| 143 | + v = tmsVersion.get().getVersion();
|
|
| 132 | 144 | }
|
| 133 | 145 | if (v == null) {
|
| 134 | 146 | log.warn(String.format("Version not found on legacy table %s", legacySqlHelper.gav()));
|
| ... | ... | @@ -137,6 +149,7 @@ public class TopiaMigrationServiceContext { |
| 137 | 149 | }
|
| 138 | 150 | } finally {
|
| 139 | 151 | if (v == null) {
|
| 152 | + //FIXME Is this can really happen?
|
|
| 140 | 153 | // la base dans ce cas n'est pas versionee.
|
| 141 | 154 | // On dit que la version de la base est 0
|
| 142 | 155 | // et les schema de cette version 0 doivent
|
| ... | ... | @@ -151,7 +164,6 @@ public class TopiaMigrationServiceContext { |
| 151 | 164 | }
|
| 152 | 165 | return new TopiaMigrationServiceContext(configuration,
|
| 153 | 166 | sqlHelper,
|
| 154 | - jdbcHelper,
|
|
| 155 | 167 | legacyVersionTableExist,
|
| 156 | 168 | versionSchemaExist,
|
| 157 | 169 | versionTableExist,
|
| ... | ... | @@ -175,9 +187,10 @@ public class TopiaMigrationServiceContext { |
| 175 | 187 | try {
|
| 176 | 188 | versionTableExist = sqlHelper.isTableExist(jdbcHelper);
|
| 177 | 189 | if (versionTableExist) {
|
| 190 | + log.info("Detected legacy migration table {}.", sqlHelper.gav());
|
|
| 178 | 191 | Optional<TMSVersion> tmsVersion = sqlHelper.getVersion(jdbcHelper);
|
| 179 | 192 | if (tmsVersion.isPresent()) {
|
| 180 | - v = tmsVersion.get().toVersion();
|
|
| 193 | + v = tmsVersion.get().getVersion();
|
|
| 181 | 194 | }
|
| 182 | 195 | if (v == null) {
|
| 183 | 196 | log.warn(String.format("Version not found on table %s", sqlHelper.gav()));
|
| ... | ... | @@ -199,7 +212,6 @@ public class TopiaMigrationServiceContext { |
| 199 | 212 | }
|
| 200 | 213 | return new TopiaMigrationServiceContext(configuration,
|
| 201 | 214 | sqlHelper,
|
| 202 | - jdbcHelper,
|
|
| 203 | 215 | false,
|
| 204 | 216 | true,
|
| 205 | 217 | versionTableExist,
|
| ... | ... | @@ -211,15 +223,14 @@ public class TopiaMigrationServiceContext { |
| 211 | 223 | |
| 212 | 224 | protected TopiaMigrationServiceContext(TopiaMigrationServiceConfiguration configuration,
|
| 213 | 225 | MigrationServiceSqlHelper sqlHelper,
|
| 214 | - JdbcHelper jdbcHelper,
|
|
| 215 | - boolean legacyVersionTableExist, boolean versionSchemaExist,
|
|
| 226 | + boolean legacyVersionTableExist,
|
|
| 227 | + boolean versionSchemaExist,
|
|
| 216 | 228 | boolean versionTableExist,
|
| 217 | 229 | boolean dbNotVersioned,
|
| 218 | 230 | Version dbVersion,
|
| 219 | 231 | MigrationVersionResourceProvider resources) {
|
| 220 | 232 | this.configuration = configuration;
|
| 221 | 233 | this.sqlHelper = sqlHelper;
|
| 222 | - this.jdbcHelper = jdbcHelper;
|
|
| 223 | 234 | this.versionSchemaExist = versionSchemaExist;
|
| 224 | 235 | this.versionTableExist = versionTableExist;
|
| 225 | 236 | this.dbNotVersioned = dbNotVersioned;
|
| ... | ... | @@ -231,26 +242,24 @@ public class TopiaMigrationServiceContext { |
| 231 | 242 | } catch (IOException e) {
|
| 232 | 243 | throw new IllegalStateException("Can't create scripts path", e);
|
| 233 | 244 | }
|
| 234 | - }
|
|
| 235 | 245 | |
| 236 | - public Path getScriptPath() {
|
|
| 237 | - return scriptPath;
|
|
| 238 | - }
|
|
| 246 | + List<Version> allVersions = getResources().getAvailableVersions();
|
|
| 247 | + log.info(String.format("Detected available versions: %1$s", allVersions));
|
|
| 239 | 248 | |
| 240 | - public boolean isVersionSchemaExist() {
|
|
| 241 | - return versionSchemaExist;
|
|
| 242 | - }
|
|
| 249 | + versionsToApply = getResources().getVersionsAfter(dbVersion);
|
|
| 250 | + log.info(String.format("Detected versions to apply: %1$s", versionsToApply));
|
|
| 243 | 251 | |
| 244 | - public boolean isVersionTableExist() {
|
|
| 245 | - return versionTableExist;
|
|
| 246 | - }
|
|
| 252 | + Optional<TopiaMigrationServiceAskUserToMigrate> askUserToMigrate = Optional.ofNullable(configuration.getCallback());
|
|
| 247 | 253 | |
| 248 | - public boolean isLegacyVersionTableExist() {
|
|
| 249 | - return legacyVersionTableExist;
|
|
| 254 | + // ask to perform the migration
|
|
| 255 | + canApplyMigrationVersions = askUserToMigrate.map(c -> c.canIMigrate(getDbVersion(), versionsToApply)).orElse(true);
|
|
| 256 | + if (!canApplyMigrationVersions) {
|
|
| 257 | + log.warn("Detected that we can not migrate versions (maybe version of database is too old?).");
|
|
| 258 | + }
|
|
| 250 | 259 | }
|
| 251 | 260 | |
| 252 | - public boolean isDbNotVersioned() {
|
|
| 253 | - return dbNotVersioned;
|
|
| 261 | + public Path getScriptPath() {
|
|
| 262 | + return scriptPath;
|
|
| 254 | 263 | }
|
| 255 | 264 | |
| 256 | 265 | public Version getModelVersion() {
|
| ... | ... | @@ -265,35 +274,65 @@ public class TopiaMigrationServiceContext { |
| 265 | 274 | return resources;
|
| 266 | 275 | }
|
| 267 | 276 | |
| 268 | - public void createSchemaIfNotExist() {
|
|
| 277 | + public boolean adaptVersionTable(TopiaSqlSupport sqlSupport) {
|
|
| 278 | + |
|
| 279 | + Version modelVersion = getModelVersion();
|
|
| 280 | + boolean dbVersionEqualsModelVersion = Objects.equals(dbVersion, modelVersion);
|
|
| 281 | + |
|
| 269 | 282 | if (!versionSchemaExist) {
|
| 270 | - sqlHelper.createSchema(jdbcHelper);
|
|
| 271 | - versionSchemaExist = true;
|
|
| 283 | + log.info("Create default migration schema.");
|
|
| 284 | + sqlHelper.createSchema(sqlSupport);
|
|
| 272 | 285 | }
|
| 273 | - }
|
|
| 274 | - |
|
| 275 | - public void createTableIfNotExist() {
|
|
| 276 | 286 | if (!versionTableExist) {
|
| 277 | - sqlHelper.createTable(jdbcHelper);
|
|
| 278 | - versionTableExist = true;
|
|
| 287 | + log.info("Create default migration table.");
|
|
| 288 | + sqlHelper.createTable(sqlSupport);
|
|
| 289 | + } else {
|
|
| 290 | + if (dbVersionEqualsModelVersion) {
|
|
| 291 | + log.info("Database is up to date, no migration needed.");
|
|
| 292 | + return false;
|
|
| 293 | + }
|
|
| 294 | + }
|
|
| 295 | + if (legacyVersionTableExist) {
|
|
| 296 | + log.info("Drop legacy migration table.");
|
|
| 297 | + MigrationServiceSqlHelper.LEGACY.dropTable(sqlSupport);
|
|
| 298 | + if (dbVersionEqualsModelVersion) {
|
|
| 299 | + log.info("Database is up to date (version: {}), but was coming from legacy migration table, fill new migration table.", modelVersion);
|
|
| 300 | + saveVersion(sqlSupport, modelVersion, null);
|
|
| 301 | + return false;
|
|
| 302 | + }
|
|
| 303 | + log.info("Fill version table {} from legacy table.", dbVersion);
|
|
| 304 | + saveVersion(sqlSupport, dbVersion, null);
|
|
| 305 | + } else if (dbNotVersioned) {
|
|
| 306 | + log.info("Database is empty, no migration needed, set ");
|
|
| 307 | + saveVersion(sqlSupport, modelVersion, new Date());
|
|
| 308 | + return false;
|
|
| 279 | 309 | }
|
| 310 | + // In all other cases, we can try to perform migration
|
|
| 311 | + return true;
|
|
| 280 | 312 | }
|
| 281 | 313 | |
| 282 | - public void saveModelVersion() {
|
|
| 283 | - saveVersion(null, getModelVersion());
|
|
| 284 | - }
|
|
| 314 | + public List<Version> getVersionsToApply() {
|
|
| 285 | 315 | |
| 286 | - public Optional<TopiaMigrationServiceAskUserToMigrate> getAskUserToMigrate() {
|
|
| 287 | - return Optional.ofNullable(configuration.getCallback());
|
|
| 288 | - }
|
|
| 316 | + if (versionsToApply.isEmpty()) {
|
|
| 317 | + log.info("No version to apply, no migration needed.");
|
|
| 318 | + // No migration, so nothing to save
|
|
| 319 | +// context.saveModelVersion();
|
|
| 320 | + return null;
|
|
| 321 | + }
|
|
| 289 | 322 | |
| 290 | - protected void saveVersion(TopiaSqlSupport sqlSupport, Version version) {
|
|
| 291 | - log.info(String.format("[ Version %s ] Saving new database version.", version));
|
|
| 292 | - if (sqlSupport != null) {
|
|
| 293 | - sqlHelper.save(sqlSupport, version.getVersion());
|
|
| 294 | - } else {
|
|
| 295 | - sqlHelper.save(jdbcHelper, version.getVersion());
|
|
| 323 | + // ask to perform the migration
|
|
| 324 | + |
|
| 325 | + if (!canApplyMigrationVersions) {
|
|
| 326 | + // user cancel migration
|
|
| 327 | + log.warn("Migration was cancelled by migration callback (maybe version of database is too old?).");
|
|
| 328 | + return null;
|
|
| 296 | 329 | }
|
| 330 | + return versionsToApply;
|
|
| 331 | + }
|
|
| 332 | + |
|
| 333 | + protected void saveVersion(TopiaSqlSupport sqlSupport, Version version, Date date) {
|
|
| 334 | + log.info(String.format("[ Version %s ] Saving new database version (date: %s).", version, date));
|
|
| 335 | + sqlHelper.save(sqlSupport, version.getVersion(), date);
|
|
| 297 | 336 | dbVersion = version;
|
| 298 | 337 | }
|
| 299 | 338 | |
| ... | ... | @@ -309,8 +348,4 @@ public class TopiaMigrationServiceContext { |
| 309 | 348 | return new MigrationVersionResourceExecutor(migrationVersionResource, sqlSupport, configuration.getClassifier(), getScriptPath(), migrationVersionResource.getScriptVariables());
|
| 310 | 349 | }
|
| 311 | 350 | |
| 312 | - public void dropLegacyTable() {
|
|
| 313 | - MigrationServiceSqlHelper.LEGACY.dropTable(jdbcHelper);
|
|
| 314 | - }
|
|
| 315 | - |
|
| 316 | 351 | } |
| ... | ... | @@ -34,10 +34,10 @@ import org.nuiton.topia.service.migration.resources.MigrationVersionResource; |
| 34 | 34 | import org.nuiton.topia.service.migration.resources.MigrationVersionResourceExecutor;
|
| 35 | 35 | |
| 36 | 36 | import java.io.IOException;
|
| 37 | +import java.util.Date;
|
|
| 37 | 38 | import java.util.List;
|
| 38 | 39 | import java.util.Map;
|
| 39 | 40 | import java.util.Objects;
|
| 40 | -import java.util.Optional;
|
|
| 41 | 41 | |
| 42 | 42 | /**
|
| 43 | 43 | * Topia migration service default implementation.
|
| ... | ... | @@ -68,81 +68,38 @@ public class TopiaMigrationServiceImpl implements TopiaMigrationService { |
| 68 | 68 | @Override
|
| 69 | 69 | public void runSchemaMigration() throws TopiaMigrationServiceException {
|
| 70 | 70 | |
| 71 | + log.info("Migration - Prepare internal states.");
|
|
| 71 | 72 | TopiaMigrationServiceContext context = TopiaMigrationServiceContext.create(configuration);
|
| 72 | - Version modelVersion = context.getModelVersion();
|
|
| 73 | - Version dbVersion = context.getDbVersion();
|
|
| 74 | - boolean dbNotVersioned = context.isDbNotVersioned();
|
|
| 75 | - boolean legacyVersionTableExist = context.isLegacyVersionTableExist();
|
|
| 76 | - boolean versionSchemaExist = context.isVersionSchemaExist();
|
|
| 77 | - boolean versionTableExist = context.isVersionTableExist();
|
|
| 78 | - |
|
| 79 | - log.info(String.format("Starting Topia Migration Service - Model version : %s, Database version : %s", modelVersion, dbVersion));
|
|
| 80 | - |
|
| 81 | - if (!versionSchemaExist) {
|
|
| 82 | - log.info("Create migration schema.");
|
|
| 83 | - context.createSchemaIfNotExist();
|
|
| 84 | - }
|
|
| 85 | - if (!versionTableExist) {
|
|
| 86 | - log.info("Create migration table.");
|
|
| 87 | - context.createTableIfNotExist();
|
|
| 88 | - }
|
|
| 89 | - if (legacyVersionTableExist) {
|
|
| 90 | - log.info("Drop legacy migration table.");
|
|
| 91 | - context.dropLegacyTable();
|
|
| 92 | - if (dbVersion.equals(modelVersion)) {
|
|
| 93 | - log.info("Database is up to date, but was coming from legacy migration table, fill new migration table.");
|
|
| 94 | - context.saveModelVersion();
|
|
| 73 | + log.info("Migration - Prepare internal states done.");
|
|
| 74 | + |
|
| 75 | + try (TopiaPersistenceContext persistenceContext = context.newPersistenceContext()) {
|
|
| 76 | + log.info("Migration - Adapting migration table.");
|
|
| 77 | + boolean canContinue = adaptVersionTable(persistenceContext, context);
|
|
| 78 | + log.info("Migration - Adapting migration table done.");
|
|
| 79 | + if (!canContinue) {
|
|
| 80 | + log.info(String.format("Migration - End - db version: %s (nothing more to do).", context.getDbVersion()));
|
|
| 81 | + return;
|
|
| 82 | + }
|
|
| 83 | + log.info("Migration - Getting migration versions to apply.");
|
|
| 84 | + List<Version> versionsToApply = context.getVersionsToApply();
|
|
| 85 | + log.info("Migration - Getting migration versions to apply done.");
|
|
| 86 | + if (versionsToApply == null) {
|
|
| 87 | + log.info(String.format("Migration - End - db version: %s (nothing more to do).", context.getDbVersion()));
|
|
| 95 | 88 | return;
|
| 96 | 89 | }
|
| 97 | - }
|
|
| 98 | - |
|
| 99 | - if (versionTableExist && dbVersion.equals(modelVersion)) {
|
|
| 100 | - log.info("Database is up to date, no migration needed.");
|
|
| 101 | - return;
|
|
| 102 | - }
|
|
| 103 | - |
|
| 104 | - if (versionTableExist && dbNotVersioned) {
|
|
| 105 | - log.info("Database is empty, no migration needed.");
|
|
| 106 | - context.saveModelVersion();
|
|
| 107 | - return;
|
|
| 108 | - }
|
|
| 109 | - |
|
| 110 | - List<Version> allVersions = context.getResources().getAvailableVersions();
|
|
| 111 | - log.info(String.format("Available versions: %1$s", allVersions));
|
|
| 112 | - |
|
| 113 | - List<Version> versionsToApply = context.getResources().getVersionsAfter(dbVersion);
|
|
| 114 | - |
|
| 115 | - if (versionsToApply.isEmpty()) {
|
|
| 116 | - log.info("No version to apply, no migration needed.");
|
|
| 117 | - context.saveModelVersion();
|
|
| 118 | - return;
|
|
| 119 | - }
|
|
| 120 | - |
|
| 121 | - log.info(String.format("Versions to apply: %1$s", versionsToApply));
|
|
| 122 | - |
|
| 123 | - Optional<TopiaMigrationServiceAskUserToMigrate> askUserToMigrate = context.getAskUserToMigrate();
|
|
| 124 | - |
|
| 125 | - // ask to perform the migration
|
|
| 126 | - boolean performMigration = askUserToMigrate.map(c -> c.canIMigrate(dbVersion, versionsToApply)).orElse(true);
|
|
| 127 | - |
|
| 128 | - log.debug("Handler choose : " + performMigration);
|
|
| 129 | 90 | |
| 130 | - if (!performMigration) {
|
|
| 131 | - // user cancel migration
|
|
| 132 | - return;
|
|
| 133 | - }
|
|
| 91 | + log.info(String.format("Migration - Will apply versions: %1$s.", versionsToApply));
|
|
| 134 | 92 | |
| 135 | - long statementCount = 0;
|
|
| 136 | - try (TopiaPersistenceContext persistenceContext = context.newPersistenceContext()) {
|
|
| 93 | + long statementCount = 0;
|
|
| 137 | 94 | for (Version version : versionsToApply) {
|
| 138 | 95 | long t0 = TimeLog.getTime();
|
| 139 | 96 | long versionCount = migrateVersion(persistenceContext, version, context);
|
| 140 | 97 | statementCount += versionCount;
|
| 141 | 98 | TIME_LOG.log(t0, "migrationVersion", version.toString() + " - " + versionCount + " sql statements");
|
| 142 | 99 | }
|
| 100 | + log.info(String.format("Migration - End - db version: %s - consume %d sql statement(s)", context.getDbVersion(), statementCount));
|
|
| 143 | 101 | }
|
| 144 | 102 | |
| 145 | - log.info(String.format("Ends migration - db version: %s - consume %d sql statement(s)", context.getDbVersion(), statementCount));
|
|
| 146 | 103 | }
|
| 147 | 104 | |
| 148 | 105 | @Override
|
| ... | ... | @@ -150,6 +107,17 @@ public class TopiaMigrationServiceImpl implements TopiaMigrationService { |
| 150 | 107 | configuration = null;
|
| 151 | 108 | }
|
| 152 | 109 | |
| 110 | + protected boolean adaptVersionTable(TopiaPersistenceContext persistenceContext, TopiaMigrationServiceContext context) {
|
|
| 111 | + try {
|
|
| 112 | + boolean canContinue = context.adaptVersionTable(persistenceContext.getSqlSupport());
|
|
| 113 | + persistenceContext.commit();
|
|
| 114 | + return canContinue;
|
|
| 115 | + } catch (Exception e) {
|
|
| 116 | + persistenceContext.rollback();
|
|
| 117 | + throw new TopiaMigrationServiceException("Exception during adapting migration table", e);
|
|
| 118 | + }
|
|
| 119 | + }
|
|
| 120 | + |
|
| 153 | 121 | protected long migrateVersion(TopiaPersistenceContext persistenceContext, Version version, TopiaMigrationServiceContext context) {
|
| 154 | 122 | |
| 155 | 123 | MigrationVersionResource resource = context.getResource(version);
|
| ... | ... | @@ -174,14 +142,15 @@ public class TopiaMigrationServiceImpl implements TopiaMigrationService { |
| 174 | 142 | }
|
| 175 | 143 | }
|
| 176 | 144 | // here we use the sqlSupport to save version, to stay on the very same transaction
|
| 177 | - context.saveVersion(sqlSupport, version);
|
|
| 145 | + context.saveVersion(sqlSupport, version, new Date());
|
|
| 178 | 146 | |
| 147 | + // do commit, this migration version is now completed
|
|
| 148 | + persistenceContext.commit();
|
|
| 179 | 149 | } catch (Exception e) {
|
| 180 | 150 | // Exception, rollback transaction
|
| 181 | 151 | persistenceContext.rollback();
|
| 182 | 152 | throw new TopiaMigrationServiceException("Exception during schema migration on version: " + version, e);
|
| 183 | 153 | }
|
| 184 | - persistenceContext.commit();
|
|
| 185 | 154 | return outStatementCount;
|
| 186 | 155 | }
|
| 187 | 156 |
| ... | ... | @@ -27,6 +27,10 @@ import org.nuiton.topia.persistence.jdbc.JdbcHelper; |
| 27 | 27 | import org.nuiton.topia.persistence.support.TopiaSqlSupport;
|
| 28 | 28 | |
| 29 | 29 | import java.sql.SQLException;
|
| 30 | +import java.sql.Timestamp;
|
|
| 31 | +import java.util.Comparator;
|
|
| 32 | +import java.util.Date;
|
|
| 33 | +import java.util.List;
|
|
| 30 | 34 | import java.util.Optional;
|
| 31 | 35 | |
| 32 | 36 | /**
|
| ... | ... | @@ -38,12 +42,8 @@ import java.util.Optional; |
| 38 | 42 | * @since 9.0.7
|
| 39 | 43 | */
|
| 40 | 44 | public interface MigrationServiceSqlHelper {
|
| 41 | - String GET_VERSION_TABLE_STATEMENT = "SELECT version FROM %s;";
|
|
| 42 | 45 | String CREATE_VERSION_SCHEMA_STATEMENT = "CREATE SCHEMA %s;";
|
| 43 | - String CREATE_VERSION_TABLE_STATEMENT = "CREATE TABLE %s(version VARCHAR(255) NOT NULL, PRIMARY KEY (version));";
|
|
| 44 | - String DELETE_VERSION_TABLE_STATEMENT = "DELETE FROM %s;";
|
|
| 45 | 46 | String DROP_VERSION_TABLE_STATEMENT = "DROP TABLE %s;";
|
| 46 | - String FILL_VERSION_TABLE_STATEMENT = "INSERT INTO %s(version) VALUES('%s');";
|
|
| 47 | 47 | |
| 48 | 48 | /**
|
| 49 | 49 | * Legacy layout.
|
| ... | ... | @@ -51,6 +51,10 @@ public interface MigrationServiceSqlHelper { |
| 51 | 51 | MigrationServiceSqlHelper LEGACY = new MigrationServiceSqlHelper() {
|
| 52 | 52 | public static final String SCHEMA_NAME = "public";
|
| 53 | 53 | public static final String TABLE_NAME = "tms_version";
|
| 54 | + public static final String CREATE_VERSION_TABLE_STATEMENT = "CREATE TABLE %s(version VARCHAR(255) NOT NULL, PRIMARY KEY(version));";
|
|
| 55 | + public static final String FILL_VERSION_TABLE_STATEMENT = "INSERT INTO %s(version) VALUES('%s');";
|
|
| 56 | + public static final String GET_VERSION_TABLE_STATEMENT = "SELECT version FROM %s;";
|
|
| 57 | + public static final String DELETE_VERSION_TABLE_STATEMENT = "DELETE FROM %s;";
|
|
| 54 | 58 | |
| 55 | 59 | @Override
|
| 56 | 60 | public String schemaName() {
|
| ... | ... | @@ -61,15 +65,46 @@ public interface MigrationServiceSqlHelper { |
| 61 | 65 | public String tableName() {
|
| 62 | 66 | return TABLE_NAME;
|
| 63 | 67 | }
|
| 68 | + |
|
| 69 | + @Override
|
|
| 70 | + public String createTableSql() {
|
|
| 71 | + return String.format(CREATE_VERSION_TABLE_STATEMENT, gav());
|
|
| 72 | + }
|
|
| 73 | + |
|
| 74 | + @Override
|
|
| 75 | + public String getVersionSql() {
|
|
| 76 | + return String.format(GET_VERSION_TABLE_STATEMENT, gav());
|
|
| 77 | + }
|
|
| 78 | + |
|
| 79 | + @Override
|
|
| 80 | + public Optional<TMSVersion> getVersion(JdbcHelper jdbcHelper) {
|
|
| 81 | + try {
|
|
| 82 | + try {
|
|
| 83 | + TMSVersion result = jdbcHelper.runSelect(getVersionSql(), r -> new TMSVersion(r.getString(1), null));
|
|
| 84 | + return Optional.ofNullable(result);
|
|
| 85 | + } catch (Exception e) {
|
|
| 86 | + throw new TopiaException("Could not obtain version", e);
|
|
| 87 | + }
|
|
| 88 | + } catch (Exception e) {
|
|
| 89 | + throw new TopiaException("Could not obtain version", e);
|
|
| 90 | + }
|
|
| 91 | + }
|
|
| 92 | + |
|
| 93 | + @Override
|
|
| 94 | + public String saveTableSql(String version, Date date) {
|
|
| 95 | + return String.format(DELETE_VERSION_TABLE_STATEMENT, gav()) + String.format(FILL_VERSION_TABLE_STATEMENT, gav(), version);
|
|
| 96 | + }
|
|
| 64 | 97 | };
|
| 65 | 98 | /**
|
| 66 | 99 | * Default layout.
|
| 67 | 100 | */
|
| 68 | 101 | MigrationServiceSqlHelper DEFAULT = new MigrationServiceSqlHelper() {
|
| 69 | - //FIXME Find a better name
|
|
| 70 | 102 | public static final String SCHEMA_NAME = "common";
|
| 71 | 103 | //FIXME Find a better name
|
| 72 | - public static final String TABLE_NAME = "tms_version";
|
|
| 104 | + public static final String TABLE_NAME = "database_version";
|
|
| 105 | + public static final String CREATE_VERSION_TABLE_STATEMENT = "CREATE TABLE %s(version VARCHAR(255) NOT NULL, date TIMESTAMP, PRIMARY KEY(version));";
|
|
| 106 | + public static final String FILL_VERSION_TABLE_STATEMENT = "INSERT INTO %s(version, date) VALUES('%s', %s);";
|
|
| 107 | + public static final String GET_VERSION_TABLE_STATEMENT = "SELECT version, date FROM %s;";
|
|
| 73 | 108 | |
| 74 | 109 | @Override
|
| 75 | 110 | public String schemaName() {
|
| ... | ... | @@ -80,6 +115,35 @@ public interface MigrationServiceSqlHelper { |
| 80 | 115 | public String tableName() {
|
| 81 | 116 | return TABLE_NAME;
|
| 82 | 117 | }
|
| 118 | + |
|
| 119 | + @Override
|
|
| 120 | + public String createTableSql() {
|
|
| 121 | + return String.format(CREATE_VERSION_TABLE_STATEMENT, gav());
|
|
| 122 | + }
|
|
| 123 | + |
|
| 124 | + @Override
|
|
| 125 | + public String getVersionSql() {
|
|
| 126 | + return String.format(GET_VERSION_TABLE_STATEMENT, gav());
|
|
| 127 | + }
|
|
| 128 | + |
|
| 129 | + @Override
|
|
| 130 | + public Optional<TMSVersion> getVersion(JdbcHelper jdbcHelper) {
|
|
| 131 | + try {
|
|
| 132 | + List<TMSVersion> result = jdbcHelper.runMultipleSelect(getVersionSql(), r -> new TMSVersion(r.getString(1), r.getTimestamp(2)));
|
|
| 133 | + if (result.isEmpty()) {
|
|
| 134 | + return Optional.empty();
|
|
| 135 | + }
|
|
| 136 | + result.sort(Comparator.comparing(TMSVersion::getVersion).reversed());
|
|
| 137 | + return Optional.of(result.get(0));
|
|
| 138 | + } catch (Exception e) {
|
|
| 139 | + throw new TopiaException("Could not obtain version", e);
|
|
| 140 | + }
|
|
| 141 | + }
|
|
| 142 | + |
|
| 143 | + @Override
|
|
| 144 | + public String saveTableSql(String version, Date date) {
|
|
| 145 | + return String.format(FILL_VERSION_TABLE_STATEMENT, gav(), version, date == null ? "NULL" : ("'" + new Timestamp(date.getTime()) + "'::timestamp"));
|
|
| 146 | + }
|
|
| 83 | 147 | };
|
| 84 | 148 | |
| 85 | 149 | /**
|
| ... | ... | @@ -89,7 +153,7 @@ public interface MigrationServiceSqlHelper { |
| 89 | 153 | * <p>
|
| 90 | 154 | * We will need even after that to keep the legacy definition, to be able to migration older database using it.
|
| 91 | 155 | */
|
| 92 | - MigrationServiceSqlHelper CURRENT = LEGACY;
|
|
| 156 | + MigrationServiceSqlHelper CURRENT = DEFAULT;
|
|
| 93 | 157 | |
| 94 | 158 | static boolean isLegacy() {
|
| 95 | 159 | return CURRENT.equals(LEGACY);
|
| ... | ... | @@ -112,59 +176,22 @@ public interface MigrationServiceSqlHelper { |
| 112 | 176 | return schemaName() + "." + tableName();
|
| 113 | 177 | }
|
| 114 | 178 | |
| 115 | - default Optional<TMSVersion> getVersion(JdbcHelper jdbcHelper) {
|
|
| 116 | - try {
|
|
| 117 | - String version = jdbcHelper.runSelectOnString(getVersionSql());
|
|
| 118 | - return Optional.ofNullable(version == null ? null : new TMSVersion(version));
|
|
| 119 | - } catch (Exception e) {
|
|
| 120 | - throw new TopiaException("Could not obtain version", e);
|
|
| 121 | - }
|
|
| 122 | - }
|
|
| 123 | - |
|
| 124 | - default String getVersionSql() {
|
|
| 125 | - return String.format(GET_VERSION_TABLE_STATEMENT, gav());
|
|
| 126 | - }
|
|
| 179 | + Optional<TMSVersion> getVersion(JdbcHelper jdbcHelper);
|
|
| 127 | 180 | |
| 128 | - default String createSchemaSql() {
|
|
| 129 | - return String.format(CREATE_VERSION_SCHEMA_STATEMENT, gav());
|
|
| 130 | - }
|
|
| 181 | + String getVersionSql();
|
|
| 131 | 182 | |
| 132 | - default String createTableSql() {
|
|
| 133 | - return String.format(CREATE_VERSION_TABLE_STATEMENT, gav());
|
|
| 134 | - }
|
|
| 183 | + String createTableSql();
|
|
| 135 | 184 | |
| 136 | - default String deleteTableSql() {
|
|
| 137 | - return String.format(DELETE_VERSION_TABLE_STATEMENT, gav());
|
|
| 138 | - }
|
|
| 185 | + String saveTableSql(String version, Date date);
|
|
| 139 | 186 | |
| 140 | - default String fillVersionSql(String version) {
|
|
| 141 | - return String.format(FILL_VERSION_TABLE_STATEMENT, gav(), version);
|
|
| 187 | + default String createSchemaSql() {
|
|
| 188 | + return String.format(CREATE_VERSION_SCHEMA_STATEMENT, gav());
|
|
| 142 | 189 | }
|
| 143 | 190 | |
| 144 | 191 | default String dropTableSql() {
|
| 145 | 192 | return String.format(DROP_VERSION_TABLE_STATEMENT, gav());
|
| 146 | 193 | }
|
| 147 | 194 | |
| 148 | - default String saveTableSql(String version) {
|
|
| 149 | - return deleteTableSql() + fillVersionSql(version);
|
|
| 150 | - }
|
|
| 151 | - |
|
| 152 | - default void save(JdbcHelper jdbcHelper, String version) {
|
|
| 153 | - try {
|
|
| 154 | - jdbcHelper.runUpdate(saveTableSql(version));
|
|
| 155 | - } catch (Exception e) {
|
|
| 156 | - throw new TopiaException(String.format("Could not save version %s", version), e);
|
|
| 157 | - }
|
|
| 158 | - }
|
|
| 159 | - |
|
| 160 | - default void save(TopiaSqlSupport sqlSupport, String version) {
|
|
| 161 | - try {
|
|
| 162 | - sqlSupport.executeSql(saveTableSql(version));
|
|
| 163 | - } catch (Exception e) {
|
|
| 164 | - throw new TopiaException(String.format("Could not save version %s", version), e);
|
|
| 165 | - }
|
|
| 166 | - }
|
|
| 167 | - |
|
| 168 | 195 | default boolean isTableExist(JdbcHelper jdbcHelper) {
|
| 169 | 196 | try {
|
| 170 | 197 | return jdbcHelper.isTableExist(schemaName(), tableName());
|
| ... | ... | @@ -181,27 +208,35 @@ public interface MigrationServiceSqlHelper { |
| 181 | 208 | }
|
| 182 | 209 | }
|
| 183 | 210 | |
| 184 | - default void createSchema(JdbcHelper jdbcHelper) {
|
|
| 211 | + default void createSchema(TopiaSqlSupport sqlSupport) {
|
|
| 185 | 212 | try {
|
| 186 | - jdbcHelper.runUpdate(createSchemaSql());
|
|
| 213 | + sqlSupport.executeSql(createSchemaSql());
|
|
| 187 | 214 | } catch (Exception e) {
|
| 188 | - throw new TopiaException(String.format("Could not create version table %s", gav()), e);
|
|
| 215 | + throw new TopiaException(String.format("Could not create version schema %s", gav()), e);
|
|
| 189 | 216 | }
|
| 190 | 217 | }
|
| 191 | 218 | |
| 192 | - default void createTable(JdbcHelper jdbcHelper) {
|
|
| 219 | + default void createTable(TopiaSqlSupport sqlSupport) {
|
|
| 193 | 220 | try {
|
| 194 | - jdbcHelper.runUpdate(createTableSql());
|
|
| 221 | + sqlSupport.executeSql(createTableSql());
|
|
| 195 | 222 | } catch (Exception e) {
|
| 196 | 223 | throw new TopiaException(String.format("Could not create version table %s", gav()), e);
|
| 197 | 224 | }
|
| 198 | 225 | }
|
| 199 | 226 | |
| 200 | - default void dropTable(JdbcHelper jdbcHelper) {
|
|
| 227 | + default void dropTable(TopiaSqlSupport sqlSupport) {
|
|
| 201 | 228 | try {
|
| 202 | - jdbcHelper.runUpdate(dropTableSql());
|
|
| 229 | + sqlSupport.executeSql(dropTableSql());
|
|
| 203 | 230 | } catch (Exception e) {
|
| 204 | 231 | throw new TopiaException(String.format("Could not drop version table %s", gav()), e);
|
| 205 | 232 | }
|
| 206 | 233 | }
|
| 234 | + |
|
| 235 | + default void save(TopiaSqlSupport sqlSupport, String version, Date date) {
|
|
| 236 | + try {
|
|
| 237 | + sqlSupport.executeSql(saveTableSql(version, date));
|
|
| 238 | + } catch (Exception e) {
|
|
| 239 | + throw new TopiaException(String.format("Could not save version %s", version), e);
|
|
| 240 | + }
|
|
| 241 | + }
|
|
| 207 | 242 | } |
| ... | ... | @@ -25,6 +25,7 @@ package org.nuiton.topia.service.migration.version; |
| 25 | 25 | import io.ultreia.java4all.util.Version;
|
| 26 | 26 | |
| 27 | 27 | import java.io.Serializable;
|
| 28 | +import java.util.Date;
|
|
| 28 | 29 | |
| 29 | 30 | /**
|
| 30 | 31 | * @author Tony Chemit - dev@tchemit.fr
|
| ... | ... | @@ -33,27 +34,23 @@ public class TMSVersion implements Serializable { |
| 33 | 34 | |
| 34 | 35 | private static final long serialVersionUID = 1L;
|
| 35 | 36 | |
| 36 | - private String version;
|
|
| 37 | + private final Version version;
|
|
| 38 | + private final Date date;
|
|
| 37 | 39 | |
| 38 | - public TMSVersion() {
|
|
| 39 | - }
|
|
| 40 | - |
|
| 41 | - public TMSVersion(String version) {
|
|
| 40 | + public TMSVersion(String version, Date date) {
|
|
| 42 | 41 | if (version == null || version.isEmpty()) {
|
| 43 | 42 | throw new IllegalArgumentException("version parameter can not be null nor empty.");
|
| 44 | 43 | }
|
| 45 | - this.version = version;
|
|
| 44 | + this.version = Version.valueOf(version);
|
|
| 45 | + this.date = date;
|
|
| 46 | 46 | }
|
| 47 | 47 | |
| 48 | - public String getVersion() {
|
|
| 48 | + public Version getVersion() {
|
|
| 49 | 49 | return version;
|
| 50 | 50 | }
|
| 51 | 51 | |
| 52 | - public void setVersion(String version) {
|
|
| 53 | - this.version = version;
|
|
| 52 | + public Date getDate() {
|
|
| 53 | + return date;
|
|
| 54 | 54 | }
|
| 55 | 55 | |
| 56 | - public Version toVersion() {
|
|
| 57 | - return version == null || version.isEmpty() ? null : Version.valueOf(version);
|
|
| 58 | - }
|
|
| 59 | 56 | } |
| ... | ... | @@ -29,6 +29,8 @@ import org.nuiton.topia.service.sql.internal.SqlRequestConsumer; |
| 29 | 29 | import org.nuiton.topia.service.sql.internal.SqlRequestSetConsumerContext;
|
| 30 | 30 | import org.nuiton.topia.service.sql.internal.request.AddVersionTableRequest;
|
| 31 | 31 | |
| 32 | +import java.util.Date;
|
|
| 33 | + |
|
| 32 | 34 | /**
|
| 33 | 35 | * Created on 21/02/2021.
|
| 34 | 36 | *
|
| ... | ... | @@ -42,7 +44,7 @@ public class AddVersionTableConsumer implements SqlRequestConsumer<AddVersionTab |
| 42 | 44 | try {
|
| 43 | 45 | SqlScriptWriter writer = context.getWriter();
|
| 44 | 46 | writer.writeSql(MigrationServiceSqlHelper.CURRENT.createTableSql());
|
| 45 | - writer.writeSql(MigrationServiceSqlHelper.CURRENT.fillVersionSql(request.getDbVersion().getVersion()));
|
|
| 47 | + writer.writeSql(MigrationServiceSqlHelper.CURRENT.saveTableSql(request.getDbVersion().getVersion(), new Date()));
|
|
| 46 | 48 | } catch (Exception e) {
|
| 47 | 49 | throw new TopiaException(String.format("Could not add version table for reason: %s", e.getMessage()), e);
|
| 48 | 50 | }
|