@launchql/core
Version:
LaunchQL Package and Migration Tools
188 lines (179 loc) • 6.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.exportMigrations = void 0;
const case_1 = __importDefault(require("case"));
const fs_1 = require("fs");
const glob_1 = require("glob");
const path_1 = __importDefault(require("path"));
const pg_cache_1 = require("pg-cache");
const files_1 = require("../files");
const export_meta_1 = require("./export-meta");
const exportMigrationsToDisk = async ({ project, options, database, databaseId, author, outdir, schema_names, extensionName, metaExtensionName }) => {
outdir = outdir + '/';
const pgPool = (0, pg_cache_1.getPgPool)({
...options.pg,
database
});
const db = await pgPool.query(`select * from collections_public.database where id=$1`, [databaseId]);
const schemas = await pgPool.query(`select * from collections_public.schema where database_id=$1`, [databaseId]);
if (!db?.rows?.length) {
console.log('NO DATABASES.');
return;
}
if (!schemas?.rows?.length) {
console.log('NO SCHEMAS.');
return;
}
const name = extensionName || db.rows[0].name;
const { replace, replacer } = makeReplacer({
schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
name
});
const results = await pgPool.query(`select * from db_migrate.sql_actions order by id`);
const opts = {
name,
replacer,
outdir,
author
};
if (results?.rows?.length > 0) {
await preparePackage({
project,
author,
outdir,
name,
extensions: [
'plpgsql',
'uuid-ossp',
'citext',
'pgcrypto',
'btree_gist',
'postgis',
'hstore',
'db_meta',
'launchql-inflection',
'launchql-uuid',
'launchql-utils',
'launchql-ext-jobs',
'launchql-jwt-claims',
'launchql-stamps',
'launchql-base32',
'launchql-totp',
'launchql-ext-types',
'launchql-ext-default-roles'
]
});
(0, files_1.writeSqitchPlan)(results.rows, opts);
(0, files_1.writeSqitchFiles)(results.rows, opts);
let meta = await (0, export_meta_1.exportMeta)({
opts: options,
dbname: database,
database_id: databaseId
});
meta = replacer(meta);
await preparePackage({
project,
author,
outdir,
extensions: ['plpgsql', 'db_meta', 'db_meta_modules'],
name: metaExtensionName
});
const metaReplacer = makeReplacer({
schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
name: metaExtensionName
});
const metaPackage = [
{
deps: [],
deploy: 'migrate/meta',
content: `SET session_replication_role TO replica;
-- using replica in case we are deploying triggers to collections_public
-- unaccent, postgis affected and require grants
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public to public;
DO $LQLMIGRATION$
DECLARE
BEGIN
EXECUTE format('GRANT CONNECT ON DATABASE %I TO %I', current_database(), 'app_user');
EXECUTE format('GRANT CONNECT ON DATABASE %I TO %I', current_database(), 'app_admin');
END;
$LQLMIGRATION$;
${meta}
UPDATE meta_public.apis
SET dbname = current_database() WHERE TRUE;
UPDATE meta_public.sites
SET dbname = current_database() WHERE TRUE;
SET session_replication_role TO DEFAULT;
`
}
];
opts.replacer = metaReplacer.replacer;
opts.name = metaExtensionName;
(0, files_1.writeSqitchPlan)(metaPackage, opts);
(0, files_1.writeSqitchFiles)(metaPackage, opts);
}
pgPool.end();
};
const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, metaExtensionName }) => {
for (let v = 0; v < dbInfo.database_ids.length; v++) {
const databaseId = dbInfo.database_ids[v];
await exportMigrationsToDisk({
project,
options,
extensionName,
metaExtensionName,
database: dbInfo.dbname,
databaseId,
schema_names,
author,
outdir
});
}
};
exports.exportMigrations = exportMigrations;
/**
* Creates a Sqitch package directory or resets the deploy/revert/verify directories if it exists.
*/
const preparePackage = async ({ project, author, outdir, name, extensions }) => {
const curDir = process.cwd();
const sqitchDir = path_1.default.resolve(path_1.default.join(outdir, name));
(0, fs_1.mkdirSync)(sqitchDir, { recursive: true });
process.chdir(sqitchDir);
const plan = (0, glob_1.sync)(path_1.default.join(sqitchDir, 'launchql.plan'));
if (!plan.length) {
project.initModule({
name,
description: name,
author,
extensions,
});
}
else {
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'deploy'), { recursive: true, force: true });
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'revert'), { recursive: true, force: true });
(0, fs_1.rmSync)(path_1.default.resolve(sqitchDir, 'verify'), { recursive: true, force: true });
}
process.chdir(curDir);
};
/**
* Generates a function for replacing schema names and extension names in strings.
*/
const makeReplacer = ({ schemas, name }) => {
const replacements = ['launchql-extension-name', name];
const schemaReplacers = schemas.map((schema) => [
schema.schema_name,
case_1.default.snake(`${name}_${schema.name}`)
]);
const replace = [...schemaReplacers, replacements].map(([from, to]) => [new RegExp(from, 'g'), to]);
const replacer = (str, n = 0) => {
if (!str)
return '';
if (replace[n] && replace[n].length === 2) {
return replacer(str.replace(replace[n][0], replace[n][1]), n + 1);
}
return str;
};
return { replacer, replace };
};