pgpm 5.19.1 → 5.21.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.
- package/commands/cache.js +1 -1
- package/commands/diff.d.ts +3 -0
- package/commands/diff.js +359 -0
- package/commands/dump.js +3 -3
- package/commands/export.js +24 -5
- package/commands/import.d.ts +3 -0
- package/commands/import.js +235 -0
- package/commands/init/boilerplate.js +1 -1
- package/commands/init/index.js +3 -3
- package/commands/package.js +0 -1
- package/commands/slice.js +1 -1
- package/commands/test-packages.js +1 -1
- package/commands/transform.d.ts +13 -0
- package/commands/transform.js +317 -0
- package/commands/update.js +1 -1
- package/commands.js +7 -0
- package/esm/commands/cache.js +1 -1
- package/esm/commands/diff.js +324 -0
- package/esm/commands/dump.js +3 -3
- package/esm/commands/export.js +22 -3
- package/esm/commands/import.js +200 -0
- package/esm/commands/init/boilerplate.js +1 -1
- package/esm/commands/init/index.js +3 -3
- package/esm/commands/package.js +0 -1
- package/esm/commands/slice.js +1 -1
- package/esm/commands/test-packages.js +1 -1
- package/esm/commands/transform.js +278 -0
- package/esm/commands/update.js +1 -1
- package/esm/commands.js +7 -0
- package/esm/utils/display.js +3 -0
- package/esm/utils/driver.js +1 -1
- package/esm/utils/emit-package.js +1 -0
- package/esm/utils/engine.js +1 -1
- package/esm/utils/module-projections.js +82 -0
- package/esm/utils/scratch-db.js +61 -0
- package/package.json +14 -12
- package/utils/display.d.ts +1 -1
- package/utils/display.js +3 -0
- package/utils/driver.js +1 -1
- package/utils/emit-package.d.ts +9 -0
- package/utils/emit-package.js +7 -0
- package/utils/engine.js +1 -1
- package/utils/module-projections.d.ts +36 -0
- package/utils/module-projections.js +123 -0
- package/utils/scratch-db.d.ts +16 -0
- package/utils/scratch-db.js +66 -0
|
@@ -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,36 @@
|
|
|
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>;
|
|
16
|
+
/** Resolved `--emit-sql` / `--emit-bundle` projection targets for a command. */
|
|
17
|
+
export interface EmitProjectionTargets {
|
|
18
|
+
/** Linear SQL target (absolute path, or `-` for stdout). */
|
|
19
|
+
emitSql?: string;
|
|
20
|
+
/** Bundle archive target (absolute path). */
|
|
21
|
+
emitBundle?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parse the shared `--emit-sql` / `--emit-bundle` projection flags off a parsed
|
|
25
|
+
* argv, resolving file targets against `cwd` (the `-` stdout sentinel for SQL is
|
|
26
|
+
* preserved). Keeps every command's projection flags identical.
|
|
27
|
+
*/
|
|
28
|
+
export declare const parseEmitProjectionTargets: (argv: Record<string, unknown>, cwd: string) => EmitProjectionTargets;
|
|
29
|
+
/** Whether any projection target was requested. */
|
|
30
|
+
export declare const hasEmitProjection: (targets: EmitProjectionTargets) => boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Run the requested SQL/bundle projections against a written module directory.
|
|
33
|
+
* `onSuccess` (when provided) is invoked with a human-readable line per emitted
|
|
34
|
+
* artifact; it is skipped for stdout SQL so the stream stays valid SQL.
|
|
35
|
+
*/
|
|
36
|
+
export declare const projectModule: (moduleDir: string, targets: EmitProjectionTargets, onSuccess?: (message: string) => void) => Promise<void>;
|
|
@@ -0,0 +1,123 @@
|
|
|
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.projectModule = exports.hasEmitProjection = exports.parseEmitProjectionTargets = 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;
|
|
86
|
+
/**
|
|
87
|
+
* Parse the shared `--emit-sql` / `--emit-bundle` projection flags off a parsed
|
|
88
|
+
* argv, resolving file targets against `cwd` (the `-` stdout sentinel for SQL is
|
|
89
|
+
* preserved). Keeps every command's projection flags identical.
|
|
90
|
+
*/
|
|
91
|
+
const parseEmitProjectionTargets = (argv, cwd) => {
|
|
92
|
+
const sqlRaw = argv['emit-sql'] ?? argv.emitSql;
|
|
93
|
+
const emitSql = typeof sqlRaw === 'string' && sqlRaw
|
|
94
|
+
? sqlRaw === exports.STDOUT_TARGET
|
|
95
|
+
? exports.STDOUT_TARGET
|
|
96
|
+
: path.resolve(cwd, sqlRaw)
|
|
97
|
+
: undefined;
|
|
98
|
+
const bundleRaw = argv['emit-bundle'] ?? argv.emitBundle;
|
|
99
|
+
const emitBundle = typeof bundleRaw === 'string' && bundleRaw ? path.resolve(cwd, bundleRaw) : undefined;
|
|
100
|
+
return { emitSql, emitBundle };
|
|
101
|
+
};
|
|
102
|
+
exports.parseEmitProjectionTargets = parseEmitProjectionTargets;
|
|
103
|
+
/** Whether any projection target was requested. */
|
|
104
|
+
const hasEmitProjection = (targets) => Boolean(targets.emitSql || targets.emitBundle);
|
|
105
|
+
exports.hasEmitProjection = hasEmitProjection;
|
|
106
|
+
/**
|
|
107
|
+
* Run the requested SQL/bundle projections against a written module directory.
|
|
108
|
+
* `onSuccess` (when provided) is invoked with a human-readable line per emitted
|
|
109
|
+
* artifact; it is skipped for stdout SQL so the stream stays valid SQL.
|
|
110
|
+
*/
|
|
111
|
+
const projectModule = async (moduleDir, targets, onSuccess) => {
|
|
112
|
+
if (targets.emitSql) {
|
|
113
|
+
await (0, exports.emitModuleSql)(moduleDir, targets.emitSql);
|
|
114
|
+
if (targets.emitSql !== exports.STDOUT_TARGET) {
|
|
115
|
+
onSuccess?.(`wrote linear SQL to ${targets.emitSql}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (targets.emitBundle) {
|
|
119
|
+
await (0, exports.emitModuleBundle)(moduleDir, targets.emitBundle);
|
|
120
|
+
onSuccess?.(`wrote bundle to ${targets.emitBundle}`);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
exports.projectModule = projectModule;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CatalogSnapshot } from '@pgpmjs/transform';
|
|
2
|
+
import type { PgConfig } from 'pg-env';
|
|
3
|
+
/**
|
|
4
|
+
* Create the named scratch databases, run `fn` with a per-database `PgConfig`
|
|
5
|
+
* for each (in the same order as `names`), and drop them all afterwards —
|
|
6
|
+
* even if `fn` throws. Drop failures are logged, never thrown, so they can't
|
|
7
|
+
* mask the original error.
|
|
8
|
+
*/
|
|
9
|
+
export declare const withScratchDatabases: <T>(config: PgConfig, names: string[], fn: (configs: PgConfig[]) => Promise<T>) => Promise<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Snapshot the catalogs of two databases and return their differences. An
|
|
12
|
+
* optional `normalize` transform is applied to both snapshots first (e.g.
|
|
13
|
+
* `withoutColumnOrder` when a drop+add migration cannot reproduce a fresh
|
|
14
|
+
* deploy's physical column ordinals). Empty result means equivalent.
|
|
15
|
+
*/
|
|
16
|
+
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 logger_1 = require("@pgpmjs/logger");
|
|
20
|
+
const transform_1 = require("@pgpmjs/transform");
|
|
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;
|