package jef.mysql.migration; import jef.model.migration.operation.AddFieldOperation; import jef.model.migration.operation.AddForeignKeyOperation; import jef.model.migration.operation.AddIndexOperation; import jef.model.migration.operation.AddKeyOperation; import jef.model.migration.operation.AddPrimaryKeyOperation; import jef.model.migration.operation.AddTableOperation; import jef.model.migration.operation.AddUniqueKeyOperation; import jef.model.migration.operation.DropConstraintOperation; import jef.model.migration.operation.DropFieldOperation; import jef.model.migration.operation.DropTableOperation; import jef.model.migration.operation.MigrationOperation; import jef.model.migration.operation.RenameFieldOperation; import jef.model.migration.operation.RenameTableOperation; import jef.model.migration.operation.UpdateFieldOperation; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; public class MysqlMigrationOperationTranslator { private static final Map, Mapper> translators; static { var map = new HashMap, Mapper>(); map.put(AddFieldOperation.class, MysqlMigrationOperationTranslator::translateAddFieldOperation); map.put(AddForeignKeyOperation.class, MysqlMigrationOperationTranslator::translateAddForeignKeyOperation); map.put(AddIndexOperation.class, MysqlMigrationOperationTranslator::translateAddIndexOperation); map.put(AddKeyOperation.class, MysqlMigrationOperationTranslator::translateAddKeyOperation); map.put(AddPrimaryKeyOperation.class, MysqlMigrationOperationTranslator::translateAddPrimaryKeyOperation); map.put(AddTableOperation.class, MysqlMigrationOperationTranslator::translateAddTableOperation); map.put(AddUniqueKeyOperation.class, MysqlMigrationOperationTranslator::translateAddUniqueKeyOperation); map.put(DropConstraintOperation.class, MysqlMigrationOperationTranslator::translateDropConstraintOperation); map.put(DropFieldOperation.class, MysqlMigrationOperationTranslator::translateDropFieldOperation); map.put(DropTableOperation.class, MysqlMigrationOperationTranslator::translateDropTableOperation); map.put(RenameFieldOperation.class, MysqlMigrationOperationTranslator::translateRenameFieldOperation); map.put(RenameTableOperation.class, MysqlMigrationOperationTranslator::translateRenameTableOperation); map.put(UpdateFieldOperation.class, MysqlMigrationOperationTranslator::translateUpdateFieldOperation); translators = Collections.unmodifiableMap(map); } public static PreparedStatement translate(Connection connection, MigrationOperation operation) throws SQLException { return Optional.ofNullable(translators.get(operation.getClass())).orElseThrow().apply(connection, operation); } private static PreparedStatement translateAddFieldOperation(Connection connection, MigrationOperation operation) throws SQLException { AddFieldOperation op = (AddFieldOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD COLUMN `" + op.getField() + "` " + op.getSqlType() + (op.isNotNull() ? " NOT NULL" : "") //TODO add after field specification + " LAST"); } private static PreparedStatement translateAddForeignKeyOperation(Connection connection, MigrationOperation operation) throws SQLException { AddForeignKeyOperation op = (AddForeignKeyOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD CONSTRAINT `" + op.getName() + "`" + " FOREIGN KEY (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")" + " REFERENCES `" + op.getReferencedTable() + "`(" + op.getReferencedFields().stream() .map(e -> "`" + e + "`") .collect(Collectors.joining(", ")) + ")"); } private static PreparedStatement translateAddIndexOperation(Connection connection, MigrationOperation operation) throws SQLException { AddIndexOperation op = (AddIndexOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD CONSTRAINT `" + op.getName() + "`" + " INDEX (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")"); } private static PreparedStatement translateAddKeyOperation(Connection connection, MigrationOperation operation) throws SQLException { AddKeyOperation op = (AddKeyOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD CONSTRAINT `" + op.getName() + "`" + " KEY (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")"); } private static PreparedStatement translateAddPrimaryKeyOperation(Connection connection, MigrationOperation operation) throws SQLException { AddPrimaryKeyOperation op = (AddPrimaryKeyOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD " + (!op.getName().equals("PRIMARY") ? "CONSTRAINT `" + op.getName() + "`" : "") + " PRIMARY KEY (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")"); // + " ADD CONSTRAINT `" + op.getName() + "`" // + " PRIMARY KEY (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")"); } private static PreparedStatement translateAddTableOperation(Connection connection, MigrationOperation operation) throws SQLException { AddTableOperation op = (AddTableOperation) operation; return connection.prepareStatement("CREATE TABLE `" + op.getTable() + "` (" + op.getFields().stream().map(e -> { var f = e.build(); return "`" + f.getField() + "` " + f.getSqlType() + (f.isNotNull() ? " NOT NULL" : ""); }).collect(Collectors.joining(", ")) + ")"); //TODO default collocation from database config or operation, field collation, primary key, constraints } private static PreparedStatement translateAddUniqueKeyOperation(Connection connection, MigrationOperation operation) throws SQLException { AddUniqueKeyOperation op = (AddUniqueKeyOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ADD CONSTRAINT `" + op.getName() + "`" + " UNIQUE (" + op.getFields().stream().map(e -> "`" + e + "`").collect(Collectors.joining(", ")) + ")"); } private static PreparedStatement translateDropConstraintOperation(Connection connection, MigrationOperation operation) throws SQLException { DropConstraintOperation op = (DropConstraintOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " DROP CONSTRAINT `" + op.getName() + "`"); } private static PreparedStatement translateDropFieldOperation(Connection connection, MigrationOperation operation) throws SQLException { DropFieldOperation op = (DropFieldOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " DROP COLUMN `" + op.getField() + "`"); } private static PreparedStatement translateDropTableOperation(Connection connection, MigrationOperation operation) throws SQLException { DropTableOperation op = (DropTableOperation) operation; return connection.prepareStatement("DROP TABLE `" + op.getTable() + "`"); } private static PreparedStatement translateRenameFieldOperation(Connection connection, MigrationOperation operation) throws SQLException { RenameFieldOperation op = (RenameFieldOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " RENAME COLUMN `" + op.getOldName() + "` `" + op.getNewName() + "`"); } private static PreparedStatement translateRenameTableOperation(Connection connection, MigrationOperation operation) throws SQLException { RenameTableOperation op = (RenameTableOperation) operation; return connection.prepareStatement("RENAME TABLE `" + op.getOldName() + "` `" + op.getNewName() + "`"); } private static PreparedStatement translateUpdateFieldOperation(Connection connection, MigrationOperation operation) throws SQLException { UpdateFieldOperation op = (UpdateFieldOperation) operation; return connection.prepareStatement("ALTER TABLE `" + op.getTable() + "`" + " ALTER COLUMN `" + op.getField() + "` `" + op.getNewName() + "`" + op.getSqlType() + (op.isNotNull() ? " NOT NULL" : "")); } @FunctionalInterface private interface Mapper { PreparedStatement apply(Connection connection, T operation) throws SQLException; } }