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
package/commands/cache.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const inquirerer_1 = require("inquirerer");
4
3
  const genomic_1 = require("genomic");
4
+ const inquirerer_1 = require("inquirerer");
5
5
  const cacheUsageText = `
6
6
  Cache Command:
7
7
 
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
3
+ export default _default;
@@ -0,0 +1,325 @@
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
+ const core_1 = require("@pgpmjs/core");
37
+ const diff_1 = require("@pgpmjs/diff");
38
+ const logger_1 = require("@pgpmjs/logger");
39
+ const transform_1 = require("@pgpmjs/transform");
40
+ const child_process_1 = require("child_process");
41
+ const fs = __importStar(require("fs"));
42
+ const inquirerer_1 = require("inquirerer");
43
+ const os = __importStar(require("os"));
44
+ const path = __importStar(require("path"));
45
+ const pg_cache_1 = require("pg-cache");
46
+ const pg_env_1 = require("pg-env");
47
+ const module_projections_1 = require("../utils/module-projections");
48
+ const scratch_db_1 = require("../utils/scratch-db");
49
+ const log = new logger_1.Logger('diff');
50
+ const diffUsageText = `
51
+ Diff Command:
52
+
53
+ pgpm diff <A> <B> [OPTIONS]
54
+
55
+ Identity-keyed semantic diff between two schema sources. Each side is
56
+ normalized to an object set keyed by identity (kind/schema/name), so the
57
+ same schema authored at different granularity, naming, or partitioning
58
+ diffs as empty. Tables are compared column-by-column and
59
+ constraint-by-constraint, so table changes emit ALTER TABLE, not a rebuild.
60
+
61
+ Sides:
62
+ <A> / <B> may each be:
63
+ - a pgpm module directory (flattened in plan order)
64
+ - a raw .sql file
65
+ - a live database: a postgres:// connection string, or db:<name>
66
+ (uses PG* env for host/port/user; schema is read via pg_dump)
67
+
68
+ The delta is one model; every --emit-* flag is a projection of it, so they
69
+ compose (a single run can emit a module, a linear SQL file, and a bundle).
70
+
71
+ Options:
72
+ --help, -h Show this help message
73
+ --emit-migration <dir> Write the delta as a pgpm module (deploy/revert/
74
+ verify per change, spec-derived paths, graph-derived
75
+ requires) into <dir>/<pkg>
76
+ --emit-module <dir> Alias of --emit-migration
77
+ --emit-sql <file|-> Also project the delta to a single consolidated SQL
78
+ file (deparsed in plan order); - writes to stdout
79
+ --emit-bundle <file> Also project the delta to a content-addressed
80
+ .bundle.tar.gz archive
81
+ --pkg <name> Emitted migration package name (default: diff-migration)
82
+ --granularity <level> Granularity for emitted changes: atomic | object |
83
+ consolidated (default: object)
84
+ --naming <style> Change path naming style: directory | flat (default: directory)
85
+ --json Machine-readable output
86
+ --verify Oracle mode: deploy A plus the emitted migration into
87
+ a scratch database and assert catalog equivalence
88
+ with B deployed fresh
89
+ --cwd <directory> Working directory (default: current directory)
90
+
91
+ Exit status: 0 when the sides are identical or the diff succeeds; non-zero on
92
+ error or when --verify finds the migrated catalog differs from B.
93
+
94
+ Examples:
95
+ pgpm diff ./v1-module ./v2-module
96
+ pgpm diff ./v1-module ./schema-v2.sql --json
97
+ pgpm diff db:app_v1 db:app_v2 --emit-migration ./out --verify
98
+ `;
99
+ const NAMING_STYLES = ['directory', 'flat'];
100
+ /** pg_dump a side's schema: `db:<name>` uses PG* env; DSNs pass through. */
101
+ const dumpDatabase = async (spec) => {
102
+ const args = ['--schema-only', '--no-owner'];
103
+ let env = process.env;
104
+ if (spec.startsWith('db:')) {
105
+ const config = (0, pg_env_1.getPgEnvOptions)({ database: spec.slice(3) });
106
+ env = (0, pg_env_1.getSpawnEnvWithPg)(config);
107
+ }
108
+ else {
109
+ args.push('--dbname', spec);
110
+ }
111
+ return new Promise((resolve, reject) => {
112
+ const child = (0, child_process_1.spawn)('pg_dump', args, { env, stdio: ['ignore', 'pipe', 'pipe'] });
113
+ let out = '';
114
+ let err = '';
115
+ child.stdout.on('data', chunk => { out += chunk; });
116
+ child.stderr.on('data', chunk => { err += chunk; });
117
+ child.on('error', (e) => {
118
+ if (e.code === 'ENOENT') {
119
+ reject(new Error('pg_dump not found; ensure PostgreSQL client tools are installed and in PATH'));
120
+ return;
121
+ }
122
+ reject(e);
123
+ });
124
+ child.on('close', code => {
125
+ if (code === 0)
126
+ resolve(out);
127
+ else
128
+ reject(new Error(`pg_dump exited with code ${code}: ${err.trim()}`));
129
+ });
130
+ });
131
+ };
132
+ /** Resolve one side spec into diff input changes. */
133
+ const loadSide = async (spec, cwd) => {
134
+ if (resolveDiffSideKindSafe(spec) === 'database') {
135
+ const label = spec.startsWith('db:') ? spec.slice(3) : spec;
136
+ return {
137
+ kind: 'database',
138
+ label,
139
+ changes: (0, diff_1.sqlToDiffChanges)(await dumpDatabase(spec), label),
140
+ warnings: []
141
+ };
142
+ }
143
+ return (0, diff_1.loadDiffSideFromDisk)(path.resolve(cwd, spec));
144
+ };
145
+ /** `resolveDiffSideKind` without throwing on relative on-disk paths. */
146
+ const resolveDiffSideKindSafe = (spec) => /^postgres(ql)?:\/\//.test(spec) || spec.startsWith('db:') ? 'database' : 'disk';
147
+ /** Apply one diff side into a scratch database (module deploy or raw SQL). */
148
+ const applySide = async (config, side, spec, cwd) => {
149
+ if (side.kind === 'module') {
150
+ const client = new core_1.PgpmMigrate(config);
151
+ const result = await client.deploy({ modulePath: path.resolve(cwd, spec) });
152
+ if (result.failed) {
153
+ throw new Error(`deploy failed at change ${result.failed} (module ${spec})`);
154
+ }
155
+ return;
156
+ }
157
+ const pool = (0, pg_cache_1.getPgPool)(config);
158
+ const sql = side.changes.map(c => c.deploy).filter(Boolean).join('\n\n');
159
+ if (sql.trim())
160
+ await pool.query(sql);
161
+ };
162
+ /**
163
+ * Oracle mode: deploy A into a scratch database, deploy the emitted migration
164
+ * module on top (when there is one), and assert catalog equivalence with B
165
+ * deployed fresh into a second scratch database. Column order is physical — a
166
+ * drop+add migration cannot reproduce a fresh deploy's ordinals — so
167
+ * equivalence is checked order-insensitively via `withoutColumnOrder`.
168
+ */
169
+ const runVerify = async (sideA, sideB, specA, specB, migrationDir, cwd) => {
170
+ const config = (0, pg_env_1.getPgEnvOptions)();
171
+ const stamp = Date.now();
172
+ const names = [`pgpm_diff_verify_a_${stamp}`, `pgpm_diff_verify_b_${stamp}`];
173
+ return (0, scratch_db_1.withScratchDatabases)(config, names, async ([cfgMigrated, cfgTarget]) => {
174
+ await applySide(cfgMigrated, sideA, specA, cwd);
175
+ if (migrationDir) {
176
+ const result = await new core_1.PgpmMigrate(cfgMigrated).deploy({ modulePath: migrationDir });
177
+ if (result.failed) {
178
+ throw new Error(`migration deploy failed at change ${result.failed}`);
179
+ }
180
+ }
181
+ await applySide(cfgTarget, sideB, specB, cwd);
182
+ return (0, scratch_db_1.catalogDifferences)(cfgMigrated, cfgTarget, transform_1.withoutColumnOrder);
183
+ });
184
+ };
185
+ const printSummary = (result, labelA, labelB) => {
186
+ if (result.identical) {
187
+ console.log(`No differences: ${labelA} and ${labelB} describe the same objects.`);
188
+ return;
189
+ }
190
+ const byDelta = (delta) => result.objects.filter(o => o.delta === delta);
191
+ const section = (title, objects) => {
192
+ if (objects.length === 0)
193
+ return;
194
+ console.log(`${title} (${objects.length}):`);
195
+ for (const obj of objects) {
196
+ const detail = [];
197
+ if (obj.columnsAdded?.length)
198
+ detail.push(`+cols: ${obj.columnsAdded.join(', ')}`);
199
+ if (obj.columnsRemoved?.length)
200
+ detail.push(`-cols: ${obj.columnsRemoved.join(', ')}`);
201
+ if (obj.columnsModified?.length)
202
+ detail.push(`~cols: ${obj.columnsModified.join(', ')}`);
203
+ console.log(` ${obj.identity.kind} ${obj.path}${detail.length ? ` (${detail.join('; ')})` : ''}`);
204
+ }
205
+ };
206
+ section('Added', byDelta('added'));
207
+ section('Removed', byDelta('removed'));
208
+ section('Changed', byDelta('modified'));
209
+ console.log(`${result.changes.length} migration change(s) derivable.`);
210
+ };
211
+ exports.default = async (argv, prompter, _options) => {
212
+ if (argv.help || argv.h) {
213
+ console.log(diffUsageText);
214
+ process.exit(0);
215
+ }
216
+ const { first: specA, newArgv } = (0, inquirerer_1.extractFirst)(argv);
217
+ const { first: specB, newArgv: restArgv } = (0, inquirerer_1.extractFirst)(newArgv);
218
+ argv = restArgv;
219
+ if (!specA || !specB) {
220
+ await (0, inquirerer_1.cliExitWithError)('pgpm diff requires two sides: pgpm diff <A> <B> (module dir, .sql file, db:<name>, or connection string).');
221
+ }
222
+ const granularityRaw = argv.granularity ?? 'object';
223
+ if (!(0, transform_1.isExportGranularity)(granularityRaw)) {
224
+ await (0, inquirerer_1.cliExitWithError)(`Invalid --granularity "${granularityRaw}". Expected one of: ${transform_1.EXPORT_GRANULARITIES.join(', ')}.`);
225
+ }
226
+ const granularity = granularityRaw;
227
+ const namingRaw = argv.naming ?? 'directory';
228
+ if (!NAMING_STYLES.includes(namingRaw)) {
229
+ await (0, inquirerer_1.cliExitWithError)(`Invalid --naming "${namingRaw}". Expected one of: ${NAMING_STYLES.join(', ')}.`);
230
+ }
231
+ const naming = namingRaw;
232
+ const cwd = argv.cwd || process.cwd();
233
+ const json = Boolean(argv.json);
234
+ const verify = Boolean(argv.verify);
235
+ const emitModuleRaw = argv['emit-migration'] ?? argv.emitMigration ?? argv['emit-module'] ?? argv.emitModule;
236
+ const emitModuleDir = typeof emitModuleRaw === 'string' && emitModuleRaw
237
+ ? path.resolve(cwd, emitModuleRaw)
238
+ : undefined;
239
+ const emitSqlRaw = argv['emit-sql'] ?? argv.emitSql;
240
+ const emitSql = typeof emitSqlRaw === 'string' && emitSqlRaw
241
+ ? (emitSqlRaw === module_projections_1.STDOUT_TARGET ? module_projections_1.STDOUT_TARGET : path.resolve(cwd, emitSqlRaw))
242
+ : undefined;
243
+ const emitBundleRaw = argv['emit-bundle'] ?? argv.emitBundle;
244
+ const emitBundle = typeof emitBundleRaw === 'string' && emitBundleRaw
245
+ ? path.resolve(cwd, emitBundleRaw)
246
+ : undefined;
247
+ const sqlToStdout = emitSql === module_projections_1.STDOUT_TARGET;
248
+ const pkgName = argv.pkg || 'diff-migration';
249
+ await (0, transform_1.loadModule)();
250
+ let sideA;
251
+ let sideB;
252
+ try {
253
+ sideA = await loadSide(specA, cwd);
254
+ sideB = await loadSide(specB, cwd);
255
+ }
256
+ catch (err) {
257
+ await (0, inquirerer_1.cliExitWithError)(err instanceof Error ? err.message : String(err));
258
+ return;
259
+ }
260
+ const result = (0, transform_1.diffChangeSets)(sideA.changes, sideB.changes, { granularity, style: naming });
261
+ const warnings = [
262
+ ...sideA.warnings.map(w => `${sideA.label}: ${w}`),
263
+ ...sideB.warnings.map(w => `${sideB.label}: ${w}`),
264
+ ...result.warnings
265
+ ];
266
+ if (json) {
267
+ console.log(JSON.stringify({
268
+ identical: result.identical,
269
+ objects: result.objects,
270
+ changes: result.changes.map(c => ({
271
+ name: c.name,
272
+ dependencies: c.dependencies,
273
+ deploy: c.deploy,
274
+ revert: c.revert,
275
+ verify: c.verify
276
+ })),
277
+ warnings
278
+ }, null, 2));
279
+ }
280
+ else {
281
+ for (const warning of warnings)
282
+ console.warn(`diff: ${warning}`);
283
+ // Keep stdout clean when the SQL projection is piped there.
284
+ if (!sqlToStdout)
285
+ printSummary(result, sideA.label, sideB.label);
286
+ }
287
+ let migrationDir;
288
+ const needModule = Boolean(emitModuleDir || emitSql || emitBundle) || (verify && !result.identical);
289
+ if (needModule) {
290
+ const outBase = emitModuleDir ?? fs.mkdtempSync(path.join(os.tmpdir(), 'pgpm-diff-'));
291
+ const rows = (0, diff_1.deltaChangesToRows)(result.changes);
292
+ if (rows.length === 0) {
293
+ if (!sqlToStdout)
294
+ log.info('no migration changes to emit (sides are identical).');
295
+ }
296
+ else {
297
+ migrationDir = (0, transform_1.writeModule)(outBase, { name: pkgName, requires: [], rows });
298
+ if (emitModuleDir && !sqlToStdout)
299
+ log.success(`wrote ${rows.length} migration change(s) to ${migrationDir}`);
300
+ if (emitSql) {
301
+ await (0, module_projections_1.emitModuleSql)(migrationDir, emitSql);
302
+ if (!sqlToStdout)
303
+ log.success(`wrote linear SQL to ${emitSql}`);
304
+ }
305
+ if (emitBundle) {
306
+ await (0, module_projections_1.emitModuleBundle)(migrationDir, emitBundle);
307
+ if (!sqlToStdout)
308
+ log.success(`wrote bundle to ${emitBundle}`);
309
+ }
310
+ }
311
+ }
312
+ if (verify) {
313
+ log.info('running --verify: deploying A plus the migration and B into scratch databases...');
314
+ const diffs = await runVerify(sideA, sideB, specA, specB, migrationDir, cwd);
315
+ if (diffs.length) {
316
+ console.error(`--verify failed: catalogs differ (${diffs.length} differences):`);
317
+ for (const diff of diffs)
318
+ console.error(` ${diff}`);
319
+ await (0, inquirerer_1.cliExitWithError)('Migrated catalog does not match the target.');
320
+ }
321
+ log.success('--verify passed: migrated catalog is structurally equivalent to the target.');
322
+ }
323
+ prompter.close();
324
+ return argv;
325
+ };
package/commands/dump.js CHANGED
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const logger_1 = require("@pgpmjs/logger");
7
- const pg_env_1 = require("pg-env");
8
- const pg_cache_1 = require("pg-cache");
7
+ const quotes_1 = require("@pgsql/quotes");
9
8
  const child_process_1 = require("child_process");
10
9
  const fs_1 = __importDefault(require("fs"));
11
10
  const path_1 = __importDefault(require("path"));
12
- const quotes_1 = require("@pgsql/quotes");
11
+ const pg_cache_1 = require("pg-cache");
12
+ const pg_env_1 = require("pg-env");
13
13
  const utils_1 = require("../utils");
14
14
  const log = new logger_1.Logger('dump');
15
15
  const dumpUsageText = `
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@pgpmjs/core");
4
- const export_1 = require("@pgpmjs/export");
5
4
  const env_1 = require("@pgpmjs/env");
5
+ const export_1 = require("@pgpmjs/export");
6
+ const transform_1 = require("@pgpmjs/transform");
6
7
  const types_1 = require("@pgpmjs/types");
7
8
  const path_1 = require("path");
8
9
  const pg_cache_1 = require("pg-cache");
@@ -30,12 +31,16 @@ Options:
30
31
  Change paths are derived from the naming spec and
31
32
  requires from the statement graph. When omitted,
32
33
  sql_actions rows are exported unchanged.
34
+ --partition <file> Partition config (JSON: rules/defaultPackage/splitRiders)
35
+ splitting the exported database module into multiple
36
+ pgpm packages with derived cross-package requires.
33
37
  --cwd <directory> Working directory (default: current directory)
34
38
 
35
39
  Examples:
36
40
  pgpm export Export migrations from selected database (SQL mode)
37
41
  pgpm export --exclude-categories security,permissions,auth,memberships
38
42
  pgpm export --granularity consolidated
43
+ pgpm export --granularity object --partition partition.json
39
44
  pgpm export --graphql-endpoint 'http://[::1]:3002/graphql' --migrate-endpoint 'http://[::1]:3000/graphql' --migrate-host db_migrate.localhost:3000
40
45
  `;
41
46
  exports.default = async (argv, prompter, _options) => {
@@ -61,12 +66,24 @@ exports.default = async (argv, prompter, _options) => {
61
66
  ? excludeCategoriesRaw
62
67
  : undefined;
63
68
  const granularityRaw = argv.granularity;
64
- if (granularityRaw !== undefined && !(0, export_1.isExportGranularity)(granularityRaw)) {
65
- console.error(`Invalid --granularity "${granularityRaw}". Expected one of: ${export_1.EXPORT_GRANULARITIES.join(', ')}.`);
69
+ if (granularityRaw !== undefined && !(0, transform_1.isExportGranularity)(granularityRaw)) {
70
+ console.error(`Invalid --granularity "${granularityRaw}". Expected one of: ${transform_1.EXPORT_GRANULARITIES.join(', ')}.`);
66
71
  prompter.close();
67
72
  return;
68
73
  }
69
74
  const granularity = granularityRaw;
75
+ const partitionRaw = argv.partition;
76
+ let partition;
77
+ if (typeof partitionRaw === 'string' && partitionRaw) {
78
+ try {
79
+ partition = (0, transform_1.parsePartitionConfig)((0, path_1.resolve)(cwd, partitionRaw));
80
+ }
81
+ catch (err) {
82
+ console.error(err instanceof Error ? err.message : String(err));
83
+ prompter.close();
84
+ return;
85
+ }
86
+ }
70
87
  if (graphqlEndpoint) {
71
88
  // =========================================================================
72
89
  // GraphQL export mode
@@ -164,7 +181,8 @@ exports.default = async (argv, prompter, _options) => {
164
181
  argv,
165
182
  username,
166
183
  excludeCategories,
167
- granularity
184
+ granularity,
185
+ partition
168
186
  });
169
187
  }
170
188
  else {
@@ -285,7 +303,8 @@ exports.default = async (argv, prompter, _options) => {
285
303
  argv,
286
304
  username,
287
305
  excludeCategories,
288
- granularity
306
+ granularity,
307
+ partition
289
308
  });
290
309
  }
291
310
  prompter.close();
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
3
+ export default _default;
@@ -0,0 +1,198 @@
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
+ const import_1 = require("@pgpmjs/import");
37
+ const logger_1 = require("@pgpmjs/logger");
38
+ const transform_1 = require("@pgpmjs/transform");
39
+ const inquirerer_1 = require("inquirerer");
40
+ const path = __importStar(require("path"));
41
+ const emit_package_1 = require("../utils/emit-package");
42
+ const log = new logger_1.Logger('import');
43
+ const importUsageText = `
44
+ Import Command:
45
+
46
+ pgpm import <dump.sql | dir-of-sql-files> --pkg <module-name> [OPTIONS]
47
+
48
+ pgpm-itize an arbitrary SQL dump (e.g. pg_dump --schema-only output): parse
49
+ it, classify every statement, and emit a complete deployable pgpm module —
50
+ module dir, pgpm.plan, and deploy/revert/verify trees with spec-derived
51
+ change paths, graph-derived requires, and generated revert/verify scripts.
52
+
53
+ Directory inputs concatenate their .sql files in sorted (lexicographic)
54
+ filename order.
55
+
56
+ Dump handling:
57
+ - pg_dump preamble noise (SET ..., SELECT set_config(...), psql backslash
58
+ commands) is skipped; COMMENT ON and GRANT statements are kept, attached
59
+ to their host object's change.
60
+ - CREATE EXTENSION statements become .control requires (pgpm owns
61
+ extension creation at deploy time).
62
+ - COPY ... FROM stdin blocks and INSERTs are skipped with a warning unless
63
+ --with-data is passed, which emits them as seed fixture changes (COPY
64
+ data is converted to INSERTs).
65
+ - Statements that classify to no object land in a misc/statements change
66
+ with a warning — never dropped silently.
67
+
68
+ Options:
69
+ --help, -h Show this help message
70
+ --pkg <name> Module name for the generated package (required)
71
+ --granularity <level> Granularity dial: atomic | object | consolidated
72
+ (default: object)
73
+ --naming <style> Change path naming style: directory | flat (default: directory)
74
+ --out <dir> Output base directory (default: current directory);
75
+ the module is written to <out>/<pkg>
76
+ --with-data Import COPY/INSERT data as seed fixture changes
77
+ --partition <file> Partition config (JSON: rules/defaultPackage/splitRiders)
78
+ splitting the import into multiple pgpm packages with
79
+ derived cross-package requires
80
+ --write Allow overwriting an existing module directory
81
+ --cwd <directory> Working directory (default: current directory)
82
+ --dry-run Print the resulting plan/paths without writing
83
+
84
+ Examples:
85
+ pgpm import dump.sql --pkg my-app
86
+ pgpm import dump.sql --pkg my-app --granularity consolidated --naming flat
87
+ pgpm import ./sql-files --pkg my-app --out ./packages --with-data
88
+ pgpm import dump.sql --pkg my-app --partition partition.json
89
+ `;
90
+ const NAMING_STYLES = ['directory', 'flat'];
91
+ exports.default = async (argv, prompter, _options) => {
92
+ if (argv.help || argv.h) {
93
+ console.log(importUsageText);
94
+ process.exit(0);
95
+ }
96
+ const cwd = argv.cwd || process.cwd();
97
+ const input = argv._?.filter(Boolean)[0];
98
+ if (!input) {
99
+ await (0, inquirerer_1.cliExitWithError)('Missing input: pgpm import <dump.sql | dir-of-sql-files> --pkg <name>');
100
+ }
101
+ const pkgName = argv.pkg;
102
+ if (!pkgName || typeof pkgName !== 'string') {
103
+ await (0, inquirerer_1.cliExitWithError)('--pkg <module-name> is required.');
104
+ }
105
+ const granularityRaw = argv.granularity ?? 'object';
106
+ if (!(0, transform_1.isExportGranularity)(granularityRaw)) {
107
+ await (0, inquirerer_1.cliExitWithError)(`Invalid --granularity "${granularityRaw}". Expected one of: ${transform_1.EXPORT_GRANULARITIES.join(', ')}.`);
108
+ }
109
+ const granularity = granularityRaw;
110
+ const namingRaw = argv.naming ?? 'directory';
111
+ if (!NAMING_STYLES.includes(namingRaw)) {
112
+ await (0, inquirerer_1.cliExitWithError)(`Invalid --naming "${namingRaw}". Expected one of: ${NAMING_STYLES.join(', ')}.`);
113
+ }
114
+ const naming = namingRaw;
115
+ let partition;
116
+ if (typeof argv.partition === 'string' && argv.partition) {
117
+ try {
118
+ partition = (0, transform_1.parsePartitionConfig)(path.resolve(cwd, argv.partition));
119
+ }
120
+ catch (err) {
121
+ await (0, inquirerer_1.cliExitWithError)(err instanceof Error ? err.message : String(err));
122
+ }
123
+ }
124
+ const outBase = typeof argv.out === 'string' && argv.out ? path.resolve(cwd, argv.out) : path.resolve(cwd);
125
+ const withData = Boolean(argv['with-data'] ?? argv.withData);
126
+ const write = Boolean(argv.write);
127
+ const dryRun = Boolean(argv['dry-run'] ?? argv.dryRun);
128
+ let source;
129
+ try {
130
+ source = (0, import_1.loadDumpSource)(path.resolve(cwd, input));
131
+ }
132
+ catch (err) {
133
+ await (0, inquirerer_1.cliExitWithError)(err instanceof Error ? err.message : String(err));
134
+ return;
135
+ }
136
+ if (source.files.length > 1) {
137
+ log.info(`concatenated ${source.files.length} .sql files in sorted order`);
138
+ }
139
+ for (const warning of (0, import_1.dumpCompatibilityWarnings)(source)) {
140
+ console.warn(`\nWARNING: ${warning}\n`);
141
+ }
142
+ const result = await (0, import_1.importDumpRows)(source, { granularity, naming, withData });
143
+ let packages;
144
+ if (partition) {
145
+ try {
146
+ const partitioned = await (0, transform_1.partitionExportRows)(result.rows, partition);
147
+ result.warnings.push(...partitioned.warnings.map(w => `partition: ${w}`));
148
+ packages = partitioned.packages.map(pkg => ({
149
+ name: pkg.name,
150
+ requires: [...result.controlRequires, ...pkg.requires],
151
+ rows: (0, import_1.linkTextualDeps)(pkg.rows)
152
+ }));
153
+ }
154
+ catch (err) {
155
+ if (err instanceof transform_1.PartitionCycleError) {
156
+ await (0, inquirerer_1.cliExitWithError)(`Partition failed: ${err.message}`);
157
+ return;
158
+ }
159
+ throw err;
160
+ }
161
+ }
162
+ else {
163
+ packages = [{ name: pkgName, requires: result.controlRequires, rows: result.rows }];
164
+ }
165
+ for (const warning of result.warnings) {
166
+ console.warn(`import: ${warning}`);
167
+ }
168
+ if (dryRun) {
169
+ for (const pkg of packages) {
170
+ console.log(`package ${pkg.name} -> ${path.join(outBase, pkg.name)}`);
171
+ if (pkg.requires.length) {
172
+ console.log(` requires: ${pkg.requires.join(', ')}`);
173
+ }
174
+ for (const row of pkg.rows) {
175
+ const deps = row.deps?.length ? ` [${row.deps.join(' ')}]` : '';
176
+ console.log(` ${row.deploy}${deps}`);
177
+ }
178
+ }
179
+ }
180
+ else {
181
+ for (const pkg of packages) {
182
+ const guard = (0, emit_package_1.checkOverwrite)(path.join(outBase, pkg.name), source.files[0], write);
183
+ if (guard) {
184
+ await (0, inquirerer_1.cliExitWithError)(guard);
185
+ }
186
+ }
187
+ for (const pkg of packages) {
188
+ const dir = (0, emit_package_1.writePackage)(outBase, pkg);
189
+ log.success(`wrote ${pkg.rows.length} changes to ${dir}`);
190
+ }
191
+ }
192
+ const { summary } = result;
193
+ log.success(`import: ${summary.statements} statement(s) -> ${summary.changes} change(s), ` +
194
+ `${summary.skippedPreamble} preamble skipped, ${summary.skippedData} data skipped, ` +
195
+ `${summary.misc} in misc, ${result.warnings.length} warning(s)`);
196
+ prompter.close();
197
+ return argv;
198
+ };
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolveInitTemplateRepo = resolveInitTemplateRepo;
7
7
  exports.persistBoilerplateSource = persistBoilerplateSource;
8
8
  exports.readBoilerplateSource = readBoilerplateSource;
9
+ const core_1 = require("@pgpmjs/core");
9
10
  const fs_1 = __importDefault(require("fs"));
10
11
  const path_1 = __importDefault(require("path"));
11
- const core_1 = require("@pgpmjs/core");
12
12
  /**
13
13
  * Resolve the template repo for an `init` invocation from its flags.
14
14
  *
@@ -4,13 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createInitUsageText = void 0;
7
- const child_process_1 = require("child_process");
8
- const fs_1 = __importDefault(require("fs"));
9
- const path_1 = __importDefault(require("path"));
10
7
  const core_1 = require("@pgpmjs/core");
11
8
  const env_1 = require("@pgpmjs/env");
12
9
  const types_1 = require("@pgpmjs/types");
10
+ const child_process_1 = require("child_process");
11
+ const fs_1 = __importDefault(require("fs"));
13
12
  const inquirerer_1 = require("inquirerer");
13
+ const path_1 = __importDefault(require("path"));
14
14
  const utils_1 = require("../../utils");
15
15
  const boilerplate_1 = require("./boilerplate");
16
16
  const DEFAULT_MOTD = `
@@ -118,7 +118,6 @@ exports.default = async (argv, prompter, _options) => {
118
118
  const project = new core_1.PgpmPackage(cwd);
119
119
  project.ensureModule();
120
120
  const info = project.getModuleInfo();
121
- info.version;
122
121
  await (0, core_1.writePackage)({
123
122
  version: info.version,
124
123
  extension: true,