All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dslplatform.compiler.client.parameters.Migration Maven / Gradle / Ivy

package com.dslplatform.compiler.client.parameters;

import com.dslplatform.compiler.client.*;

import java.io.File;
import java.io.IOException;
import java.util.*;

public enum Migration implements CompileParameter {
	INSTANCE;

	@Override
	public String getAlias() {
		return "migration";
	}

	@Override
	public String getUsage() {
		return null;
	}

	private final static String DESCRIPTION_START = "/*MIGRATION_DESCRIPTION";
	private final static String DESCRIPTION_END = "MIGRATION_DESCRIPTION*/";

	private static final String POSTGRES_MIGRATION_FILE_NAME = "postgres_migration_file";
	private static final String ORACLE_MIGRATION_FILE_NAME = "oracle_migration_file";

	public static File getPostgresMigrationFile(final Context context) {
		return context.load(POSTGRES_MIGRATION_FILE_NAME);
	}

	public static File getOracleMigrationFile(final Context context) {
		return context.load(ORACLE_MIGRATION_FILE_NAME);
	}

	public static String[] extractDescriptions(final String sql) throws ExitException {
		final int start = sql.indexOf(DESCRIPTION_START);
		final int end = sql.indexOf(DESCRIPTION_END);
		if (end > start) {
			return sql.substring(start + DESCRIPTION_START.length(), end).split("\n");
		}
		return new String[0];
	}

	@Override
	public boolean check(final Context context) {
		if (context.contains(INSTANCE)) {
			if (!context.contains(PostgresConnection.INSTANCE)
					&& !context.contains(OracleConnection.INSTANCE)) {
				context.error("Connection string is required to create a migration script.\n"
						+ "Neither Oracle or Postgres connection string found");
				return false;
			}
			if (context.contains(SqlPath.INSTANCE)) {
				final String value = context.get(SqlPath.INSTANCE);
				if (value == null || value.length() == 0) {
					return true;
				}
				final File sqlPath = new File(value);
				if (!sqlPath.exists()) {
					context.error("Path for SQL migration script provided (" + value + ") but not found");
					return false;
				}
				if (sqlPath.isFile()) {
					context.error("Provided path for SQL migration is a file and not a folder (" + value + ").\n"
							+ "Please specify folder which will be used for migration.");
					return false;
				}
			}
		}
		return true;
	}

	@Override
	public void run(final Context context) throws ExitException {
		if (context.contains(Migration.INSTANCE)) {
			final String value = context.get(SqlPath.INSTANCE);
			final File path;
			if (!context.contains(SqlPath.INSTANCE) || value == null || value.length() == 0) {
				path = TempPath.getTempProjectPath(context);
			} else {
				path = new File(value);
			}
			if (!path.exists()) {
				context.error("Error accessing SQL path (" + path.getAbsolutePath() + ").");
				throw new ExitException();
			}
			if (context.contains(PostgresConnection.INSTANCE)) {
				final DatabaseInfo dbInfo = PostgresConnection.getDatabaseDslAndVersion(context);
				createMigration(context, path, dbInfo, POSTGRES_MIGRATION_FILE_NAME);
			}
			if (context.contains(OracleConnection.INSTANCE)) {
				final DatabaseInfo dbInfo = OracleConnection.getDatabaseDslAndVersion(context);
				createMigration(context, path, dbInfo, ORACLE_MIGRATION_FILE_NAME);
			}
		}
	}

	private static void createMigration(
			final Context context,
			final File path,
			final DatabaseInfo dbInfo,
			final String file) throws ExitException {
		final List currentDsl = DslPath.getDslPaths(context);
		context.show("Creating SQL migration for " + dbInfo.database + " ...");
		final Either migration = DslCompiler.migration(context, dbInfo, currentDsl);
		if (!migration.isSuccess()) {
			context.error("Error creating SQL migration:");
			context.error(migration.whyNot());
			throw new ExitException();
		}
		final String script = migration.get();
		final String sqlFileName = dbInfo.database.toLowerCase() + "-sql-migration-" + (new Date().getTime());
		if (script.length() > 0) {
			final File sqlFile = new File(path.getAbsolutePath(), sqlFileName + ".sql");
			try {
				Utils.saveFile(context, sqlFile, script);
			} catch (IOException e) {
				context.error("Error saving migration script to " + sqlFile.getAbsolutePath());
				context.error(e);
				throw new ExitException();
			}
			context.show("Migration saved to " + sqlFile.getAbsolutePath());
			final String[] descriptions = extractDescriptions(script);
			for (int i = 1; i < descriptions.length; i++) {
				context.log(descriptions[i]);
			}
			context.cache(file, sqlFile);
		} else {
			context.show("No database changes detected.");
			context.cache(file, new File("empty.sql"));
		}
	}

	@Override
	public String getShortDescription() {
		return "Create SQL migration from previous DSL to the current one";
	}

	@Override
	public String getDetailedDescription() {
		return "DSL Platform will compare previously applied DSL with the current one and provide a migration SQL script.\n" +
				"Developer can inspect migration (although it contains a lot of boilerplate due to dependency graph rebuild),\n" +
				"to check if the requested migration matches what he had in mind.\n" +
				"Every migration contains description of the important changes to the database.\n" +
				"\n" +
				"Postgres migrations are transactional due to Transactional DDL Postgres feature.\n" +
				"\n" +
				"While for most migrations ownership of the database is sufficient, some require superuser access (Enum changes, strange primary keys, ...).";
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy