001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014 015package de.softwareforge.testing.postgres.embedded; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018 019import jakarta.annotation.Nonnull; 020import java.io.IOException; 021import java.util.Set; 022import java.util.function.Consumer; 023import javax.sql.DataSource; 024 025import com.google.common.collect.ImmutableList; 026import org.flywaydb.core.Flyway; 027import org.flywaydb.core.api.FlywayException; 028import org.flywaydb.core.api.configuration.FluentConfiguration; 029 030/** 031 * An {@link EmbeddedPostgresPreparer<DataSource>} that uses the <a href="https://flywaydb.org/">Flyway version control for your database</a> framework to 032 * migrate a data source to a known state. 033 */ 034public final class FlywayPreparer implements EmbeddedPostgresPreparer<DataSource> { 035 036 private final ImmutableList.Builder<Consumer<FluentConfiguration>> customizers = ImmutableList.builder(); 037 038 /** 039 * Creates a new instance using one or more classpath locations. 040 * 041 * @param locations One or more locations on the classpath. 042 * @return A {@link FlywayPreparer} instance. 043 */ 044 @Nonnull 045 public static FlywayPreparer forClasspathLocation(String... locations) { 046 FlywayPreparer preparer = new FlywayPreparer(); 047 preparer.addCustomizer(c -> c.locations(locations)); 048 return preparer; 049 } 050 051 /** 052 * Create a new, uninitialized preparer instance. Use {@link FlywayPreparer#addCustomizer(Consumer)} to modify the configuration for the 053 * {@link FluentConfiguration} object. 054 */ 055 public FlywayPreparer() { 056 } 057 058 /** 059 * Add a customizer instance. Each customizer is called once with the {@link FluentConfiguration} instance before setting the datasource and calling 060 * {@link FluentConfiguration#load()} and {@link Flyway#migrate()}. 061 * 062 * @param customizer A {@link Consumer<FluentConfiguration>} instance. Must not be null. 063 * @return This object. 064 * @since 3.0 065 */ 066 @Nonnull 067 public FlywayPreparer addCustomizer(@Nonnull Consumer<FluentConfiguration> customizer) { 068 checkNotNull(customizer, "customizer is null"); 069 customizers.add(customizer); 070 071 return this; 072 } 073 074 /** 075 * Add customizer instances. Each customizer is called once with the {@link FluentConfiguration} instance before setting the datasource and calling 076 * {@link FluentConfiguration#load()} and {@link Flyway#migrate()}. 077 * 078 * @param customizers A set of {@link Consumer<FluentConfiguration>} instances. Must not be null. 079 * @return This object. 080 * @since 3.0 081 */ 082 @Nonnull 083 public FlywayPreparer addCustomizers(@Nonnull Set<Consumer<FluentConfiguration>> customizers) { 084 checkNotNull(customizers, "customizers is null"); 085 customizers.addAll(customizers); 086 087 return this; 088 } 089 090 @Override 091 public void prepare(@Nonnull DataSource dataSource) throws IOException { 092 checkNotNull(dataSource, "dataSource is null"); 093 094 try { 095 final FluentConfiguration config = Flyway.configure(); 096 097 customizers.build().forEach(c -> c.accept(config)); 098 099 config.dataSource(dataSource); 100 Flyway flyway = config.load(); 101 flyway.migrate(); 102 103 } catch (FlywayException e) { 104 throw new IOException(e); 105 } 106 } 107}