Last active
August 29, 2015 14:24
-
-
Save fuxingloh/25b1287673f62b2f9e03 to your computer and use it in GitHub Desktop.
AutoMigration From PuffinCore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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