Skip to content

Instantly share code, notes, and snippets.

@fuxingloh
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fuxingloh/25b1287673f62b2f9e03 to your computer and use it in GitHub Desktop.
Save fuxingloh/25b1287673f62b2f9e03 to your computer and use it in GitHub Desktop.
AutoMigration From PuffinCore
-- The first statement you need to run in your sql to setup migration.
CREATE TABLE Versioning (
migrated VARCHAR(255) NOT NULL,
appliedDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (migrated));
INSERT INTO Versioning (migrated) VALUES ('0.0.0.migration.sql');
//Auto migration tool copied from puffin core
// How to use?
// If you are using it for the first time, you need to run the 0.0.0.migration.sql manually in your sql
// Create a folder called migration in your working directory
// You can start creating migration script and place it in the migration folder
// Pattern for script must always be <major>.<minor>.<fixes>.migration.sql
// <major>.<minor>.<fixes> must be in increasing order
// E.g.
// 0.0.0.migration.sql
// 0.1.0.migration.sql
// 0.1.5.migration.sql
// 0.3.0.migration.sql
// 1.0.0.migration.sql
// 1.10.2.migration.sql
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.io.IOException;
import java.sql.*;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Created by Fuxing
* Date: 3/7/2015
* Time: 8:00 PM
* Project: puffin-core
*/
public class AutoMigration {
private static final String PERSISTENCE = "META-INF/persistence.xml";
private static final String MIGRATION_FOLDER = "migration";
public static void main(String[] args) throws Exception {
try (Connection connection = getConnection()) {
AutoMigration auto = new AutoMigration(connection);
String version = auto.getLatestVersion();
System.out.println("Current latest version: " + version);
List<String> migrationList = auto.getMigrateList(version);
// Check if there is anything migration
if (!migrationList.isEmpty()) {
for (String file : migrationList) {
String statementString = auto.readStatementFromFile(file);
System.out.println("\n\nExecuting: migration/" + file);
System.out.println(statementString);
connection.createStatement().execute(statementString);
auto.addVersion(file);
System.out.println("Completed: " + file);
Thread.sleep(500);
}
} else {
System.out.println("Your current version is the latest version.");
}
}
}
private final Pattern filePattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.migration.sql");
private Connection connection;
public AutoMigration(Connection connection) {
this.connection = connection;
}
public String readStatementFromFile(String version) throws IOException {
return FileUtils.readFileToString(new File(MIGRATION_FOLDER + "/" + version));
}
public List<String> getMigrations() {
File directory = new File(MIGRATION_FOLDER);
return Arrays.stream(directory.list()).filter(f -> filePattern.matcher(f).matches()).collect(Collectors.toList());
}
/**
* @param version version after
* @return list to migrate
*/
public List<String> getMigrateList(String version) {
Pair<String, Boolean> pair = MutablePair.of(version, false);
List<String> list = getMigrations().stream().sorted().filter(s -> {
if (version.equals(s)) {
pair.setValue(true);
return false;
}
return pair.getRight();
}).collect(Collectors.toList());
if (!pair.getRight()) {
throw new RuntimeException("Local migration list is different from database.");
}
return list;
}
/**
* @return get current latest version
* @throws SQLException
*/
public String getLatestVersion() throws SQLException {
Statement statement = connection.createStatement();
try {
statement.execute("SELECT * FROM Versioning ORDER BY appliedDate desc LIMIT 1");
} catch (SQLException ex) {
if (ex.getLocalizedMessage().contains("Versioning")) {
throw new RuntimeException("Table don't exist?, you need to create it you can find the script on top.");
} else {
throw ex;
}
}
ResultSet resultSet = statement.getResultSet();
if (!resultSet.next()) {
throw new RuntimeException("Versioning data is not available in sql!");
}
String version = resultSet.getString("migrated");
if (!filePattern.matcher(version).matches()) {
throw new RuntimeException("");
}
return version;
}
/**
* @param version version to add
* @throws SQLException
*/
public void addVersion(String version) throws SQLException {
PreparedStatement prepared = connection.prepareStatement("INSERT INTO Versioning (migrated) VALUES (?)");
prepared.setString(1, version);
prepared.execute();
}
/**
* @return get Connection from persistence file
* @throws Exception
*/
public static Connection getConnection() throws ConfigurationException, ClassNotFoundException, InterruptedException, SQLException {
final XMLConfiguration configuration = new XMLConfiguration(PERSISTENCE);
final List<HierarchicalConfiguration> configList = configuration.configurationsAt("persistence-unit.properties.property");
String username = null;
String url = null;
String password = null;
// Get username, url and password
for (HierarchicalConfiguration hier : configList) {
if (hier.getString("[@name]").equals("hibernate.hikari.dataSource.user")) {
username = hier.getString("[@value]");
}
if (hier.getString("[@name]").equals("hibernate.hikari.dataSource.url")) {
url = hier.getString("[@value]");
}
if (hier.getString("[@name]").equals("hibernate.hikari.dataSource.password")) {
password = hier.getString("[@value]");
}
}
assert username != null && url != null && password != null;
System.out.println("Url: " + url);
System.out.println("Username: " + username);
System.out.println("Password: " + password);
System.out.println("Check if this is the correct targeted database.");
// Message
Thread.sleep(250);
System.err.println("\nGiving you 30 seconds to stop this operations if you targeted the wrong database.");
Thread.sleep(10000);
System.err.println("20 more seconds.");
Thread.sleep(10000);
System.err.println("10 more seconds.");
Thread.sleep(10000);
System.err.println("\n\n\n\n\n\n\n\n\n\n\n\n\n");
// Get connection
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection(url + "&allowMultiQueries=true&user=" + username + "&password=" + password);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment