pgpm 5.19.1 → 5.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/commands/cache.js +1 -1
  2. package/commands/diff.d.ts +3 -0
  3. package/commands/diff.js +325 -0
  4. package/commands/dump.js +3 -3
  5. package/commands/export.js +24 -5
  6. package/commands/import.d.ts +3 -0
  7. package/commands/import.js +198 -0
  8. package/commands/init/boilerplate.js +1 -1
  9. package/commands/init/index.js +3 -3
  10. package/commands/package.js +0 -1
  11. package/commands/slice.js +1 -1
  12. package/commands/test-packages.js +1 -1
  13. package/commands/transform.d.ts +13 -0
  14. package/commands/transform.js +275 -0
  15. package/commands/update.js +1 -1
  16. package/commands.js +7 -0
  17. package/esm/commands/cache.js +1 -1
  18. package/esm/commands/diff.js +290 -0
  19. package/esm/commands/dump.js +3 -3
  20. package/esm/commands/export.js +22 -3
  21. package/esm/commands/import.js +163 -0
  22. package/esm/commands/init/boilerplate.js +1 -1
  23. package/esm/commands/init/index.js +3 -3
  24. package/esm/commands/package.js +0 -1
  25. package/esm/commands/slice.js +1 -1
  26. package/esm/commands/test-packages.js +1 -1
  27. package/esm/commands/transform.js +236 -0
  28. package/esm/commands/update.js +1 -1
  29. package/esm/commands.js +7 -0
  30. package/esm/utils/display.js +3 -0
  31. package/esm/utils/driver.js +1 -1
  32. package/esm/utils/emit-package.js +1 -0
  33. package/esm/utils/engine.js +1 -1
  34. package/esm/utils/module-projections.js +47 -0
  35. package/esm/utils/scratch-db.js +61 -0
  36. package/package.json +14 -12
  37. package/utils/display.d.ts +1 -1
  38. package/utils/display.js +3 -0
  39. package/utils/driver.js +1 -1
  40. package/utils/emit-package.d.ts +9 -0
  41. package/utils/emit-package.js +7 -0
  42. package/utils/engine.js +1 -1
  43. package/utils/module-projections.d.ts +15 -0
  44. package/utils/module-projections.js +85 -0
  45. package/utils/scratch-db.d.ts +31 -0
  46. package/utils/scratch-db.js +66 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Projections of an emitted pgpm module directory.
