[jOOQ/jOOQ#9506] Fix mixing SCRIPT with SCHEMA

A SCRIPT is allowed to modify a schema that is otherwise managed by SCHEMA files. There must be a SCHEMA file documenting the outcome. Other than for that purpose, that SCHEMA file must be ignored, and no diff must be applied from the previously known SCHEMA file.

This currently only works if the SCHEMA and SCRIPT files are contained in the same Commit. It's currently not possible to fix a mistake, where the SCHEMA file has been forgotten, other than to edit the SCRIPT file.
This commit is contained in:
Lukas Eder 2024-11-27 14:26:03 +01:00
parent ab67f867de
commit 12b590548b
3 changed files with 51 additions and 6 deletions

View File

@ -66,6 +66,7 @@ import java.util.Set;
import org.jooq.Commit;
import org.jooq.Configuration;
import org.jooq.ContentType;
import org.jooq.DSLContext;
import org.jooq.File;
import org.jooq.Files;
@ -79,6 +80,9 @@ import org.jooq.exception.DataMigrationVerificationException;
import org.jooq.impl.DefaultParseContext.IgnoreQuery;
import org.jooq.tools.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Lukas Eder
*/
@ -572,7 +576,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
// Script files
Iterator<File> scripts = filter(commitFiles.iterator(), f -> f.type() == SCRIPT);
boolean hasScripts = false;
for (File file : iterable(scripts)) {
hasScripts = true;
String path = file.path();
File oldFile = recordingResult ? history.get(path) : history.put(path, file);
@ -594,6 +600,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
String path = file.path();
String key = commit.id() + "-" + path;
if (hasScripts)
file = new IgnoreFile(file);
if (recordingResult) {
tempHistory.put(path, file);
tempHistoryKeys.put(path, key);
@ -611,6 +620,9 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
}
if (hasScripts)
move(tempHistory, result, tempHistoryKeys);
recordingResult |= id().equals(commit.id());
}
@ -695,6 +707,28 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
}
}
private static final record IgnoreFile(File file) implements File {
@Override
public final String path() {
return file.path();
}
@Override
public final String name() {
return file.name();
}
@Override
public final String content() {
return file.content();
}
@Override
public final ContentType type() {
return file.type();
}
}
private final Version version(Version from, String newId, Map<String, File> files, Iterable<File> result) {
Version to = from;
@ -704,8 +738,14 @@ final class CommitImpl extends AbstractNode<Commit> implements Commit {
// Version IDs per file path. It doesn't seem to be necessary anymore.
// String commitId = newId + "-" + file.path();
if (file.type() == SCHEMA)
to = to.commit(newId, sources(apply(files, file, true).values()).toArray(EMPTY_SOURCE));
if (file.type() == SCHEMA) {
Meta meta = ctx.meta(sources(apply(files, file, true).values()).toArray(EMPTY_SOURCE));
if (file instanceof IgnoreFile)
to = ((VersionImpl) to).commit(newId, meta, ctx.queries());
else
to = to.commit(newId, meta);
}
// [#9506] Scripts must be ignored by the interpreter
else if (file.type() == SCRIPT)

View File

@ -366,7 +366,8 @@ final class MigrationImpl extends AbstractScope implements Migration {
if (from().equals(to())) {
if (log.isInfoEnabled())
log.info("jOOQ Migrations", "Version " + to().id() + " is already installed as the current version.");
log.info("Version " + to().id() + " is already installed as the current version.");
return;
}
@ -378,7 +379,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
if (log.isInfoEnabled()) {
Commit snapshot = fromSnapshot();
log.info("jOOQ Migrations", "Version " + from().id() + " is being migrated to " + to().id() + (snapshot != null ? " (from snapshot: " + snapshot.id() + ")" : ""));
log.info("Version " + from().id() + " is being migrated to " + to().id() + (snapshot != null ? " (from snapshot: " + snapshot.id() + ")" : ""));
}
StopWatch watch = new StopWatch();
@ -386,7 +387,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
// TODO: Make logging configurable
if (log.isDebugEnabled())
for (Query query : queries())
log.debug("jOOQ Migrations", dsl().renderInlined(query));
log.debug(dsl().renderInlined(query));
HistoryRecord record = createRecord(STARTING);
@ -402,7 +403,7 @@ final class MigrationImpl extends AbstractScope implements Migration {
e.printStackTrace(new PrintWriter(s));
if (log.isErrorEnabled())
log.error("jOOQ Migrations", "Version " + from().id() + " migration to " + to().id() + " failed: " + e.getMessage());
log.error("Version " + from().id() + " migration to " + to().id() + " failed: " + e.getMessage());
log(watch, record, FAILURE, OPEN, s.toString());
throw new DataMigrationRedoLogException(record, e);

View File

@ -227,6 +227,10 @@ final class VersionImpl extends AbstractNode<Version> implements Version {
return new VersionImpl(ctx.configuration(), newId, newMeta, root, new Version[] { this });
}
final Version commit(String newId, Meta newMeta, Queries migration) {
return new VersionImpl(ctx.configuration(), newId, newMeta, root, this, migration);
}
@Override
public final Version merge(String newId, Version with) {
Meta m = commonAncestor(with).meta();