[jOOQ/jOOQ#9506] More work on Migrations API:

- Improved DefaultMigrationContext::toString
- Updated TODO list
- Added migration client info to HISTORY table
- Handle missing decrements
- Throw exception when attempting to decrement a deletion (for now)
- Ignore snapshots when backwards migrating
This commit is contained in:
Lukas Eder 2024-11-26 13:11:33 +01:00
parent d0cdd0c820
commit a822575123
7 changed files with 135 additions and 52 deletions

View File

@ -422,11 +422,6 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
@ -456,6 +451,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
@ -494,7 +492,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
// [#9506] Migrations from root to a snapshot can be skipped
// TODO: effectively skip all intermediary steps
// TODO: Support pathHistory
if (isRoot && anyMatch(commitFiles, f -> f.type() == SNAPSHOT)) {
result.clear();
@ -530,7 +530,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
tempHistory.remove(path);
deletions.remove();
// TODO: Support pathHistory
}
}
@ -551,11 +553,28 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
increments.remove();
if (pathHistory != null)
pathHistory.computeIfAbsent(path, p -> new LinkedHashMap<>()).put(commit.id(), file);
}
}
// Schema files
Iterator<File> schemas = commitFiles.iterator();
while (schemas.hasNext()) {
@ -576,8 +595,10 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
schemas.remove();
if (pathHistory != null)
pathHistory.computeIfAbsent(path, p -> new LinkedHashMap<>()).put(commit.id(), file);
}
}

View File

@ -129,7 +129,7 @@ final class DefaultMigrationContext extends AbstractScope implements MigrationCo
sb.append(
"MigrationContext for migration from: " + migrationFrom + " to " + migrationTo + "\n"
+ "Migration queries:\n" + migrationQueries
+ "Migration queries:\n" + migrationQueries + "\n"
+ "Revert untracked queries:\n" + revertUntrackedQueries
);

View File