3
+ *
4
+ * A module directory is the canonical artifact the dials pipeline produces
5
+ * (`writeModule` from `@pgpmjs/transform`). "Linear SQL" and "bundle" are not
6
+ * separate emitters — they are pure projections of that one module, produced
7
+ * by the same battle-tested machinery `pgpm package` uses:
8
+ *
9
+ * - {@link emitModuleSql} -> consolidated single-file SQL (`packageModule`)
10
+ * - {@link emitModuleBundle} -> content-addressed bundle (`buildExecutableBundle`)
11
+ *
12
+ * They live in the CLI (not `@pgpmjs/transform`) because they reuse packaging
13
+ * and bundle code from `@pgpmjs/core`, and `core` already depends on
14
+ * `transform`.
15
+ */
16
+ import { buildExecutableBundle, packageModule, writeBundleArchiveFile } from '@pgpmjs/core';
17
+ import * as fs from 'fs';
18
+ import * as path from 'path';
19
+ /** Sentinel meaning "write to stdout" for a file-valued emit target. */
20
+ export const STDOUT_TARGET = '-';
21
+ /**
22
+ * Consolidate an emitted module directory into a single linear SQL script.
23
+ * Statements are resolved in plan order and deparsed once (comments and
24
+ * per-change file boundaries collapse away). When `target` is `-` the SQL is
25
+ * written to stdout; otherwise it is written to the given file path.
26
+ */
27
+ export const emitModuleSql = async (moduleDir, target) => {
28
+ const { sql } = await packageModule(moduleDir, { extension: false, usePlan: true, pretty: true });
29
+ if (target === STDOUT_TARGET) {
30
+ process.stdout.write(sql.endsWith('\n') ? sql : sql + '\n');
31
+ return;
32
+ }
33
+ const resolved = path.resolve(target);
34
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
35
+ fs.writeFileSync(resolved, sql.endsWith('\n') ? sql : sql + '\n');
36
+ };
37
+ /**
38
+ * Project an emitted module directory into a content-addressed bundle archive
39
+ * (`.bundle.tar.gz`) at `target` — the same executable bundle `pgpm package`
40
+ * stores beside the packaged SQL, but written to an arbitrary path.
41
+ */
42
+ export const emitModuleBundle = async (moduleDir, target) => {
43
+ const bundle = await buildExecutableBundle(moduleDir, { createdWith: '@pgpmjs/cli' });
44
+ const resolved = path.resolve(target);
45
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
46
+ writeBundleArchiveFile(bundle, resolved);
47
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Scratch-database catalog oracle shared by the dials commands that prove
3
+ * structural equivalence (`pgpm transform --check`, `pgpm diff --verify`).
4
+ *
5
+ * Both commands do the same dance: create throwaway databases, deploy a
6
+ * schema into each, snapshot the catalogs, and diff them — always dropping the
7
+ * scratch databases afterwards even on failure. This centralizes the lifecycle
8
+ * (`withScratchDatabases`) and the snapshot/compare step (`catalogDifferences`)
9
+ * so each command only supplies what is genuinely command-specific: how it
10
+ * deploys a side.
11
+ *
12
+ * It lives in the CLI (not `@pgpmjs/transform`) because deploying touches
13
+ * `PgpmMigrate` from `@pgpmjs/core`, and `core` already depends on `transform`
14
+ * — hosting the oracle in `transform` would close that cycle.
15
+ */
16
+ import { diffCatalogSnapshots, snapshotCatalog } from '@pgpmjs/transform';
17
+ import { Logger } from '@pgpmjs/logger';
18
+ import { getPgPool } from 'pg-cache';
19
+ const log = new Logger('scratch-db');
20
+ const createScratchDb = async (config, dbName) => {
21
+ const adminPool = getPgPool({ ...config, database: 'postgres' });
22
+ await adminPool.query(`DROP DATABASE IF EXISTS "${dbName}"`);
23
+ await adminPool.query(`CREATE DATABASE "${dbName}"`);
24
+ };
25
+ const dropScratchDb = async (config, dbName) => {
26
+ const adminPool = getPgPool({ ...config, database: 'postgres' });
27
+ await adminPool.query(`DROP DATABASE IF EXISTS "${dbName}" WITH (FORCE)`);
28
+ };
29
+ /**
30
+ * Create the named scratch databases, run `fn` with a per-database `PgConfig`
31
+ * for each (in the same order as `names`), and drop them all afterwards —
32
+ * even if `fn` throws. Drop failures are logged, never thrown, so they can't
33
+ * mask the original error.
34
+ */
35
+ export const withScratchDatabases = async (config, names, fn) => {
36
+ try {
37
+ for (const name of names)
38
+ await createScratchDb(config, name);
39
+ return await fn(names.map(name => ({ ...config, database: name })));
40
+ }
41
+ finally {
42
+ try {
43
+ for (const name of names)
44
+ await dropScratchDb(config, name);
45
+ }
46
+ catch (err) {
47
+ log.warn(`failed to drop scratch databases: ${err instanceof Error ? err.message : err}`);
48
+ }
49
+ }
50
+ };
51
+ /**
52
+ * Snapshot the catalogs of two databases and return their differences. An
53
+ * optional `normalize` transform is applied to both snapshots first (e.g.
54
+ * `withoutColumnOrder` when a drop+add migration cannot reproduce a fresh
55
+ * deploy's physical column ordinals). Empty result means equivalent.
56
+ */
57
+ export const catalogDifferences = async (configA, configB, normalize = snap => snap) => {
58
+ const snapA = await snapshotCatalog(getPgPool(configA));
59
+ const snapB = await snapshotCatalog(getPgPool(configB));
60
+ return diffCatalogSnapshots(normalize(snapA), normalize(snapB));
61
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgpm",
3
- "version": "5.19.1",
3
+ "version": "5.20.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PostgreSQL Package Manager - Database migration and package management CLI",
6
6
  "main": "index.js",
@@ -46,22 +46,24 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@inquirerer/utils": "^3.3.9",
49
- "@pgpmjs/core": "^7.21.2",
50
- "@pgpmjs/env": "^2.40.2",
51
- "@pgpmjs/export": "^1.14.2",
52
- "@pgpmjs/logger": "^2.23.2",
53
- "@pgpmjs/slice": "^0.13.7",
54
- "@pgpmjs/transform": "^0.18.0",
55
- "@pgpmjs/types": "^2.49.2",
56
- "@pgsql/quotes": "^18.1.0",
49
+ "@pgpmjs/core": "^7.21.3",
50
+ "@pgpmjs/diff": "^0.1.1",
51
+ "@pgpmjs/env": "^2.40.3",
52
+ "@pgpmjs/export": "^1.15.0",
53
+ "@pgpmjs/import": "^0.1.1",
54
+ "@pgpmjs/logger": "^2.23.3",
55
+ "@pgpmjs/slice": "^0.13.8",
56
+ "@pgpmjs/transform": "^0.19.0",
57
+ "@pgpmjs/types": "^2.49.3",
58
+ "@pgsql/quotes": "^18.2.0",
57
59
  "appstash": "^0.7.0",
58
60
  "find-and-require-package-json": "^0.9.1",
59
61
  "genomic": "^5.6.2",
60
62
  "inquirerer": "^4.9.1",
61
63
  "js-yaml": "^4.1.0",
62
- "pg-cache": "^3.24.2",
64
+ "pg-cache": "^3.24.3",
63
65
  "pg-env": "^1.27.2",
64
- "pgsql-deparser": "^18.2.0",
66
+ "pgsql-deparser": "^18.3.1",
65
67
  "semver": "^7.8.1",
66
68
  "shelljs": "^0.10.0",
67
69
  "yanse": "^0.2.1"
@@ -78,5 +80,5 @@
78
80
  "pg",
79
81
  "pgsql"
80
82
  ],
81
- "gitHead": "6d3e25dc5c9f93421dba49ddedf93239f87213a8"
83
+ "gitHead": "c20b6be96b39bf71c0e2df0f4b51e05deacd006b"
82
84
  }
