graphile-migrate
Version:
Opinionated SQL-powered migration tool for PostgreSQL
136 lines • 6.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const pg_connection_string_1 = require("pg-connection-string");
const util_1 = require("util");
const lib_1 = require("./lib");
const migration_1 = require("./migration");
const pg_1 = require("./pg");
const settings_1 = require("./settings");
exports.DO_NOT_USE_DATABASE_URL = "postgres://PLEASE:USE@GM_DBURL/INSTEAD";
const exec = util_1.promisify(child_process_1.exec);
async function executeActions(parsedSettings, shadow = false, actions) {
if (!actions) {
return;
}
const connectionString = shadow
? parsedSettings.shadowConnectionString
: parsedSettings.connectionString;
if (!connectionString) {
throw new Error("Could not determine connection string for running commands");
}
const { database: databaseName, user: databaseUser } = pg_connection_string_1.parse(connectionString);
if (!databaseName) {
throw new Error("Could not extract database name from connection string");
}
for (const actionSpec of actions) {
if (actionSpec.shadow !== undefined && actionSpec.shadow !== shadow) {
continue;
}
const hookConnectionString = actionSpec.root
? settings_1.makeRootDatabaseConnectionString(parsedSettings, databaseName)
: connectionString;
if (actionSpec._ === "sql") {
const body = await fs_1.promises.readFile(`${parsedSettings.migrationsFolder}/${actionSpec.file}`, "utf8");
await pg_1.withClient(hookConnectionString, parsedSettings, async (pgClient, context) => {
const query = migration_1.generatePlaceholderReplacement(parsedSettings, context)(body);
await pgClient.query({
text: query,
});
});
}
else if (actionSpec._ === "command") {
// Run the command
const promise = exec(actionSpec.command, {
env: lib_1.mergeWithoutClobbering(Object.assign(Object.assign({}, process.env), { DATABASE_URL: exports.DO_NOT_USE_DATABASE_URL }), Object.assign(Object.assign(Object.assign({ GM_DBNAME: databaseName }, (actionSpec.root
? null
: {
GM_DBUSER: databaseUser,
})), { GM_DBURL: hookConnectionString }), (shadow
? {
GM_SHADOW: "1",
}
: null)), "please ensure this environmental variable is not set because graphile-migrate sets it dynamically for children."),
encoding: "utf8",
// 50MB of log data should be enough for any reasonable migration... right?
maxBuffer: 50 * 1024 * 1024,
});
try {
const { stdout, stderr } = await promise;
if (stdout) {
parsedSettings.logger.info(stdout);
}
if (stderr) {
parsedSettings.logger.error(stderr);
}
}
catch (e) {
const { stdout, stderr } = e;
if (stdout) {
parsedSettings.logger.info(stdout);
}
if (stderr) {
parsedSettings.logger.error(stderr);
}
throw e;
}
}
}
}
exports.executeActions = executeActions;
function makeValidateActionCallback(logger, allowRoot = false) {
return async (inputValue) => {
const specs = [];
if (inputValue) {
const rawSpecArray = Array.isArray(inputValue)
? inputValue
: [inputValue];
for (const trueRawSpec of rawSpecArray) {
// This fudge is for backwards compatibility with v0.0.3
const isV003OrBelowCommand = typeof trueRawSpec === "object" &&
trueRawSpec &&
!trueRawSpec["_"] &&
typeof trueRawSpec["command"] === "string";
if (isV003OrBelowCommand) {
logger.warn("DEPRECATED: graphile-migrate now requires command action specs to have an `_: 'command'` property; we'll back-fill this for now, but please update your configuration");
}
const rawSpec = isV003OrBelowCommand
? Object.assign({ _: "command" }, trueRawSpec) : trueRawSpec;
if (rawSpec && typeof rawSpec === "string") {
const sqlSpec = rawSpec.startsWith("!")
? {
_: "sql",
file: rawSpec.substring(1),
root: true,
}
: {
_: "sql",
file: rawSpec,
};
specs.push(sqlSpec);
}
else if (settings_1.isActionSpec(rawSpec)) {
if (settings_1.isSqlActionSpec(rawSpec) || settings_1.isCommandActionSpec(rawSpec)) {
specs.push(rawSpec);
}
else {
throw new Error(`Action spec of type '${rawSpec["_"]}' not supported; perhaps you need to upgrade?`);
}
}
else {
throw new Error(`Expected action spec to contain an array of strings or action specs; received '${typeof rawSpec}'`);
}
}
}
// Final validations
for (const spec of specs) {
if (!allowRoot && spec._ === "sql" && spec.root) {
throw new Error("This hooks isn't permitted to require root privileges.");
}
}
return specs;
};
}
exports.makeValidateActionCallback = makeValidateActionCallback;
//# sourceMappingURL=actions.js.map