NativeConnectorsMigrationInfoService.java
/*-
* ========================LICENSE_START=================================
* flyway-nc-core
* ========================================================================
* Copyright (C) 2010 - 2025 Red Gate Software Ltd
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/
package org.flywaydb.nc.info;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.flywaydb.core.api.CoreMigrationType;
import org.flywaydb.core.api.MigrationFilter;
import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.MigrationInfoService;
import org.flywaydb.core.api.MigrationState;
import org.flywaydb.core.api.configuration.Configuration;
import org.flywaydb.core.api.output.CommandResultFactory;
import org.flywaydb.core.api.output.InfoResult;
import org.flywaydb.core.internal.nc.NativeConnectorsMigrationInfoFilter;
public class NativeConnectorsMigrationInfoService implements MigrationInfoService {
private final MigrationInfo[] allMigrations;
private final Configuration configuration;
private final MigrationInfo[] applicableMigrations;
private final String databaseName;
private final Boolean allSchemasEmpty;
public NativeConnectorsMigrationInfoService(final MigrationInfo[] migrations,
final Configuration configuration,
final String databaseName,
final Boolean allSchemasEmpty) {
this.allMigrations = migrations;
this.configuration = configuration;
this.allSchemasEmpty = allSchemasEmpty;
applicableMigrations = getApplicableMigrations(migrations, configuration);
this.databaseName = databaseName;
}
private MigrationInfo[] getApplicableMigrations(final MigrationInfo[] migrations,
final Configuration configuration) {
final MigrationInfo[] applicableMigrations;
final List<NativeConnectorsMigrationInfoFilter> filters = configuration.getPluginRegister()
.getLicensedPlugins(NativeConnectorsMigrationInfoFilter.class, configuration);
MigrationInfo[] tempMigrations = Arrays.copyOf(migrations, migrations.length);
for (final NativeConnectorsMigrationInfoFilter filter : filters) {
final Predicate<MigrationInfo> predicate = filter.getFilter(configuration);
tempMigrations = Arrays.stream(tempMigrations).filter(predicate).toArray(MigrationInfo[]::new);
}
applicableMigrations = tempMigrations;
return applicableMigrations;
}
@Override
public MigrationInfo[] all() {
return allMigrations.clone();
}
@Override
public MigrationInfo[] all(final MigrationFilter filter) {
return Arrays.stream(allMigrations).filter(filter::matches).toArray(MigrationInfo[]::new);
}
@Override
public MigrationInfo current() {
MigrationInfo current = null;
for (final MigrationInfo migrationInfo : allMigrations) {
if (migrationInfo.getState().isApplied()
&& !MigrationState.DELETED.equals(migrationInfo.getState())
&& !migrationInfo.getType().equals(CoreMigrationType.DELETE)
&& !MigrationState.UNDONE.equals(migrationInfo.getState())
&& !migrationInfo.getType().isUndo()
&& migrationInfo.isVersioned()
&& (current == null || migrationInfo.getVersion().compareTo(current.getVersion()) > 0)) {
current = migrationInfo;
}
}
if (current != null) {
return current;
}
// If no versioned migration has been applied so far, fall back to the latest repeatable one
for (int i = allMigrations.length - 1; i >= 0; i--) {
final MigrationInfo migrationInfo = allMigrations[i];
if (migrationInfo.getState().isApplied()
&& !MigrationState.DELETED.equals(migrationInfo.getState())
&& !migrationInfo.getType().equals(CoreMigrationType.DELETE)
&& !MigrationState.UNDONE.equals(migrationInfo.getState())
&& migrationInfo.getVersion() == null) {
return migrationInfo;
}
}
return null;
}
@Override
public MigrationInfo[] pending() {
return Arrays.stream(applicableMigrations)
.filter(migrationInfo -> MigrationState.PENDING == migrationInfo.getState())
.toArray(MigrationInfo[]::new);
}
@Override
public MigrationInfo[] applied() {
return Arrays.stream(applicableMigrations).filter(x -> x.getState().isApplied()).toArray(MigrationInfo[]::new);
}
@Override
public InfoResult getInfoResult() {
return getInfoResult(all());
}
@Override
public InfoResult getInfoResult(final MigrationFilter filter) {
return getInfoResult(all(filter));
}
private InfoResult getInfoResult(MigrationInfo[] infos) {
return CommandResultFactory.createInfoResult(configuration, databaseName, infos, current(), allSchemasEmpty);
}
}