@ -65,9 +65,10 @@ class History extends TableImpl<HistoryRecord> {
final TableField<HistoryRecord, String> MIGRATED_TO = createField(DSL.name("MIGRATED_TO"), SQLDataType.VARCHAR(255).nullable(false), this, "The current database version ID.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
* The column <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>. A
* message associated with the migration execution.
*/
final TableField<HistoryRecord, String> MIGRATED_TO_MESSAGE = createField(DSL.name("MIGRATED_TO_MESSAGE"), SQLDataType.CLOB.nullable(false), this, "");
final TableField<HistoryRecord, String> MIGRATED_TO_MESSAGE = createField(DSL.name("MIGRATED_TO_MESSAGE"), SQLDataType.CLOB.nullable(false), this, "A message associated with the migration execution.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_TAGS</code>. The
@ -81,6 +82,18 @@ class History extends TableImpl<HistoryRecord> {
*/
final TableField<HistoryRecord, Long> MIGRATION_TIME = createField(DSL.name("MIGRATION_TIME"), SQLDataType.BIGINT, this, "The time in milliseconds it took to migrate to this database version.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.CLIENT_USER_NAME</code>. The
* client user name that was running the migration.
*/
final TableField<HistoryRecord, String> CLIENT_USER_NAME = createField(DSL.name("CLIENT_USER_NAME"), SQLDataType.VARCHAR(255), this, "The client user name that was running the migration.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.CLIENT_HOST_NAME</code>. The
* client host name that was running the migration.
*/
final TableField<HistoryRecord, String> CLIENT_HOST_NAME = createField(DSL.name("CLIENT_HOST_NAME"), SQLDataType.VARCHAR(255), this, "The client host name that was running the migration.");
/**
* The column <code>JOOQ_MIGRATION_HISTORY.JOOQ_VERSION</code>. The jOOQ
* version used to migrate to this database version.

View File

@ -86,7 +86,8 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
* Setter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>. A
* message associated with the migration execution.
*/
HistoryRecord setMigratedToMessage(String value) {
set(4, value);
@ -94,7 +95,8 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
}
/**
* Getter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>.
* Getter for <code>JOOQ_MIGRATION_HISTORY.MIGRATED_TO_MESSAGE</code>. A
* message associated with the migration execution.
*/
String getMigratedToMessage() {
return (String) get(4);
@ -134,12 +136,46 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
return (Long) get(6);
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.CLIENT_USER_NAME</code>. The
* client user name that was running the migration.
*/
HistoryRecord setClientUserName(String value) {
set(7, value);
return this;
}
/**
* Getter for <code>JOOQ_MIGRATION_HISTORY.CLIENT_USER_NAME</code>. The
* client user name that was running the migration.
*/
String getClientUserName() {
return (String) get(7);
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.CLIENT_HOST_NAME</code>. The
* client host name that was running the migration.
*/
HistoryRecord setClientHostName(String value) {
set(8, value);
return this;
}
/**
* Getter for <code>JOOQ_MIGRATION_HISTORY.CLIENT_HOST_NAME</code>. The
* client host name that was running the migration.
*/
String getClientHostName() {
return (String) get(8);
}
/**
* Setter for <code>JOOQ_MIGRATION_HISTORY.JOOQ_VERSION</code>. The jOOQ
* version used to migrate to this database version.
*/
HistoryRecord setJooqVersion(String value) {
set(7, value);
set(9, value);
return this;
}
@ -148,7 +184,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version used to migrate to this database version.
*/
String getJooqVersion() {
return (String) get(7);
return (String) get(9);
}
/**
@ -156,7 +192,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* that were run to install this database version.
*/
HistoryRecord setSql(String value) {
set(8, value);
set(10, value);
return this;
}
@ -165,7 +201,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* that were run to install this database version.
*/
String getSql() {
return (String) get(8);
return (String) get(10);
}
/**
@ -173,7 +209,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* SQL statements that were run to install this database version.
*/
HistoryRecord setSqlCount(Integer value) {
set(9, value);
set(11, value);
return this;
}
@ -182,7 +218,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* SQL statements that were run to install this database version.
*/
Integer getSqlCount() {
return (Integer) get(9);
return (Integer) get(11);
}
/**
@ -190,7 +226,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version installation status.
*/
HistoryRecord setStatus(HistoryStatus value) {
set(10, value);
set(12, value);
return this;
}
@ -199,7 +235,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* version installation status.
*/
HistoryStatus getStatus() {
return (HistoryStatus) get(10);
return (HistoryStatus) get(12);
}
/**
@ -207,7 +243,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* or error message explaining the status.
*/
HistoryRecord setStatusMessage(String value) {
set(11, value);
set(13, value);
return this;
}
@ -216,7 +252,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* or error message explaining the status.
*/
String getStatusMessage() {
return (String) get(11);
return (String) get(13);
}
/**
@ -224,7 +260,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* resolution, if any.
*/
HistoryRecord setResolution(HistoryResolution value) {
set(12, value);
set(14, value);
return this;
}
@ -233,7 +269,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* resolution, if any.
*/
HistoryResolution getResolution() {
return (HistoryResolution) get(12);
return (HistoryResolution) get(14);
}
/**
@ -241,7 +277,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* info or error message explaining the resolution.
*/
HistoryRecord setResolutionMessage(String value) {
set(13, value);
set(15, value);
return this;
}
@ -250,7 +286,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
* info or error message explaining the resolution.
*/
String getResolutionMessage() {
return (String) get(13);
return (String) get(15);
}
// -------------------------------------------------------------------------
@ -276,7 +312,7 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
/**
* Create a detached, initialised HistoryRecord
*/
HistoryRecord(Integer id, Timestamp migratedAt, String migratedFrom, String migratedTo, String migratedToMessage, String migratedToTags, Long migrationTime, String jooqVersion, String sql, Integer sqlCount, HistoryStatus status, String statusMessage, HistoryResolution resolution, String resolutionMessage) {
HistoryRecord(Integer id, Timestamp migratedAt, String migratedFrom, String migratedTo, String migratedToMessage, String migratedToTags, Long migrationTime, String clientUserName, String clientHostName, String jooqVersion, String sql, Integer sqlCount, HistoryStatus status, String statusMessage, HistoryResolution resolution, String resolutionMessage) {
super(History.HISTORY);
setId(id);
@ -286,6 +322,8 @@ class HistoryRecord extends UpdatableRecordImpl<HistoryRecord> {
setMigratedToMessage(migratedToMessage);
setMigratedToTags(migratedToTags);
setMigrationTime(migrationTime);
setClientUserName(clientUserName);
setClientHostName(clientHostName);
setJooqVersion(jooqVersion);
setSql(sql);
setSqlCount(sqlCount);

View File

@ -58,6 +58,8 @@ import static org.jooq.tools.StringUtils.isEmpty;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.HashSet;
@ -345,13 +347,8 @@ final class MigrationImpl extends AbstractScope implements Migration {
// TODO: Implement preconditions
// TODO: Implement a listener with a variety of pro / oss features
// TODO: Implement additional out-of-the-box sanity checks
// TODO: Allow undo migrations only if enabled explicitly
// TODO: Add some migration settings, e.g. whether HISTORY.SQL should be filled
// TODO: Migrate the HISTORY table with the Migration API
// TODO: Create an Enum for HISTORY.STATUS
// TODO: Add HISTORY.USERNAME and HOSTNAME columns
// TODO: Add HISTORY.COMMENTS column
// TODO: Replace (MIGRATED_AT, MIGRATION_TIME) by (MIGRATION_START, MIGRATION_END)
if (log.isInfoEnabled()) {
Commit snapshot = fromSnapshot();
@ -408,6 +405,14 @@ final class MigrationImpl extends AbstractScope implements Migration {
private final HistoryRecord createRecord(HistoryStatus status) {
HistoryRecord record = history.historyCtx.newRecord(HISTORY);
String hostName;
try {
hostName = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e) {
hostName = "unknown";
}
record
.setJooqVersion(Constants.VERSION)
@ -417,6 +422,8 @@ final class MigrationImpl extends AbstractScope implements Migration {
.setMigratedToMessage(to().message())
.setMigratedToTags(new JSONArray(map(to().tags(), Tag::id)).toString())
.setMigrationTime(0L)
.setClientUserName(System.getProperty("user.name"))
.setClientHostName(hostName)
.setSql(queries().toString())
.setSqlCount(queries().queries().length)
.setStatus(status)

View File

@ -6,6 +6,8 @@ CREATE TABLE jooq_migration_history (
migrated_to_message CLOB NOT NULL,
migrated_to_tags CLOB NOT NULL,
migration_time BIGINT NULL,
client_user_name VARCHAR(255) NULL,
client_host_name VARCHAR(255) NULL,
jooq_version VARCHAR(50) NOT NULL,
sql CLOB NULL,
sql_count INT NOT NULL,
@ -19,19 +21,20 @@ CREATE TABLE jooq_migration_history (
CONSTRAINT jooq_migr_hist_chk2 CHECK (resolution IN ('OPEN', 'RESOLVED', 'IGNORED'))
);
CREATE INDEX jooq_migr_hist_i1 ON jooq_migration_history (migrated_at);
COMMENT ON TABLE jooq_migration_history IS 'The migration history of jOOQ Migrations.';
COMMENT ON COLUMN jooq_migration_history.id IS 'The database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_at IS 'The date/time when the database version was migrated to.';
COMMENT ON COLUMN jooq_migration_history.migrated_from IS 'The previous database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_to IS 'The current database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_to_tags IS 'The current database version tags, if any, in JSON array format.';
COMMENT ON COLUMN jooq_migration_history.migration_time IS 'The time in milliseconds it took to migrate to this database version.';
COMMENT ON COLUMN jooq_migration_history.jooq_version IS 'The jOOQ version used to migrate to this database version.';
COMMENT ON COLUMN jooq_migration_history.sql_count IS 'The number of SQL statements that were run to install this database version.';
COMMENT ON COLUMN jooq_migration_history.sql IS 'The SQL statements that were run to install this database version.';
COMMENT ON COLUMN jooq_migration_history.status IS 'The database version installation status.';
COMMENT ON COLUMN jooq_migration_history.status_message IS 'Any info or error message explaining the status.';
COMMENT ON COLUMN jooq_migration_history.resolution IS 'The error resolution, if any.';
COMMENT ON COLUMN jooq_migration_history.resolution_message IS 'Any info or error message explaining the resolution.';
COMMENT ON TABLE jooq_migration_history IS 'The migration history of jOOQ Migrations.';
COMMENT ON COLUMN jooq_migration_history.id IS 'The database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_at IS 'The date/time when the database version was migrated to.';
COMMENT ON COLUMN jooq_migration_history.migrated_from IS 'The previous database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_to IS 'The current database version ID.';
COMMENT ON COLUMN jooq_migration_history.migrated_to_message IS 'A message associated with the migration execution.';
COMMENT ON COLUMN jooq_migration_history.migrated_to_tags IS 'The current database version tags, if any, in JSON array format.';
COMMENT ON COLUMN jooq_migration_history.migration_time IS 'The time in milliseconds it took to migrate to this database version.';
COMMENT ON COLUMN jooq_migration_history.client_user_name IS 'The client user name that was running the migration.';
COMMENT ON COLUMN jooq_migration_history.client_host_name IS 'The client host name that was running the migration.';
COMMENT ON COLUMN jooq_migration_history.jooq_version IS 'The jOOQ version used to migrate to this database version.';
COMMENT ON COLUMN jooq_migration_history.sql IS 'The SQL statements that were run to install this database version.';
COMMENT ON COLUMN jooq_migration_history.sql_count IS 'The number of SQL statements that were run to install this database version.';
COMMENT ON COLUMN jooq_migration_history.status IS 'The database version installation status.';
COMMENT ON COLUMN jooq_migration_history.status_message IS 'Any info or error message explaining the status.';
COMMENT ON COLUMN jooq_migration_history.resolution IS 'The error resolution, if any.';
COMMENT ON COLUMN jooq_migration_history.resolution_message IS 'Any info or error message explaining the resolution.';

View File

@ -0,0 +1 @@
CREATE INDEX jooq_migr_hist_i1 ON jooq_migration_history (migrated_at);