UNPKG

pg-diff-cli

Version:

PostgreSQL schema and data comparing tool

274 lines (249 loc) 8.67 kB
#!/usr/bin/env node const CLI = require("./src/CLI").CLI; const ConfigHandler = require("./src/ConfigHandler").ConfigHandler; const PgDiffApi = require("pg-diff-api").PgDiff; const chalk = require("chalk"); const { Progress } = require("clui"); const stdout = require("readline"); const pjson = require("./package.json"); const log = console.log; const actions = require("./src/enums/actions"); const options = require("./src/enums/options"); //pgTypes.setTypeParser(1114, value => new Date(Date.parse(`${value}+0000`))); CLI.PrintIntro(pjson); Run() .then(() => { process.exitCode = 0; process.exit(); }) .catch((err) => { HandleError(err); process.exitCode = -1; process.exit(); }); /** * * @param {Error} e */ function HandleError(e, nostack = false) { log(); if (!nostack) log(chalk.red(e.stack)); if (!nostack) process.stderr.write(e.message); else log(chalk.red(e.message)); process.stderr.write("\n"); switch (e.code) { case "MODULE_NOT_FOUND": log( chalk.red( 'Please create the configuration file "pg-diff-config.json" in the same folder where you run pg-diff or specify config file full path with option parameter "-f"!' ) ); break; } } /** * * @param {String} lastAction * @param {String} currentAction */ function CheckDoubleActionError(lastAction, currentAction) { if (lastAction) { HandleError(new Error(`Too many execution options specified! "${lastAction}" and "${currentAction}" cannot co-exists.`)); CLI.PrintHelp(); process.exit(); } } /** * Run the tool */ async function Run() { var args = process.argv.slice(2); if (args.length <= 0) { HandleError(new Error("Options not specified!"), true); } let action = null; let lastOption = null; let breakLoop = false; /** @type {Map<String,String[]>} */ let optionParams = new Map(); let parsingOptionParams = false; for (const arg of args) { if (arg.startsWith("-")) { parsingOptionParams = true; breakLoop = false; lastOption = null; switch (arg) { case "-h": case "--help": CheckDoubleActionError(action, arg); action = actions.HELP; breakLoop = true; parsingOptionParams = false; break; case "-c": case "--compare": CheckDoubleActionError(action, arg); action = actions.COMPARE; lastOption = actions.COMPARE; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-ms": case "--migrate-to-source": CheckDoubleActionError(action, arg); action = actions.MIGRATE_TO_SOURCE; lastOption = actions.MIGRATE_TO_SOURCE; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-mt": case "--migrate-to-target": CheckDoubleActionError(action, arg); action = actions.MIGRATE_TO_TARGET; lastOption = actions.MIGRATE_TO_TARGET; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-s": case "--save": CheckDoubleActionError(action, arg); action = actions.SAVE; lastOption = actions.SAVE; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-p": case "--patch-folder": lastOption = options.PATCH_FOLDER; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-f": case "--config-file": lastOption = options.CONFIG_FILEPATH; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; case "-g": case "--generate-config": CheckDoubleActionError(action, arg); action = actions.GENERATE_CONFIG; lastOption = actions.GENERATE_CONFIG; if (!optionParams.has(lastOption)) optionParams.set(lastOption, []); break; default: HandleError(new Error(`Invalid parameter "${arg}"!`)); CLI.PrintHelp(); process.exit(); } } else if (parsingOptionParams) { optionParams.get(lastOption).push(arg); } if (breakLoop) break; } if (!action) { HandleError(new Error(`Missing execution options! Please specify one between -c, -ms, -mt, -s, -g execution option.`), true); CLI.PrintHelp(); process.exit(); } switch (action) { case actions.HELP: { CLI.PrintHelp(); process.exit(); break; } case actions.COMPARE: { if (!optionParams.has(actions.COMPARE) || optionParams.get(actions.COMPARE).length != 2) { HandleError(new Error("Missing or invalid arguments for option 'COMPARE'!")); CLI.PrintHelp(); process.exit(); } const params = optionParams.get(actions.COMPARE); let config = ConfigHandler.LoadConfig(params[0], ConfigHandler.GetConfigFilePath(optionParams)); ConfigHandler.ValidateCompareConfig(optionParams, config); CLI.PrintOptions(config); let progressBar = new Progress(20); let pgDiff = new PgDiffApi(config); pgDiff.events.on("compare", function (message, percentage) { stdout.clearLine(process.stdout); stdout.cursorTo(process.stdout, 0); process.stdout.write(progressBar.update(percentage / 100) + " - " + chalk.whiteBright(message)); }); let scriptFilePath = await pgDiff.compare(params[1]); log(); if (scriptFilePath) log(chalk.whiteBright("SQL patch file has been created succesfully at: ") + chalk.green(scriptFilePath)); else log(chalk.yellow("No patch has been created because no differences have been found!")); } break; case actions.MIGRATE_TO_SOURCE: case actions.MIGRATE_TO_TARGET: { let configName = null; let toSourceClient = false; if (action == actions.MIGRATE_TO_SOURCE) { if (!optionParams.has(actions.MIGRATE_TO_SOURCE) || optionParams.get(actions.MIGRATE_TO_SOURCE).length != 1) { HandleError(new Error("Missing or invalid arguments for option 'MIGRATE TO SOURCE'!")); CLI.PrintHelp(); process.exit(); } else { configName = optionParams.get(actions.MIGRATE_TO_SOURCE)[0]; toSourceClient = true; } } if (action == actions.MIGRATE_TO_TARGET) { if (!optionParams.has(actions.MIGRATE_TO_TARGET) || optionParams.get(actions.MIGRATE_TO_TARGET).length != 1) { HandleError(new Error("Missing or invalid arguments for option 'MIGRATE TO TARGET'!")); CLI.PrintHelp(); process.exit(); } else configName = optionParams.get(actions.MIGRATE_TO_TARGET)[0]; } let config = ConfigHandler.LoadConfig(configName, ConfigHandler.GetConfigFilePath(optionParams)); ConfigHandler.ValidateMigrationConfig(optionParams, config); CLI.PrintOptions(config); let progressBar = new Progress(20); let pgDiff = new PgDiffApi(config); pgDiff.events.on("migrate", function (message, percentage) { stdout.clearLine(process.stdout); stdout.cursorTo(process.stdout, 0); process.stdout.write(progressBar.update(percentage / 100) + " - " + chalk.whiteBright(message)); }); let patches = await pgDiff.migrate(true, toSourceClient); log(); if (patches.length <= 0) log(chalk.yellow("No new db patches have been found.")); else { log(chalk.green("Following db patches have been applied:")); for (let patch of patches) { log(chalk.green(`- Patch "${patch.name}" version "${patch.version}"`)); } } } break; case actions.SAVE: { if (!optionParams.has(actions.SAVE) || optionParams.get(actions.SAVE).length != 2) { HandleError(new Error("Missing or invalid arguments for option 'SAVE'!")); CLI.PrintHelp(); process.exit(); } const params = optionParams.get(actions.SAVE); let config = ConfigHandler.LoadConfig(params[0], ConfigHandler.GetConfigFilePath(optionParams)); CLI.PrintOptions(config); let pgDiff = new PgDiffApi(config); await pgDiff.save(params[1]); log(); log(chalk.green(`Patch ${params[1]} has been saved!`)); } break; case actions.GENERATE_CONFIG: { if (!optionParams.has(actions.GENERATE_CONFIG) || optionParams.get(actions.GENERATE_CONFIG).length > 1) { HandleError(new Error("Invalid arguments for option 'GENERATE CONFIG'!")); CLI.PrintHelp(); process.exit(); } const params = optionParams.get(actions.GENERATE_CONFIG); await CLI.GenerateConfig(params[0]); } break; default: { HandleError(new Error(`Not implemented yet execution option "${action}"!`)); CLI.PrintHelp(); process.exit(); } } }