Search in sources :

Example 1 with Pair

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();
        }
    }
}
Also used : Pair(org.flywaydb.core.internal.util.Pair) AppliedMigration(org.flywaydb.core.internal.schemahistory.AppliedMigration) ResolvedMigration(org.flywaydb.core.api.resolver.ResolvedMigration)

Example 2 with Pair

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);
}
Also used : Context(org.flywaydb.core.api.resolver.Context) MigrationInfoServiceImpl(org.flywaydb.core.internal.info.MigrationInfoServiceImpl) ArrayList(java.util.ArrayList) ErrorDetails(org.flywaydb.core.api.ErrorDetails) StopWatch(org.flywaydb.core.internal.util.StopWatch) ValidateOutput(org.flywaydb.core.api.output.ValidateOutput) ArrayList(java.util.ArrayList) List(java.util.List) Pair(org.flywaydb.core.internal.util.Pair)

Example 3 with Pair

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;
}
Also used : Configuration(org.flywaydb.core.api.configuration.Configuration) MigrationVersion(org.flywaydb.core.api.MigrationVersion) java.util(java.util) Event(org.flywaydb.core.api.callback.Event) Pair(org.flywaydb.core.internal.util.Pair) Event(org.flywaydb.core.api.callback.Event) Pair(org.flywaydb.core.internal.util.Pair)

Aggregations

Pair (org.flywaydb.core.internal.util.Pair)3 java.util (java.util)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 ErrorDetails (org.flywaydb.core.api.ErrorDetails)1 MigrationVersion (org.flywaydb.core.api.MigrationVersion)1 Event (org.flywaydb.core.api.callback.Event)1 Configuration (org.flywaydb.core.api.configuration.Configuration)1 ValidateOutput (org.flywaydb.core.api.output.ValidateOutput)1 Context (org.flywaydb.core.api.resolver.Context)1 ResolvedMigration (org.flywaydb.core.api.resolver.ResolvedMigration)1 MigrationInfoServiceImpl (org.flywaydb.core.internal.info.MigrationInfoServiceImpl)1 AppliedMigration (org.flywaydb.core.internal.schemahistory.AppliedMigration)1 StopWatch (org.flywaydb.core.internal.util.StopWatch)1