UNPKG

graphile-migrate

Version:

Opinionated SQL-powered migration tool for PostgreSQL

141 lines 4.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const pg_1 = require("pg"); const pg_connection_string_1 = require("pg-connection-string"); /** * For efficiency, we keep pools around for a period of time after they were * last "released" so we don't have to keep re-creating them. This value * chooses this time (in milliseconds). Note: clean exit will be delayed by * this duration. */ const POOL_KEEPALIVE = 200; const poolDetailsByConnectionString = new Map(); function clearAllPools() { for (const details of poolDetailsByConnectionString.values()) { if (details.referenceCount === 0) { details._reallyRelease(); } } } exports.clearAllPools = clearAllPools; function getPoolDetailsFromConnectionString({ logger }, connectionString) { let details = poolDetailsByConnectionString.get(connectionString); if (!details) { const { database } = pg_connection_string_1.parse(connectionString); if (!database) { throw new Error("Connection string does not specify a database"); } const pool = new pg_1.Pool({ connectionString }); pool.on("error", (error) => { logger.error(`An error occurred in the PgPool: ${error.message}`, { error, }); process.exit(1); }); // We don't want someone else ending our pool; delete the end method. const end = pool.end; pool.end = () => { throw new Error("You must not call .end() on this pool! Release the pool detail instead"); }; details = { pool, database, referenceCount: 0, release() { this.referenceCount--; if (this.referenceCount === 0) { this._timer = setTimeout(this._reallyRelease, POOL_KEEPALIVE); } }, _timer: null, _reference() { clearTimeout(this._timer); this._timer = null; this.referenceCount++; }, _reallyRelease() { clearTimeout(this._timer); this._timer = null; pool.end = end; pool.end(); poolDetailsByConnectionString.delete(connectionString); }, }; poolDetailsByConnectionString.set(connectionString, details); } details._reference(); return details; } async function withClient(connectionString, parsedSettings, callback) { const details = getPoolDetailsFromConnectionString(parsedSettings, connectionString); const { pool: pgPool, database } = details; try { const pgClient = await pgPool.connect(); try { if (parsedSettings.pgSettings) { const sqlFragments = []; const sqlValues = []; for (const [key, value] of Object.entries(parsedSettings.pgSettings)) { sqlValues.push(key, value); sqlFragments.push(`pg_catalog.set_config($${sqlValues.length - 1}::text, $${sqlValues.length}::text, false)`); } if (sqlFragments.length) { await pgClient.query({ text: `select ${sqlFragments.join(", ")}`, values: sqlValues, }); } } const context = { database, }; return await callback(pgClient, context); } finally { await Promise.resolve(pgClient.release()); } } finally { details.release(); } } exports.withClient = withClient; const ADVISORY_LOCK_MIGRATE = "4727445306447283"; /* `GRAPHILE MIGRATE` on phone keypad */ async function withAdvisoryLock(pgClient, callback) { if (pgClient["__isMockClient"]) { return callback(pgClient); } const { rows: [{ locked }], } = await pgClient.query("select pg_try_advisory_lock($1) as locked", [ ADVISORY_LOCK_MIGRATE, ]); if (!locked) { throw new Error("Failed to get exclusive lock"); } try { return await callback(pgClient); } finally { await pgClient.query("select pg_advisory_unlock($1)", [ ADVISORY_LOCK_MIGRATE, ]); } } exports.withAdvisoryLock = withAdvisoryLock; async function withTransaction(pgClient, callback) { await pgClient.query("begin"); try { const result = await callback(); await pgClient.query("commit"); return result; } catch (e) { await pgClient.query("rollback"); throw e; } } exports.withTransaction = withTransaction; function escapeIdentifier(str) { return '"' + str.replace(/"/g, '""') + '"'; } exports.escapeIdentifier = escapeIdentifier; //# sourceMappingURL=pgReal.js.map