UNPKG

@launchql/core

Version:

LaunchQL Package and Migration Tools

188 lines (179 loc) 6.47 kB
"use strict"; 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 }; };