use of org.flywaydb.core.internal.util.Pair in project flyway by flyway.
the class MigrationInfoServiceImpl method refresh.
/**
* Refreshes the info about all known migrations from both the classpath and the DB.
*/
public void refresh() {
Collection<ResolvedMigration> resolvedMigrations = migrationResolver.resolveMigrations(context);
List<AppliedMigration> appliedMigrations = schemaHistory.allAppliedMigrations();
MigrationInfoContext context = new MigrationInfoContext();
context.outOfOrder = outOfOrder;
context.pending = pending;
context.missing = missing;
context.ignored = ignored;
context.future = future;
context.ignorePatterns = configuration.getIgnoreMigrationPatterns();
context.target = target;
context.cherryPick = cherryPick;
Map<Pair<MigrationVersion, Boolean>, ResolvedMigration> resolvedVersioned = new TreeMap<>();
Map<String, ResolvedMigration> resolvedRepeatable = new TreeMap<>();
ResolvedMigration pendingBaselineMigration = null;
AppliedMigration appliedBaselineMigration = null;
// Separate resolved migrations into versioned and repeatable
for (ResolvedMigration resolvedMigration : resolvedMigrations) {
MigrationVersion version = resolvedMigration.getVersion();
if (version != null) {
if (version.compareTo(context.lastResolved) > 0) {
context.lastResolved = version;
}
if (resolvedMigration.getType().isBaselineMigration() && version.compareTo(context.latestBaselineMigration) > 0) {
} else {
// noinspection RedundantConditionalExpression
resolvedVersioned.put(Pair.of(version, false), resolvedMigration);
}
} else {
resolvedRepeatable.put(resolvedMigration.getDescription(), resolvedMigration);
}
}
// Split applied into version and repeatable, and update state from synthetic migrations
List<Pair<AppliedMigration, AppliedMigrationAttributes>> appliedVersioned = new ArrayList<>();
List<Pair<AppliedMigration, AppliedMigrationAttributes>> appliedRepeatable = new ArrayList<>();
for (AppliedMigration appliedMigration : appliedMigrations) {
MigrationVersion version = appliedMigration.getVersion();
if (version == null) {
appliedRepeatable.add(Pair.of(appliedMigration, new AppliedMigrationAttributes()));
if (appliedMigration.getType().equals(MigrationType.DELETE) && appliedMigration.isSuccess()) {
markRepeatableAsDeleted(appliedMigration.getDescription(), appliedRepeatable);
}
continue;
}
if (appliedMigration.getType() == MigrationType.SCHEMA) {
context.schema = version;
}
if (appliedMigration.getType() == MigrationType.BASELINE) {
context.baseline = version;
}
if (appliedMigration.getType().equals(MigrationType.DELETE) && appliedMigration.isSuccess()) {
markAsDeleted(version, appliedVersioned);
}
appliedVersioned.add(Pair.of(appliedMigration, new AppliedMigrationAttributes()));
}
// Update last applied and out of order states
for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedVersioned) {
AppliedMigration appliedMigration = av.getLeft();
MigrationVersion version = appliedMigration.getVersion();
if (version != null) {
if (version.compareTo(context.lastApplied) > 0) {
if (av.getLeft().getType() != MigrationType.DELETE && !av.getRight().deleted) {
context.lastApplied = version;
}
} else {
av.getRight().outOfOrder = true;
}
}
}
// Set target
if (MigrationVersion.CURRENT == target) {
context.target = context.lastApplied;
}
// Identify pending versioned migrations and build output migration info list
List<MigrationInfoImpl> migrationInfos1 = new ArrayList<>();
Set<ResolvedMigration> pendingResolvedVersioned = new HashSet<>(resolvedVersioned.values());
for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedVersioned) {
ResolvedMigration resolvedMigration = resolvedVersioned.get(Pair.of(av.getLeft().getVersion(), av.getLeft().getType().isUndo()));
// Remove pending migrations
if (resolvedMigration != null && !av.getRight().deleted && av.getLeft().getType() != MigrationType.DELETE) {
pendingResolvedVersioned.remove(resolvedMigration);
}
// Build final migration info
migrationInfos1.add(new MigrationInfoImpl(resolvedMigration, av.getLeft(), context, av.getRight().outOfOrder, av.getRight().deleted, av.getRight().undone));
}
// Add all pending migrations to output list
for (ResolvedMigration prv : pendingResolvedVersioned) {
if (prv.getVersion().compareTo(context.latestBaselineMigration) <= 0) {
continue;
}
migrationInfos1.add(new MigrationInfoImpl(prv, null, context, false, false, false));
}
if (pendingBaselineMigration != null) {
migrationInfos1.add(new MigrationInfoImpl(pendingBaselineMigration, null, context, false, false, false));
}
if (configuration.isFailOnMissingTarget() && target != null && target != MigrationVersion.CURRENT && target != MigrationVersion.LATEST && target != MigrationVersion.NEXT) {
boolean targetFound = false;
for (MigrationInfoImpl migration : migrationInfos1) {
if (target.compareTo(migration.getVersion()) == 0) {
targetFound = true;
break;
}
}
if (!targetFound) {
throw new FlywayException("No migration with a target version " + target + " could be found. Ensure target is specified correctly and the migration exists.");
}
}
// Setup the latest repeatable run ranks
for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedRepeatable) {
if (av.getRight().deleted && av.getLeft().getType() == MigrationType.DELETE) {
continue;
}
AppliedMigration appliedRepeatableMigration = av.getLeft();
String desc = appliedRepeatableMigration.getDescription();
int rank = appliedRepeatableMigration.getInstalledRank();
Map<String, Integer> latestRepeatableRuns = context.latestRepeatableRuns;
if (!latestRepeatableRuns.containsKey(desc) || (rank > latestRepeatableRuns.get(desc))) {
latestRepeatableRuns.put(desc, rank);
}
}
// Using latest repeatable runs, discover pending repeatables and build output list
Set<ResolvedMigration> pendingResolvedRepeatable = new HashSet<>(resolvedRepeatable.values());
for (Pair<AppliedMigration, AppliedMigrationAttributes> av : appliedRepeatable) {
AppliedMigration appliedRepeatableMigration = av.getLeft();
String desc = appliedRepeatableMigration.getDescription();
int rank = appliedRepeatableMigration.getInstalledRank();
ResolvedMigration resolvedMigration = resolvedRepeatable.get(desc);
int latestRank = context.latestRepeatableRuns.get(desc);
// If latest run is the same rank, its not pending
if (!av.getRight().deleted && av.getLeft().getType() != MigrationType.DELETE && resolvedMigration != null && rank == latestRank && resolvedMigration.checksumMatches(appliedRepeatableMigration.getChecksum())) {
pendingResolvedRepeatable.remove(resolvedMigration);
}
// Add to output list
migrationInfos1.add(new MigrationInfoImpl(resolvedMigration, appliedRepeatableMigration, context, false, av.getRight().deleted, false));
}
// Add pending repeatables to output list
for (ResolvedMigration prr : pendingResolvedRepeatable) {
migrationInfos1.add(new MigrationInfoImpl(prr, null, context, false, false, false));
}
// Set output
Collections.sort(migrationInfos1);
migrationInfos = migrationInfos1;
if (context.target == MigrationVersion.NEXT) {
MigrationInfo[] pendingMigrationInfos = pending();
if (pendingMigrationInfos.length == 0) {
context.target = null;
} else {
context.target = pendingMigrationInfos[0].getVersion();
}
}
}
use of org.flywaydb.core.internal.util.Pair in project flyway by flyway.
the class DbValidate method validate.
/**
* Starts the actual migration.
*
* @return The validation error, if any.
*/
public ValidateResult validate() {
if (!schema.exists()) {
if (!migrationResolver.resolveMigrations(new Context() {
@Override
public Configuration getConfiguration() {
return configuration;
}
}).isEmpty() && !pending) {
String validationErrorMessage = "Schema " + schema + " doesn't exist yet";
ErrorDetails validationError = new ErrorDetails(ErrorCode.SCHEMA_DOES_NOT_EXIST, validationErrorMessage);
return CommandResultFactory.createValidateResult(database.getCatalog(), validationError, 0, null, new ArrayList<>());
}
return CommandResultFactory.createValidateResult(database.getCatalog(), null, 0, null, new ArrayList<>());
}
callbackExecutor.onEvent(Event.BEFORE_VALIDATE);
LOG.debug("Validating migrations ...");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Pair<Integer, List<ValidateOutput>> result = ExecutionTemplateFactory.createExecutionTemplate(connection.getJdbcConnection(), database).execute(new Callable<Pair<Integer, List<ValidateOutput>>>() {
@Override
public Pair<Integer, List<ValidateOutput>> call() {
MigrationInfoServiceImpl migrationInfoService = new MigrationInfoServiceImpl(migrationResolver, schemaHistory, database, configuration, configuration.getTarget(), configuration.isOutOfOrder(), configuration.getCherryPick(), pending, configuration.isIgnoreMissingMigrations(), configuration.isIgnoreIgnoredMigrations(), configuration.isIgnoreFutureMigrations());
migrationInfoService.refresh();
int count = migrationInfoService.all().length;
List<ValidateOutput> invalidMigrations = migrationInfoService.validate();
return Pair.of(count, invalidMigrations);
}
});
stopWatch.stop();
List<String> warnings = new ArrayList<>();
List<ValidateOutput> invalidMigrations = result.getRight();
ErrorDetails validationError = null;
int count = 0;
if (invalidMigrations.isEmpty()) {
count = result.getLeft();
if (count == 1) {
LOG.info(String.format("Successfully validated 1 migration (execution time %s)", TimeFormat.format(stopWatch.getTotalTimeMillis())));
} else {
LOG.info(String.format("Successfully validated %d migrations (execution time %s)", count, TimeFormat.format(stopWatch.getTotalTimeMillis())));
if (count == 0) {
String noMigrationsWarning = "No migrations found. Are your locations set up correctly?";
warnings.add(noMigrationsWarning);
LOG.warn(noMigrationsWarning);
}
}
callbackExecutor.onEvent(Event.AFTER_VALIDATE);
} else {
validationError = new ErrorDetails(ErrorCode.VALIDATE_ERROR, "Migrations have failed validation");
callbackExecutor.onEvent(Event.AFTER_VALIDATE_ERROR);
}
return CommandResultFactory.createValidateResult(database.getCatalog(), validationError, count, invalidMigrations, warnings);
}
use of org.flywaydb.core.internal.util.Pair in project flyway by flyway.
the class ResourceNameParser method populatePrefixes.
private List<Pair<String, ResourceType>> populatePrefixes(Configuration configuration) {
List<Pair<String, ResourceType>> prefixes = new ArrayList<>();
prefixes.add(Pair.of(configuration.getSqlMigrationPrefix(), ResourceType.MIGRATION));
prefixes.add(Pair.of(configuration.getRepeatableSqlMigrationPrefix(), ResourceType.REPEATABLE_MIGRATION));
for (Event event : Event.values()) {
prefixes.add(Pair.of(event.getId(), ResourceType.CALLBACK));
}
Comparator<Pair<String, ResourceType>> prefixComparator = (p1, p2) -> {
// Sort most-hard-to-match first; that is, in descending order of prefix length
return p2.getLeft().length() - p1.getLeft().length();
};
prefixes.sort(prefixComparator);
return prefixes;
}
Aggregations