@@ -1 +1 @@
1
- export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n regen Generate revert/verify scripts from deploy scripts\n package Package module for distribution\n materialize Transpile an apply proxy into a plain, committed module\n sync-versions Sync .control/Makefile/sql metadata to package.json versions\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n tune Tune PostgreSQL for throwaway environments (CI/test)\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage Docker containers (start/stop/ls, --minio)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --minio)\n test-packages Run integration tests on workspace packages\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n --engine <name> Migration backend: pg (default, Postgres server) or\n pglite (in-process WASM Postgres, no server). Also set by\n the \"engine\" key of pgpm.json or PGPM_ENGINE.\n --driver <pkg> Driver plugin package backing the engine (escape hatch)\n --pglite[=dataDir] Sugar for --engine pglite, persisted to <dataDir> if given\n\n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n\n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
1
+ export declare const usageText = "\n Usage: pgpm <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n regen Generate revert/verify scripts from deploy scripts\n transform Re-dial a module through the dials pipeline (granularity/naming/partition)\n import pgpm-itize an arbitrary SQL dump into a deployable module\n diff Identity-keyed semantic diff between two schema sources (+ migration generation)\n package Package module for distribution\n materialize Transpile an apply proxy into a plain, committed module\n sync-versions Sync .control/Makefile/sql metadata to package.json versions\n export Export database migrations from existing databases\n update Update pgpm to the latest version\n cache Manage cached templates (clean)\n upgrade Upgrade installed pgpm modules to latest versions (alias: up)\n\n Database Administration:\n dump Dump a database to a sql file\n kill Terminate database connections and optionally drop databases\n install Install database modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n tune Tune PostgreSQL for throwaway environments (CI/test)\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n \n Development Tools:\n docker Manage Docker containers (start/stop/ls, --minio)\n doctor Check local dependencies (node, docker, psql) with install guidance\n env Manage environment variables (--supabase, --minio)\n test-packages Run integration tests on workspace packages\n \n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n --engine <name> Migration backend: pg (default, Postgres server) or\n pglite (in-process WASM Postgres, no server). Also set by\n the \"engine\" key of pgpm.json or PGPM_ENGINE.\n --driver <pkg> Driver plugin package backing the engine (escape hatch)\n --pglite[=dataDir] Sugar for --engine pglite, persisted to <dataDir> if given\n\n Individual Command Help:\n pgpm <command> --help Display detailed help for specific command\n pgpm <command> -h Display detailed help for specific command\n\n Examples:\n pgpm deploy --help Show deploy command options\n pgpm init workspace Initialize new workspace\n pgpm install @pgpm/base32 Install a database module\n ";
package/utils/display.js CHANGED
@@ -15,6 +15,9 @@ exports.usageText = `
15
15
  extension Manage module dependencies
16
16
  plan Generate module deployment plans
17
17
  regen Generate revert/verify scripts from deploy scripts
18
+ transform Re-dial a module through the dials pipeline (granularity/naming/partition)
19
+ import pgpm-itize an arbitrary SQL dump into a deployable module
20
+ diff Identity-keyed semantic diff between two schema sources (+ migration generation)
18
21
  package Package module for distribution
19
22
  materialize Transpile an apply proxy into a plain, committed module
20
23
  sync-versions Sync .control/Makefile/sql metadata to package.json versions
package/utils/driver.js CHANGED
@@ -4,9 +4,9 @@ exports.PGLITE_DRIVER_PLUGIN = void 0;
4
4
  exports.resolveDriverConfig = resolveDriverConfig;
5
5
  exports.driverOverrideFromArgv = driverOverrideFromArgv;
6
6
  exports.activateDriver = activateDriver;
7
- const types_1 = require("@pgpmjs/types");
8
7
  const node_module_1 = require("node:module");
9
8
  const node_path_1 = require("node:path");
9
+ const types_1 = require("@pgpmjs/types");
10
10
  /** Package name of the built-in PGlite driver plugin (the `--pglite` alias). */
11
11
  exports.PGLITE_DRIVER_PLUGIN = '@pgpmjs/pglite-adapter';
12
12
  /**
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared module emission for the dials commands (`pgpm transform`,
3
+ * `pgpm import`, `pgpm diff`). The implementation lives in `@pgpmjs/transform`
4
+ * (`module-emit`) so every command renders through one writer; this module is
5
+ * a thin re-export that keeps the CLI's local names (`writePackage`,
6
+ * `EmitPackage`) stable.
7
+ */
8
+ export type { PgpmModuleModel as EmitPackage } from '@pgpmjs/transform';
9
+ export { checkOverwrite, writeControlFile, writeModule as writePackage } from '@pgpmjs/transform';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writePackage = exports.writeControlFile = exports.checkOverwrite = void 0;
4
+ var transform_1 = require("@pgpmjs/transform");
5
+ Object.defineProperty(exports, "checkOverwrite", { enumerable: true, get: function () { return transform_1.checkOverwrite; } });
6
+ Object.defineProperty(exports, "writeControlFile", { enumerable: true, get: function () { return transform_1.writeControlFile; } });
7
+ Object.defineProperty(exports, "writePackage", { enumerable: true, get: function () { return transform_1.writeModule; } });
package/utils/engine.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deactivateEngine = exports.activateEngine = exports.getActiveEngine = exports.resolveEngine = exports.engineDefinitions = exports.SERVER_CAPABILITIES = void 0;
4
+ const node_path_1 = require("node:path");
4
5
  const env_1 = require("@pgpmjs/env");
5
6
  const types_1 = require("@pgpmjs/types");
6
- const node_path_1 = require("node:path");
7
7
  const driver_1 = require("./driver");
8
8
  /** Everything a real Postgres server can do — the built-in `pg` engine. */
9
9
  exports.SERVER_CAPABILITIES = {
@@ -0,0 +1,15 @@
1
+ /** Sentinel meaning "write to stdout" for a file-valued emit target. */
2
+ export declare const STDOUT_TARGET = "-";
3
+ /**
4
+ * Consolidate an emitted module directory into a single linear SQL script.
5
+ * Statements are resolved in plan order and deparsed once (comments and
6
+ * per-change file boundaries collapse away). When `target` is `-` the SQL is
7
+ * written to stdout; otherwise it is written to the given file path.
8
+ */
9
+ export declare const emitModuleSql: (moduleDir: string, target: string) => Promise<void>;
10
+ /**
11
+ * Project an emitted module directory into a content-addressed bundle archive
12
+ * (`.bundle.tar.gz`) at `target` — the same executable bundle `pgpm package`
13
+ * stores beside the packaged SQL, but written to an arbitrary path.
14
+ */
15
+ export declare const emitModuleBundle: (moduleDir: string, target: string) => Promise<void>;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.emitModuleBundle = exports.emitModuleSql = exports.STDOUT_TARGET = void 0;
37
+ /**
38
+ * Projections of an emitted pgpm module directory.
39
+ *
40
+ * A module directory is the canonical artifact the dials pipeline produces
41
+ * (`writeModule` from `@pgpmjs/transform`). "Linear SQL" and "bundle" are not
42
+ * separate emitters — they are pure projections of that one module, produced
43
+ * by the same battle-tested machinery `pgpm package` uses:
44
+ *
45
+ * - {@link emitModuleSql} -> consolidated single-file SQL (`packageModule`)
46
+ * - {@link emitModuleBundle} -> content-addressed bundle (`buildExecutableBundle`)
47
+ *
48
+ * They live in the CLI (not `@pgpmjs/transform`) because they reuse packaging
49
+ * and bundle code from `@pgpmjs/core`, and `core` already depends on
50
+ * `transform`.
51
+ */
52
+ const core_1 = require("@pgpmjs/core");
53
+ const fs = __importStar(require("fs"));
54
+ const path = __importStar(require("path"));
55
+ /** Sentinel meaning "write to stdout" for a file-valued emit target. */
56
+ exports.STDOUT_TARGET = '-';
57
+ /**
58
+ * Consolidate an emitted module directory into a single linear SQL script.
59
+ * Statements are resolved in plan order and deparsed once (comments and
60
+ * per-change file boundaries collapse away). When `target` is `-` the SQL is
61
+ * written to stdout; otherwise it is written to the given file path.
62
+ */
63
+ const emitModuleSql = async (moduleDir, target) => {
64
+ const { sql } = await (0, core_1.packageModule)(moduleDir, { extension: false, usePlan: true, pretty: true });
65
+ if (target === exports.STDOUT_TARGET) {
66
+ process.stdout.write(sql.endsWith('\n') ? sql : sql + '\n');
67
+ return;
68
+ }
69
+ const resolved = path.resolve(target);
70
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
71
+ fs.writeFileSync(resolved, sql.endsWith('\n') ? sql : sql + '\n');
72
+ };
73
+ exports.emitModuleSql = emitModuleSql;
74
+ /**
75
+ * Project an emitted module directory into a content-addressed bundle archive
76
+ * (`.bundle.tar.gz`) at `target` — the same executable bundle `pgpm package`
77
+ * stores beside the packaged SQL, but written to an arbitrary path.
78
+ */
79
+ const emitModuleBundle = async (moduleDir, target) => {
80
+ const bundle = await (0, core_1.buildExecutableBundle)(moduleDir, { createdWith: '@pgpmjs/cli' });
81
+ const resolved = path.resolve(target);
82
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
83
+ (0, core_1.writeBundleArchiveFile)(bundle, resolved);
84
+ };
85
+ exports.emitModuleBundle = emitModuleBundle;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Scratch-database catalog oracle shared by the dials commands that prove
3
+ * structural equivalence (`pgpm transform --check`, `pgpm diff --verify`).
4
+ *
5
+ * Both commands do the same dance: create throwaway databases, deploy a
6
+ * schema into each, snapshot the catalogs, and diff them — always dropping the
7
+ * scratch databases afterwards even on failure. This centralizes the lifecycle
8
+ * (`withScratchDatabases`) and the snapshot/compare step (`catalogDifferences`)
9
+ * so each command only supplies what is genuinely command-specific: how it
10
+ * deploys a side.
11
+ *
12
+ * It lives in the CLI (not `@pgpmjs/transform`) because deploying touches
13
+ * `PgpmMigrate` from `@pgpmjs/core`, and `core` already depends on `transform`
14
+ * — hosting the oracle in `transform` would close that cycle.
15
+ */
16
+ import { CatalogSnapshot } from '@pgpmjs/transform';
17
+ import type { PgConfig } from 'pg-env';
18
+ /**
19
+ * Create the named scratch databases, run `fn` with a per-database `PgConfig`
20
+ * for each (in the same order as `names`), and drop them all afterwards —
21
+ * even if `fn` throws. Drop failures are logged, never thrown, so they can't
22
+ * mask the original error.
23
+ */
24
+ export declare const withScratchDatabases: <T>(config: PgConfig, names: string[], fn: (configs: PgConfig[]) => Promise<T>) => Promise<T>;
25
+ /**
26
+ * Snapshot the catalogs of two databases and return their differences. An
27
+ * optional `normalize` transform is applied to both snapshots first (e.g.
28
+ * `withoutColumnOrder` when a drop+add migration cannot reproduce a fresh
29
+ * deploy's physical column ordinals). Empty result means equivalent.
30
+ */
31
+ export declare const catalogDifferences: (configA: PgConfig, configB: PgConfig, normalize?: (snap: CatalogSnapshot) => CatalogSnapshot) => Promise<string[]>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.catalogDifferences = exports.withScratchDatabases = void 0;
4
+ /**
5
+ * Scratch-database catalog oracle shared by the dials commands that prove
6
+ * structural equivalence (`pgpm transform --check`, `pgpm diff --verify`).
7
+ *
8
+ * Both commands do the same dance: create throwaway databases, deploy a
9
+ * schema into each, snapshot the catalogs, and diff them — always dropping the
10
+ * scratch databases afterwards even on failure. This centralizes the lifecycle
11
+ * (`withScratchDatabases`) and the snapshot/compare step (`catalogDifferences`)
12
+ * so each command only supplies what is genuinely command-specific: how it
13
+ * deploys a side.
14
+ *
15
+ * It lives in the CLI (not `@pgpmjs/transform`) because deploying touches
16
+ * `PgpmMigrate` from `@pgpmjs/core`, and `core` already depends on `transform`
17
+ * — hosting the oracle in `transform` would close that cycle.
18
+ */
19
+ const transform_1 = require("@pgpmjs/transform");
20
+ const logger_1 = require("@pgpmjs/logger");
21
+ const pg_cache_1 = require("pg-cache");
22
+ const log = new logger_1.Logger('scratch-db');
23
+ const createScratchDb = async (config, dbName) => {
24
+ const adminPool = (0, pg_cache_1.getPgPool)({ ...config, database: 'postgres' });
25
+ await adminPool.query(`DROP DATABASE IF EXISTS "${dbName}"`);
26
+ await adminPool.query(`CREATE DATABASE "${dbName}"`);
27
+ };
28
+ const dropScratchDb = async (config, dbName) => {
29
+ const adminPool = (0, pg_cache_1.getPgPool)({ ...config, database: 'postgres' });
30
+ await adminPool.query(`DROP DATABASE IF EXISTS "${dbName}" WITH (FORCE)`);
31
+ };
32
+ /**
33
+ * Create the named scratch databases, run `fn` with a per-database `PgConfig`
34
+ * for each (in the same order as `names`), and drop them all afterwards —
35
+ * even if `fn` throws. Drop failures are logged, never thrown, so they can't
36
+ * mask the original error.
37
+ */
38
+ const withScratchDatabases = async (config, names, fn) => {
39
+ try {
40
+ for (const name of names)
41
+ await createScratchDb(config, name);
42
+ return await fn(names.map(name => ({ ...config, database: name })));
43
+ }
44
+ finally {
45
+ try {
46
+ for (const name of names)
47
+ await dropScratchDb(config, name);
48
+ }
49
+ catch (err) {
50
+ log.warn(`failed to drop scratch databases: ${err instanceof Error ? err.message : err}`);
51
+ }
52
+ }
53
+ };
54
+ exports.withScratchDatabases = withScratchDatabases;
55
+ /**
56
+ * Snapshot the catalogs of two databases and return their differences. An
57
+ * optional `normalize` transform is applied to both snapshots first (e.g.
58
+ * `withoutColumnOrder` when a drop+add migration cannot reproduce a fresh
59
+ * deploy's physical column ordinals). Empty result means equivalent.
60
+ */
61
+ const catalogDifferences = async (configA, configB, normalize = snap => snap) => {
62
+ const snapA = await (0, transform_1.snapshotCatalog)((0, pg_cache_1.getPgPool)(configA));
63
+ const snapB = await (0, transform_1.snapshotCatalog)((0, pg_cache_1.getPgPool)(configB));
64
+ return (0, transform_1.diffCatalogSnapshots)(normalize(snapA), normalize(snapB));
65
+ };
66
+ exports.catalogDifferences = catalogDifferences;