frg-data-diff 2.0.0 → 2.1.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/README.md +45 -4
- package/dist/cli/generator.js +156 -5
- package/dist/cli/pg-views.d.ts +2 -0
- package/dist/cli/pg-views.js +195 -0
- package/dist/cli/root.js +6 -0
- package/dist/config/config-schema.d.ts +32 -0
- package/dist/config/config-schema.js +4 -0
- package/dist/config/load-config.d.ts +1 -0
- package/dist/config/load-config.js +78 -1
- package/dist/config/resolve-options.d.ts +8 -2
- package/dist/config/resolve-options.js +28 -0
- package/dist/config/write-config.d.ts +2 -1
- package/dist/config/write-config.js +4 -0
- package/dist/db/pg-views.d.ts +24 -0
- package/dist/db/pg-views.js +137 -0
- package/dist/diff/pg-views-diff.d.ts +11 -0
- package/dist/diff/pg-views-diff.js +133 -0
- package/dist/schema-diff/generate-schema-diff.js +1 -1
- package/dist/schema-diff/schema-diff-schema.d.ts +3 -3
- package/dist/schema-diff/schema-diff-schema.js +1 -1
- package/dist/shared/generator-wizard.js +9 -0
- package/frg-triggers-diff.sql +4 -0
- package/frg-views-diff.sql +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> It compares row data between two PostgreSQL databases and safely applies changes.
|
|
4
4
|
>
|
|
5
|
-
> It also produces
|
|
5
|
+
> It also produces review-only schema, trigger/function, and view SQL artifacts for manual execution.
|
|
6
6
|
|
|
7
7
|
Safe PostgreSQL **data** diff and apply tooling, with companion PostgreSQL **schema** diff output for manual review. Compare data between two PostgreSQL databases and apply changes with strong safety guards.
|
|
8
8
|
|
|
@@ -23,6 +23,8 @@ npx frg-data-diff
|
|
|
23
23
|
npx frg-data-diff generate
|
|
24
24
|
npx frg-data-diff apply
|
|
25
25
|
npx frg-data-diff sql
|
|
26
|
+
npx frg-data-diff pg-triggers
|
|
27
|
+
npx frg-data-diff pg-views
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
---
|
|
@@ -62,12 +64,30 @@ Reads a JSON diff file and writes a plain SQL script for manual review and execu
|
|
|
62
64
|
npx frg-data-diff sql --input frg-data-diff.json --output frg-data-diff.sql
|
|
63
65
|
```
|
|
64
66
|
|
|
67
|
+
### `frg-data-diff pg-triggers`
|
|
68
|
+
|
|
69
|
+
Compares PostgreSQL triggers and functions and writes a SQL diff script.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx frg-data-diff pg-triggers --output frg-triggers-diff.sql
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `frg-data-diff pg-views`
|
|
76
|
+
|
|
77
|
+
Compares regular and materialized view definitions and writes a SQL diff script.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx frg-data-diff pg-views --output frg-views-diff.sql
|
|
81
|
+
```
|
|
82
|
+
|
|
65
83
|
---
|
|
66
84
|
|
|
67
85
|
## Configuration File: `.frg-data-diff.config.json`
|
|
68
86
|
|
|
69
87
|
Commands look for this file in the current working directory.
|
|
70
88
|
|
|
89
|
+
The config file is JSON with comments: `// line comments` and `/* block comments */` are accepted. Other JSON rules still apply, including no trailing commas.
|
|
90
|
+
|
|
71
91
|
### Committing the config file
|
|
72
92
|
|
|
73
93
|
**Do commit** `.frg-data-diff.config.json` to version control.
|
|
@@ -86,11 +106,13 @@ Generator list fields also support `$ENV_VAR` entries:
|
|
|
86
106
|
- `schemaDiffExcludeTables`
|
|
87
107
|
- `pgTriggersTables`
|
|
88
108
|
- `pgTriggersExcludeTables`
|
|
109
|
+
- `pgViews`
|
|
110
|
+
- `pgViewsExclude`
|
|
89
111
|
- `ignoreColumns`
|
|
90
112
|
|
|
91
113
|
When used in those list fields, the environment variable value is parsed as a comma-separated list at runtime.
|
|
92
114
|
|
|
93
|
-
Data, schema diff, and PostgreSQL
|
|
115
|
+
Data, schema diff, PostgreSQL trigger, and PostgreSQL view filters are independent. Schema and trigger include filters inherit `tables` when omitted. View include filters default to all views when omitted.
|
|
94
116
|
|
|
95
117
|
In the interactive wizard, pressing Enter keeps the displayed default. For optional list fields, type `none` to clear the value; the config stores that explicit clear as an empty array.
|
|
96
118
|
|
|
@@ -121,6 +143,9 @@ In the interactive wizard, pressing Enter keeps the displayed default. For optio
|
|
|
121
143
|
"pgTriggersTables": ["my_table"],
|
|
122
144
|
"pgTriggersExcludeTables": [],
|
|
123
145
|
"pgTriggersOutput": "frg-triggers-diff.sql",
|
|
146
|
+
"pgViews": ["*"],
|
|
147
|
+
"pgViewsExclude": [],
|
|
148
|
+
"pgViewsOutput": "frg-views-diff.sql",
|
|
124
149
|
"ignoreColumns": ["created_at", "updated_at"],
|
|
125
150
|
"includeDeletes": true,
|
|
126
151
|
"skipMissingPk": false,
|
|
@@ -256,6 +281,13 @@ Key options:
|
|
|
256
281
|
| `--table` | Table(s) or `*` patterns to include (repeatable) |
|
|
257
282
|
| `--exclude-table` | Table(s) or `*` patterns to skip (repeatable) |
|
|
258
283
|
| `--ignore-column` | Column(s) to ignore during comparison (repeatable) |
|
|
284
|
+
| `--pg-triggers-table` | Table(s) for trigger/function diff |
|
|
285
|
+
| `--pg-triggers-output` | Output path for PostgreSQL trigger/function diff SQL |
|
|
286
|
+
| `--generate-pg-triggers` | Generate PostgreSQL trigger/function diff SQL |
|
|
287
|
+
| `--pg-view` | View(s) or `*` patterns for view DDL diff |
|
|
288
|
+
| `--pg-view-exclude` | View(s) or `*` patterns to skip in view DDL diff |
|
|
289
|
+
| `--pg-views-output` | Output path for PostgreSQL view diff SQL |
|
|
290
|
+
| `--generate-pg-views` | Generate PostgreSQL view diff SQL from `generate` |
|
|
259
291
|
| `--include-deletes` | Generate delete entries for rows only in dest |
|
|
260
292
|
| `--skip-missing-pk` | Skip tables without a primary key instead of failing |
|
|
261
293
|
| `--output` | Output diff file path (default: `frg-data-diff.json`) |
|
|
@@ -372,6 +404,8 @@ export DIRECTUS_TABLES="directus_*, custom_table"
|
|
|
372
404
|
export DIRECTUS_EXCLUDES="directus_activity, directus_sessions"
|
|
373
405
|
export DIRECTUS_PG_TRIGGER_TABLES="directus_flows, directus_operations"
|
|
374
406
|
export DIRECTUS_PG_TRIGGER_EXCLUDES="directus_sessions"
|
|
407
|
+
export DIRECTUS_PG_VIEWS="directus_*_view, custom_view"
|
|
408
|
+
export DIRECTUS_PG_VIEW_EXCLUDES="legacy_*"
|
|
375
409
|
export DIRECTUS_IGNORED_COLUMNS="created_at, updated_at"
|
|
376
410
|
```
|
|
377
411
|
|
|
@@ -383,6 +417,9 @@ export DIRECTUS_IGNORED_COLUMNS="created_at, updated_at"
|
|
|
383
417
|
"pgTriggersTables": ["$DIRECTUS_PG_TRIGGER_TABLES"],
|
|
384
418
|
"pgTriggersExcludeTables": ["$DIRECTUS_PG_TRIGGER_EXCLUDES"],
|
|
385
419
|
"pgTriggersOutput": "frg-triggers-diff.sql",
|
|
420
|
+
"pgViews": ["$DIRECTUS_PG_VIEWS"],
|
|
421
|
+
"pgViewsExclude": ["$DIRECTUS_PG_VIEW_EXCLUDES"],
|
|
422
|
+
"pgViewsOutput": "frg-views-diff.sql",
|
|
386
423
|
"ignoreColumns": ["$DIRECTUS_IGNORED_COLUMNS"]
|
|
387
424
|
}
|
|
388
425
|
}
|
|
@@ -400,7 +437,7 @@ export DIRECTUS_IGNORED_COLUMNS="created_at, updated_at"
|
|
|
400
437
|
- **dryRun defaults to true** — no mutations without `--execute`.
|
|
401
438
|
- **Transaction by default** — all changes in a single transaction; rolled back on failure in `abort` mode.
|
|
402
439
|
- **Generated columns are never written**.
|
|
403
|
-
- **
|
|
440
|
+
- **Data apply never mutates schema** — generated schema, trigger, and view SQL is review-only and must be executed manually.
|
|
404
441
|
|
|
405
442
|
---
|
|
406
443
|
|
|
@@ -479,6 +516,9 @@ For publishing Directus configuration data from development to production:
|
|
|
479
516
|
"pgTriggersTables": ["directus_flows", "directus_operations"],
|
|
480
517
|
"pgTriggersExcludeTables": [],
|
|
481
518
|
"pgTriggersOutput": "frg-triggers-diff.sql",
|
|
519
|
+
"pgViews": ["directus_*_view"],
|
|
520
|
+
"pgViewsExclude": [],
|
|
521
|
+
"pgViewsOutput": "frg-views-diff.sql",
|
|
482
522
|
"ignoreColumns": ["created_at", "updated_at"],
|
|
483
523
|
"includeDeletes": true,
|
|
484
524
|
"skipMissingPk": false,
|
|
@@ -546,7 +586,7 @@ npx frg-data-diff apply --execute --apply-deletes
|
|
|
546
586
|
- Schema diff (table creation, column changes, index changes) — use a dedicated schema migration tool.
|
|
547
587
|
- Cross-schema comparisons within a single call (one schema per run).
|
|
548
588
|
- Tables without primary keys (use `--skip-missing-pk` to skip them).
|
|
549
|
-
-
|
|
589
|
+
- Foreign tables.
|
|
550
590
|
- Streaming of very large tables — v1 loads each table into memory. For huge tables, process in smaller table batches.
|
|
551
591
|
- PostgreSQL pseudo-types and internal-only types as table columns.
|
|
552
592
|
- Multiple databases in a single run — run the tool once per database pair.
|
|
@@ -617,6 +657,7 @@ frg-data-diff sql --help
|
|
|
617
657
|
4. **No schema migration**: This tool does not create tables, add columns, or change indexes.
|
|
618
658
|
5. **Single schema per run**: All tables must be in the same schema.
|
|
619
659
|
6. **Env var references use shell-style names**: `$ENV_VAR`, `$envVar`, and `$env_var` are all valid.
|
|
660
|
+
7. **View SQL scope**: View diffs compare definitions from PostgreSQL catalog metadata. Ownership, grants, comments, and materialized-view indexes are not recreated.
|
|
620
661
|
|
|
621
662
|
---
|
|
622
663
|
|
package/dist/cli/generator.js
CHANGED
|
@@ -49,6 +49,7 @@ const resolve_options_1 = require("../config/resolve-options");
|
|
|
49
49
|
const write_config_1 = require("../config/write-config");
|
|
50
50
|
const connection_1 = require("../db/connection");
|
|
51
51
|
const metadata_1 = require("../db/metadata");
|
|
52
|
+
const pg_views_1 = require("../db/pg-views");
|
|
52
53
|
const generate_diff_1 = require("../diff/generate-diff");
|
|
53
54
|
const write_diff_yaml_1 = require("../diff/write-diff-yaml");
|
|
54
55
|
const prompts_1 = require("../shared/prompts");
|
|
@@ -82,15 +83,20 @@ program
|
|
|
82
83
|
.option("--schema-diff-exclude-table <table...>", "Table(s) to exclude from schema diff")
|
|
83
84
|
.option("--pg-triggers-table <table...>", "Table(s) to include for PostgreSQL triggers diff")
|
|
84
85
|
.option("--pg-triggers-exclude-table <table...>", "Table(s) to exclude from PostgreSQL triggers diff")
|
|
86
|
+
.option("--pg-view <view...>", "View(s) to include for PostgreSQL views diff")
|
|
87
|
+
.option("--pg-view-exclude <view...>", "View(s) to exclude from PostgreSQL views diff")
|
|
85
88
|
.option("--ignore-column <column...>", "Column(s) to ignore during comparison")
|
|
86
89
|
.option("--include-deletes", "Include deletes in the diff (rows in dest not in source)")
|
|
87
90
|
.option("--skip-missing-pk", "Skip tables that have no primary key instead of failing")
|
|
88
91
|
.option("--output <file>", "Output diff file path")
|
|
89
92
|
.option("--schema-diff-output <file>", "Output schema diff file path")
|
|
90
93
|
.option("--pg-triggers-output <file>", "Output PostgreSQL triggers diff file path")
|
|
94
|
+
.option("--pg-views-output <file>", "Output PostgreSQL views diff file path")
|
|
91
95
|
.option("--pretty", "Pretty-print the output JSON")
|
|
92
96
|
.option("--generate-pg-triggers", "Generate a PostgreSQL triggers and functions diff")
|
|
93
97
|
.option("--no-generate-pg-triggers", "Do not generate a PostgreSQL triggers and functions diff")
|
|
98
|
+
.option("--generate-pg-views", "Generate a PostgreSQL views diff")
|
|
99
|
+
.option("--no-generate-pg-views", "Do not generate a PostgreSQL views diff")
|
|
94
100
|
.option("--verbose", "Enable verbose logging")
|
|
95
101
|
.option("--config <file>", "Path to config file", load_config_1.DEFAULT_CONFIG_FILENAME)
|
|
96
102
|
.option("--wizard <value>", "Force the interactive wizard (use true or 1)")
|
|
@@ -136,14 +142,18 @@ async function main() {
|
|
|
136
142
|
schemaDiffExcludeTables: opts["schemaDiffExcludeTable"],
|
|
137
143
|
pgTriggersTables: opts["pgTriggersTable"],
|
|
138
144
|
pgTriggersExcludeTables: opts["pgTriggersExcludeTable"],
|
|
145
|
+
pgViews: opts["pgView"],
|
|
146
|
+
pgViewsExclude: opts["pgViewExclude"],
|
|
139
147
|
ignoreColumns: opts["ignoreColumn"],
|
|
140
148
|
includeDeletes: opts["includeDeletes"] ? true : undefined,
|
|
141
149
|
skipMissingPk: opts["skipMissingPk"] ? true : undefined,
|
|
142
150
|
output: opts["output"],
|
|
143
151
|
schemaDiffOutput: opts["schemaDiffOutput"],
|
|
144
152
|
pgTriggersOutput: opts["pgTriggersOutput"],
|
|
153
|
+
pgViewsOutput: opts["pgViewsOutput"],
|
|
145
154
|
pretty: opts["pretty"] ? true : undefined,
|
|
146
155
|
generatePgTriggers: normalizeOptionalBoolean(opts["generatePgTriggers"]),
|
|
156
|
+
generatePgViews: normalizeOptionalBoolean(opts["generatePgViews"]),
|
|
147
157
|
verbose: opts["verbose"] ? true : undefined,
|
|
148
158
|
};
|
|
149
159
|
// Remove undefined values
|
|
@@ -173,6 +183,14 @@ async function main() {
|
|
|
173
183
|
const requestedPgTriggersExcludeTables = cleanCliArgs.pgTriggersExcludeTables === null
|
|
174
184
|
? null
|
|
175
185
|
: [...resolved.pgTriggersExcludeTables];
|
|
186
|
+
const requestedPgViews = [...resolved.pgViews];
|
|
187
|
+
let requestedPgViewsExclude;
|
|
188
|
+
if (cleanCliArgs.pgViewsExclude === null) {
|
|
189
|
+
requestedPgViewsExclude = null;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
requestedPgViewsExclude = [...resolved.pgViewsExclude];
|
|
193
|
+
}
|
|
176
194
|
const requestedIgnoreColumns = cleanCliArgs.ignoreColumns === null ? null : [...resolved.ignoreColumns];
|
|
177
195
|
const runtimeBaseResolved = (0, resolve_options_1.resolveRuntimeGeneratorOptions)({
|
|
178
196
|
...resolved,
|
|
@@ -182,6 +200,8 @@ async function main() {
|
|
|
182
200
|
schemaDiffExcludeTables: resolved.schemaDiffExcludeTables,
|
|
183
201
|
pgTriggersTables: requestedPgTriggersTables,
|
|
184
202
|
pgTriggersExcludeTables: resolved.pgTriggersExcludeTables,
|
|
203
|
+
pgViews: requestedPgViews,
|
|
204
|
+
pgViewsExclude: resolved.pgViewsExclude,
|
|
185
205
|
ignoreColumns: resolved.ignoreColumns,
|
|
186
206
|
});
|
|
187
207
|
// Validate required values
|
|
@@ -215,6 +235,8 @@ async function main() {
|
|
|
215
235
|
schemaDiffExcludeTables: requestedSchemaDiffExcludeTables,
|
|
216
236
|
pgTriggersTables: requestedPgTriggersTables,
|
|
217
237
|
pgTriggersExcludeTables: requestedPgTriggersExcludeTables,
|
|
238
|
+
pgViews: requestedPgViews,
|
|
239
|
+
pgViewsExclude: requestedPgViewsExclude,
|
|
218
240
|
ignoreColumns: requestedIgnoreColumns,
|
|
219
241
|
}, (0, resolve_options_1.resolveApplyOptions)(loadedConfig?.apply, {
|
|
220
242
|
destPgHost: resolved.destPgHost,
|
|
@@ -228,6 +250,16 @@ async function main() {
|
|
|
228
250
|
if (configExists) {
|
|
229
251
|
const shouldUpdate = await (0, prompts_1.confirmUpdateConfig)();
|
|
230
252
|
if (shouldUpdate) {
|
|
253
|
+
const date = new Date();
|
|
254
|
+
const yyyy = date.getFullYear();
|
|
255
|
+
const mm = String(date.getMonth() + 1).padStart(2, "0");
|
|
256
|
+
const dd = String(date.getDate()).padStart(2, "0");
|
|
257
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
258
|
+
const min = String(date.getMinutes()).padStart(2, "0");
|
|
259
|
+
const ss = String(date.getSeconds()).padStart(2, "0");
|
|
260
|
+
const backupPath = `${configFilePath}~${yyyy}-${mm}-${dd}-${hh}${min}${ss}`;
|
|
261
|
+
fs.copyFileSync(configFilePath, backupPath);
|
|
262
|
+
console.log(`Backup of previous config saved to: ${backupPath}`);
|
|
231
263
|
(0, write_config_1.writeConfig)(configFilePath, configToWrite);
|
|
232
264
|
configWritten = true;
|
|
233
265
|
configUpdatedThisRun = true;
|
|
@@ -304,7 +336,8 @@ async function main() {
|
|
|
304
336
|
const expandedTables = resolvedTablePatterns.data;
|
|
305
337
|
const expandedSchemaDiffTables = resolvedTablePatterns.schema;
|
|
306
338
|
const expandedPgTriggersTables = resolvedTablePatterns.pgTriggers;
|
|
307
|
-
|
|
339
|
+
const expandedPgViews = resolvedTablePatterns.pgViews;
|
|
340
|
+
console.log(`Resolved ${expandedTables.tables.length} data table(s), ${expandedSchemaDiffTables.tables.length} schema table(s), ${expandedPgTriggersTables.tables.length} PostgreSQL trigger table(s), and ${expandedPgViews.views.length} PostgreSQL view(s).`);
|
|
308
341
|
const runtimeResolved = {
|
|
309
342
|
...runtimeBaseResolved,
|
|
310
343
|
tables: expandedTables.tables,
|
|
@@ -313,6 +346,8 @@ async function main() {
|
|
|
313
346
|
schemaDiffExcludeTables: expandedSchemaDiffTables.excludedTables,
|
|
314
347
|
pgTriggersTables: expandedPgTriggersTables.tables,
|
|
315
348
|
pgTriggersExcludeTables: expandedPgTriggersTables.excludedTables,
|
|
349
|
+
pgViews: expandedPgViews.views,
|
|
350
|
+
pgViewsExclude: expandedPgViews.excludedViews,
|
|
316
351
|
};
|
|
317
352
|
const logProgress = (message) => {
|
|
318
353
|
console.log(message);
|
|
@@ -323,9 +358,9 @@ async function main() {
|
|
|
323
358
|
}
|
|
324
359
|
: undefined;
|
|
325
360
|
// Print resolved plan
|
|
326
|
-
printResolvedPlan(resolved, runtimeResolved.tables, runtimeResolved.excludeTables, runtimeResolved.schemaDiffTables, runtimeResolved.schemaDiffExcludeTables, runtimeResolved.pgTriggersTables, runtimeResolved.pgTriggersExcludeTables, sourceConnection, destConnection);
|
|
361
|
+
printResolvedPlan(resolved, runtimeResolved.tables, runtimeResolved.excludeTables, runtimeResolved.schemaDiffTables, runtimeResolved.schemaDiffExcludeTables, runtimeResolved.pgTriggersTables, runtimeResolved.pgTriggersExcludeTables, runtimeResolved.pgViews, runtimeResolved.pgViewsExclude, sourceConnection, destConnection);
|
|
327
362
|
console.log("Connecting to databases...");
|
|
328
|
-
console.log(`Comparing ${runtimeResolved.tables.length} data table(s), ${runtimeResolved.schemaDiffTables.length} schema table(s),
|
|
363
|
+
console.log(`Comparing ${runtimeResolved.tables.length} data table(s), ${runtimeResolved.schemaDiffTables.length} schema table(s), ${runtimeResolved.pgTriggersTables.length} PostgreSQL trigger table(s), and ${runtimeResolved.pgViews.length} PostgreSQL view(s)...`);
|
|
329
364
|
console.log("Starting data and schema diff generation...");
|
|
330
365
|
const [diff, schemaDiff] = await Promise.all([
|
|
331
366
|
(0, generate_diff_1.generateDiff)(sourcePool, destPool, {
|
|
@@ -356,6 +391,7 @@ async function main() {
|
|
|
356
391
|
const schemaDiffYamlOutputPath = path.resolve((0, write_diff_yaml_1.buildYamlOutputPath)(runtimeResolved.schemaDiffOutput));
|
|
357
392
|
const schemaDiffSqlOutputPath = path.resolve((0, generate_schema_sql_1.buildSchemaSqlOutputPath)(runtimeResolved.schemaDiffOutput));
|
|
358
393
|
const pgTriggersOutputPath = path.resolve(runtimeResolved.pgTriggersOutput);
|
|
394
|
+
const pgViewsOutputPath = path.resolve(runtimeResolved.pgViewsOutput);
|
|
359
395
|
console.log("Writing JSON and YAML diff artifacts...");
|
|
360
396
|
const dataContent = runtimeResolved.pretty
|
|
361
397
|
? JSON.stringify(diff, null, 2) + "\n"
|
|
@@ -376,6 +412,7 @@ async function main() {
|
|
|
376
412
|
fs.writeFileSync(schemaDiffSqlOutputPath, schemaSqlResult.sql, "utf-8");
|
|
377
413
|
let sqlGenerated = false;
|
|
378
414
|
let pgTriggersSqlGenerated = false;
|
|
415
|
+
let pgViewsSqlGenerated = false;
|
|
379
416
|
console.log("\nData diff summary:");
|
|
380
417
|
console.log(` Tables compared: ${diff.summary.tablesCompared}`);
|
|
381
418
|
console.log(` Inserts: ${diff.summary.inserts}`);
|
|
@@ -471,6 +508,72 @@ async function main() {
|
|
|
471
508
|
pgTriggersSqlGenerated = true;
|
|
472
509
|
}
|
|
473
510
|
}
|
|
511
|
+
let shouldGeneratePgViews = false;
|
|
512
|
+
if (runtimeResolved.generatePgViews !== undefined) {
|
|
513
|
+
shouldGeneratePgViews = runtimeResolved.generatePgViews;
|
|
514
|
+
}
|
|
515
|
+
else if (shouldAskInteractiveQuestion(opts["yes"])) {
|
|
516
|
+
shouldGeneratePgViews = await (0, prompts_1.confirmProceed)("\nGenerate a PostgreSQL views diff? (SQL script) [yes]: ", true);
|
|
517
|
+
}
|
|
518
|
+
if (shouldGeneratePgViews) {
|
|
519
|
+
console.log("\nGenerating PostgreSQL views diff...");
|
|
520
|
+
const pgViewsArgs = [];
|
|
521
|
+
if (configWritten) {
|
|
522
|
+
pgViewsArgs.push("--config", path.relative(process.cwd(), configFilePath) ||
|
|
523
|
+
load_config_1.DEFAULT_CONFIG_FILENAME);
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
// Pass all resolved args down manually if no config is available.
|
|
527
|
+
// This is a rare edge case, usually we write the config.
|
|
528
|
+
pgViewsArgs.push("--source-pg-host", resolved.sourcePgHost);
|
|
529
|
+
pgViewsArgs.push("--source-pg-port", String(resolved.sourcePgPort));
|
|
530
|
+
pgViewsArgs.push("--source-pg-database", resolved.sourcePgDatabase);
|
|
531
|
+
pgViewsArgs.push("--source-pg-user", resolved.sourcePgUser);
|
|
532
|
+
if ((0, env_values_1.isEnvReference)(resolved.sourcePgPassword)) {
|
|
533
|
+
pgViewsArgs.push("--source-pg-password-env", resolved.sourcePgPassword);
|
|
534
|
+
}
|
|
535
|
+
if (resolved.sourcePgSsl) {
|
|
536
|
+
pgViewsArgs.push("--source-pg-ssl");
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
pgViewsArgs.push("--no-source-pg-ssl");
|
|
540
|
+
}
|
|
541
|
+
pgViewsArgs.push("--dest-pg-host", resolved.destPgHost);
|
|
542
|
+
pgViewsArgs.push("--dest-pg-port", String(resolved.destPgPort));
|
|
543
|
+
pgViewsArgs.push("--dest-pg-database", resolved.destPgDatabase);
|
|
544
|
+
pgViewsArgs.push("--dest-pg-user", resolved.destPgUser);
|
|
545
|
+
if ((0, env_values_1.isEnvReference)(resolved.destPgPassword)) {
|
|
546
|
+
pgViewsArgs.push("--dest-pg-password-env", resolved.destPgPassword);
|
|
547
|
+
}
|
|
548
|
+
if (resolved.destPgSsl) {
|
|
549
|
+
pgViewsArgs.push("--dest-pg-ssl");
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
pgViewsArgs.push("--no-dest-pg-ssl");
|
|
553
|
+
}
|
|
554
|
+
pgViewsArgs.push("--schema", resolved.schema);
|
|
555
|
+
for (const viewName of runtimeResolved.pgViews) {
|
|
556
|
+
pgViewsArgs.push("--view", viewName);
|
|
557
|
+
}
|
|
558
|
+
for (const viewName of runtimeResolved.pgViewsExclude) {
|
|
559
|
+
pgViewsArgs.push("--exclude-view", viewName);
|
|
560
|
+
}
|
|
561
|
+
pgViewsArgs.push("--output", runtimeResolved.pgViewsOutput);
|
|
562
|
+
}
|
|
563
|
+
if (runtimeResolved.verbose) {
|
|
564
|
+
pgViewsArgs.push("--verbose");
|
|
565
|
+
}
|
|
566
|
+
const pgViewsCommandPath = path.join(__dirname, "pg-views.js");
|
|
567
|
+
const res = (0, child_process_1.spawnSync)(process.execPath, [pgViewsCommandPath, ...pgViewsArgs], {
|
|
568
|
+
stdio: "inherit",
|
|
569
|
+
});
|
|
570
|
+
if (res.status !== 0) {
|
|
571
|
+
console.error("Warning: pg-views diff generation failed.");
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
pgViewsSqlGenerated = true;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
474
577
|
console.log("\nReview the data diff and schema SQL carefully before applying anything.");
|
|
475
578
|
if (!sqlGenerated) {
|
|
476
579
|
console.log("\nGenerate SQL Diff:");
|
|
@@ -490,6 +593,9 @@ async function main() {
|
|
|
490
593
|
if (pgTriggersSqlGenerated) {
|
|
491
594
|
console.log(`PostgreSQL triggers SQL written to: ${pgTriggersOutputPath}`);
|
|
492
595
|
}
|
|
596
|
+
if (pgViewsSqlGenerated) {
|
|
597
|
+
console.log(`PostgreSQL views SQL written to: ${pgViewsOutputPath}`);
|
|
598
|
+
}
|
|
493
599
|
console.log("");
|
|
494
600
|
}
|
|
495
601
|
finally {
|
|
@@ -569,10 +675,13 @@ async function resolveGeneratorTablePatterns(sourcePool, destPool, resolved, log
|
|
|
569
675
|
destClient = await runLoggedAsyncStep("connecting to destination database for table resolution", () => destPool.connect(), logProgress);
|
|
570
676
|
const sourceTables = await listTablesWithProgress(sourceClient, resolved.schema, "source", logProgress);
|
|
571
677
|
const destTables = await listTablesWithProgress(destClient, resolved.schema, "destination", logProgress);
|
|
678
|
+
const sourceViews = await listPgViewsWithProgress(sourceClient, resolved.schema, "source", logProgress);
|
|
679
|
+
const destViews = await listPgViewsWithProgress(destClient, resolved.schema, "destination", logProgress);
|
|
572
680
|
const data = resolveTablePatternGroup("data", sourceTables, destTables, resolved.tables, resolved.excludeTables, "common", logProgress);
|
|
573
681
|
const schema = resolveTablePatternGroup("schema diff", sourceTables, destTables, resolved.schemaDiffTables, resolved.schemaDiffExcludeTables, "either", logProgress);
|
|
574
682
|
const pgTriggers = resolveTablePatternGroup("PostgreSQL trigger", sourceTables, destTables, resolved.pgTriggersTables, resolved.pgTriggersExcludeTables, "common", logProgress);
|
|
575
|
-
|
|
683
|
+
const pgViews = resolveViewPatternGroup("PostgreSQL view", sourceViews, destViews, resolved.pgViews, resolved.pgViewsExclude, logProgress);
|
|
684
|
+
return { data, schema, pgTriggers, pgViews };
|
|
576
685
|
}
|
|
577
686
|
finally {
|
|
578
687
|
if (destClient !== undefined) {
|
|
@@ -591,6 +700,12 @@ async function listTablesWithProgress(client, schema, databaseLabel, logProgress
|
|
|
591
700
|
logProgress(`[table resolution] ${databaseLabel} table preview: ${formatStringList(tables)}`);
|
|
592
701
|
return tables;
|
|
593
702
|
}
|
|
703
|
+
async function listPgViewsWithProgress(client, schema, databaseLabel, logProgress) {
|
|
704
|
+
const views = await runLoggedAsyncStep(`scanning ${databaseLabel} views in schema "${schema}"`, () => (0, pg_views_1.listPgViews)(client, schema), logProgress);
|
|
705
|
+
logProgress(`[view resolution] ${databaseLabel} database returned ${views.length} view(s).`);
|
|
706
|
+
logProgress(`[view resolution] ${databaseLabel} view preview: ${formatStringList(views)}`);
|
|
707
|
+
return views;
|
|
708
|
+
}
|
|
594
709
|
function resolveTablePatternGroup(label, sourceTables, destTables, includePatterns, excludePatterns, availability, logProgress) {
|
|
595
710
|
const startedAt = Date.now();
|
|
596
711
|
logProgress(`[table resolution] resolving ${label} patterns against ${formatAvailability(availability)}.`);
|
|
@@ -616,6 +731,25 @@ function resolveTablePatternGroup(label, sourceTables, destTables, includePatter
|
|
|
616
731
|
throw error;
|
|
617
732
|
}
|
|
618
733
|
}
|
|
734
|
+
function resolveViewPatternGroup(label, sourceViews, destViews, includePatterns, excludePatterns, logProgress) {
|
|
735
|
+
const startedAt = Date.now();
|
|
736
|
+
logProgress(`[view resolution] resolving ${label} patterns.`);
|
|
737
|
+
logProgress(`[view resolution] ${label} include patterns: ${formatStringList(includePatterns)}`);
|
|
738
|
+
logProgress(`[view resolution] ${label} exclude patterns: ${formatStringList(excludePatterns)}`);
|
|
739
|
+
try {
|
|
740
|
+
const result = (0, pg_views_1.resolvePgViewPatternsFromViewLists)(sourceViews, destViews, includePatterns, excludePatterns);
|
|
741
|
+
logProgress(`[view resolution] resolved ${label} patterns in ${formatDuration(Date.now() - startedAt)}.`);
|
|
742
|
+
logProgress(`[view resolution] ${label} views: ${formatStringList(result.views)}`);
|
|
743
|
+
if (result.excludedViews.length > 0) {
|
|
744
|
+
logProgress(`[view resolution] ${label} excluded views: ${formatStringList(result.excludedViews)}`);
|
|
745
|
+
}
|
|
746
|
+
return result;
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
console.error(`[view resolution] failed to resolve ${label} patterns after ${formatDuration(Date.now() - startedAt)}.`);
|
|
750
|
+
throw error;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
619
753
|
async function runLoggedAsyncStep(label, action, logProgress) {
|
|
620
754
|
const startedAt = Date.now();
|
|
621
755
|
logProgress(`[table resolution] ${label}...`);
|
|
@@ -676,7 +810,7 @@ function shellEscapeArg(value) {
|
|
|
676
810
|
}
|
|
677
811
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
678
812
|
}
|
|
679
|
-
function printResolvedPlan(resolved, expandedTables, expandedExcludeTables, expandedSchemaDiffTables, expandedSchemaDiffExcludeTables, expandedPgTriggersTables, expandedPgTriggersExcludeTables, sourceConnection, destConnection) {
|
|
813
|
+
function printResolvedPlan(resolved, expandedTables, expandedExcludeTables, expandedSchemaDiffTables, expandedSchemaDiffExcludeTables, expandedPgTriggersTables, expandedPgTriggersExcludeTables, expandedPgViews, expandedPgViewsExclude, sourceConnection, destConnection) {
|
|
680
814
|
console.log("\ntool:");
|
|
681
815
|
console.log(" frg-data-diff generate");
|
|
682
816
|
console.log("\nsource:");
|
|
@@ -741,10 +875,22 @@ function printResolvedPlan(resolved, expandedTables, expandedExcludeTables, expa
|
|
|
741
875
|
console.log("expanded pg triggers exclude tables: " +
|
|
742
876
|
expandedPgTriggersExcludeTables.join(", "));
|
|
743
877
|
}
|
|
878
|
+
console.log("pg views output: " + resolved.pgViewsOutput);
|
|
879
|
+
console.log("pg views: " + resolved.pgViews.join(", "));
|
|
880
|
+
if (expandedPgViews.join(",") !== resolved.pgViews.join(",")) {
|
|
881
|
+
console.log("expanded pg views: " + expandedPgViews.join(", "));
|
|
882
|
+
}
|
|
883
|
+
if (resolved.pgViewsExclude.length > 0) {
|
|
884
|
+
console.log("pg views exclude: " + resolved.pgViewsExclude.join(", "));
|
|
885
|
+
}
|
|
886
|
+
if (expandedPgViewsExclude.join(",") !== resolved.pgViewsExclude.join(",")) {
|
|
887
|
+
console.log("expanded pg views exclude: " + expandedPgViewsExclude.join(", "));
|
|
888
|
+
}
|
|
744
889
|
console.log("include deletes: " + resolved.includeDeletes);
|
|
745
890
|
console.log("pretty: " + resolved.pretty);
|
|
746
891
|
console.log("generate sql: " + (resolved.generateSql ?? "interactive"));
|
|
747
892
|
console.log("generate pg triggers: " + (resolved.generatePgTriggers ?? "interactive"));
|
|
893
|
+
console.log("generate pg views: " + (resolved.generatePgViews ?? "interactive"));
|
|
748
894
|
}
|
|
749
895
|
function hasAnyGeneratorArgs(argv) {
|
|
750
896
|
const argKeys = [
|
|
@@ -770,14 +916,19 @@ function hasAnyGeneratorArgs(argv) {
|
|
|
770
916
|
"--schema-diff-exclude-table",
|
|
771
917
|
"--pg-triggers-table",
|
|
772
918
|
"--pg-triggers-exclude-table",
|
|
919
|
+
"--pg-view",
|
|
920
|
+
"--pg-view-exclude",
|
|
773
921
|
"--include-deletes",
|
|
774
922
|
"--skip-missing-pk",
|
|
775
923
|
"--output",
|
|
776
924
|
"--schema-diff-output",
|
|
777
925
|
"--pg-triggers-output",
|
|
926
|
+
"--pg-views-output",
|
|
778
927
|
"--pretty",
|
|
779
928
|
"--generate-pg-triggers",
|
|
780
929
|
"--no-generate-pg-triggers",
|
|
930
|
+
"--generate-pg-views",
|
|
931
|
+
"--no-generate-pg-views",
|
|
781
932
|
"--verbose",
|
|
782
933
|
"--config",
|
|
783
934
|
"--wizard",
|
|
@@ -0,0 +1,195 @@
|
|
|
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 fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const commander_1 = require("commander");
|
|
39
|
+
const load_config_1 = require("../config/load-config");
|
|
40
|
+
const resolve_options_1 = require("../config/resolve-options");
|
|
41
|
+
const connection_1 = require("../db/connection");
|
|
42
|
+
const pg_views_diff_1 = require("../diff/pg-views-diff");
|
|
43
|
+
const program = new commander_1.Command();
|
|
44
|
+
program
|
|
45
|
+
.name("frg-data-diff pg-views")
|
|
46
|
+
.description("Compare PostgreSQL view definitions and write a SQL diff script.")
|
|
47
|
+
.option("--source-pg-host <host>", "Source database host")
|
|
48
|
+
.option("--source-pg-port <port>", "Source database port", (value) => parseInt(value, 10))
|
|
49
|
+
.option("--source-pg-database <db>", "Source database name")
|
|
50
|
+
.option("--source-pg-user <user>", "Source database user")
|
|
51
|
+
.option("--source-pg-password-env <value>", "Source DB password or $ENV_VAR reference")
|
|
52
|
+
.option("--source-pg-ssl", "Use SSL for source database connection")
|
|
53
|
+
.option("--no-source-pg-ssl", "Do not use SSL for source database connection")
|
|
54
|
+
.option("--dest-pg-host <host>", "Destination database host")
|
|
55
|
+
.option("--dest-pg-port <port>", "Destination database port", (value) => parseInt(value, 10))
|
|
56
|
+
.option("--dest-pg-database <db>", "Destination database name")
|
|
57
|
+
.option("--dest-pg-user <user>", "Destination database user")
|
|
58
|
+
.option("--dest-pg-password-env <value>", "Destination DB password or $ENV_VAR reference")
|
|
59
|
+
.option("--dest-pg-ssl", "Use SSL for destination database connection")
|
|
60
|
+
.option("--no-dest-pg-ssl", "Do not use SSL for destination database connection")
|
|
61
|
+
.option("--schema <schema>", "PostgreSQL schema to compare")
|
|
62
|
+
.option("--view <view...>", "View(s) to include")
|
|
63
|
+
.option("--exclude-view <view...>", "View(s) to exclude")
|
|
64
|
+
.option("--output <file>", "Output diff file path", "frg-views-diff.sql")
|
|
65
|
+
.option("--verbose", "Enable verbose logging")
|
|
66
|
+
.option("--config <file>", "Path to config file", load_config_1.DEFAULT_CONFIG_FILENAME);
|
|
67
|
+
program.parse(process.argv);
|
|
68
|
+
const opts = program.opts();
|
|
69
|
+
function normalizeOptionalBoolean(value) {
|
|
70
|
+
if (value === true) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (value === false) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
async function main() {
|
|
79
|
+
const configFilePath = path.resolve(opts["config"] || load_config_1.DEFAULT_CONFIG_FILENAME);
|
|
80
|
+
const configExists = fs.existsSync(configFilePath);
|
|
81
|
+
let generatorConfig = undefined;
|
|
82
|
+
if (configExists) {
|
|
83
|
+
const loadedConfig = (0, load_config_1.loadConfig)(configFilePath);
|
|
84
|
+
generatorConfig = loadedConfig.generator;
|
|
85
|
+
}
|
|
86
|
+
let verbose;
|
|
87
|
+
if (opts["verbose"]) {
|
|
88
|
+
verbose = true;
|
|
89
|
+
}
|
|
90
|
+
const cliArgs = {
|
|
91
|
+
sourcePgHost: opts["sourcePgHost"],
|
|
92
|
+
sourcePgPort: opts["sourcePgPort"],
|
|
93
|
+
sourcePgDatabase: opts["sourcePgDatabase"],
|
|
94
|
+
sourcePgUser: opts["sourcePgUser"],
|
|
95
|
+
sourcePgPassword: opts["sourcePgPasswordEnv"],
|
|
96
|
+
sourcePgSsl: normalizeOptionalBoolean(opts["sourcePgSsl"]),
|
|
97
|
+
destPgHost: opts["destPgHost"],
|
|
98
|
+
destPgPort: opts["destPgPort"],
|
|
99
|
+
destPgDatabase: opts["destPgDatabase"],
|
|
100
|
+
destPgUser: opts["destPgUser"],
|
|
101
|
+
destPgPassword: opts["destPgPasswordEnv"],
|
|
102
|
+
destPgSsl: normalizeOptionalBoolean(opts["destPgSsl"]),
|
|
103
|
+
schema: opts["schema"],
|
|
104
|
+
pgViews: opts["view"],
|
|
105
|
+
pgViewsExclude: opts["excludeView"],
|
|
106
|
+
pgViewsOutput: opts["output"],
|
|
107
|
+
verbose,
|
|
108
|
+
};
|
|
109
|
+
const cleanCliArgs = Object.fromEntries(Object.entries(cliArgs).filter(([, value]) => value !== undefined));
|
|
110
|
+
const resolved = (0, resolve_options_1.resolveGeneratorOptions)(generatorConfig, cleanCliArgs);
|
|
111
|
+
const runtimeResolved = (0, resolve_options_1.resolveRuntimeGeneratorOptions)({
|
|
112
|
+
...resolved,
|
|
113
|
+
tables: [...resolved.tables],
|
|
114
|
+
excludeTables: [...resolved.excludeTables],
|
|
115
|
+
schemaDiffTables: [...resolved.schemaDiffTables],
|
|
116
|
+
schemaDiffExcludeTables: [...resolved.schemaDiffExcludeTables],
|
|
117
|
+
pgTriggersTables: [...resolved.pgTriggersTables],
|
|
118
|
+
pgTriggersExcludeTables: [...resolved.pgTriggersExcludeTables],
|
|
119
|
+
pgViews: [...resolved.pgViews],
|
|
120
|
+
pgViewsExclude: [...resolved.pgViewsExclude],
|
|
121
|
+
ignoreColumns: [...resolved.ignoreColumns],
|
|
122
|
+
});
|
|
123
|
+
console.log("frg-data-diff: generate pg-views");
|
|
124
|
+
if (!resolved.sourcePgHost || !resolved.destPgHost) {
|
|
125
|
+
console.error("Missing generator configuration. Please run with full arguments or define config.");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const sourceConnection = (0, connection_1.resolveConnectionParams)({
|
|
129
|
+
host: resolved.sourcePgHost,
|
|
130
|
+
port: resolved.sourcePgPort,
|
|
131
|
+
database: resolved.sourcePgDatabase,
|
|
132
|
+
user: resolved.sourcePgUser,
|
|
133
|
+
password: resolved.sourcePgPassword,
|
|
134
|
+
ssl: runtimeResolved.sourcePgSsl,
|
|
135
|
+
}, {
|
|
136
|
+
host: "source host",
|
|
137
|
+
port: "source port",
|
|
138
|
+
database: "source database",
|
|
139
|
+
user: "source user",
|
|
140
|
+
password: "source password",
|
|
141
|
+
});
|
|
142
|
+
const destConnection = (0, connection_1.resolveConnectionParams)({
|
|
143
|
+
host: resolved.destPgHost,
|
|
144
|
+
port: resolved.destPgPort,
|
|
145
|
+
database: resolved.destPgDatabase,
|
|
146
|
+
user: resolved.destPgUser,
|
|
147
|
+
password: resolved.destPgPassword,
|
|
148
|
+
ssl: runtimeResolved.destPgSsl,
|
|
149
|
+
}, {
|
|
150
|
+
host: "dest host",
|
|
151
|
+
port: "dest port",
|
|
152
|
+
database: "dest database",
|
|
153
|
+
user: "dest user",
|
|
154
|
+
password: "dest password",
|
|
155
|
+
});
|
|
156
|
+
const sourcePool = (0, connection_1.createPool)(sourceConnection);
|
|
157
|
+
const destPool = (0, connection_1.createPool)(destConnection);
|
|
158
|
+
try {
|
|
159
|
+
console.log("Preparing pg-views diff...");
|
|
160
|
+
let onVerboseProgress;
|
|
161
|
+
if (runtimeResolved.verbose) {
|
|
162
|
+
onVerboseProgress = (message) => {
|
|
163
|
+
console.log(message);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const diffOptions = {
|
|
167
|
+
schema: runtimeResolved.schema,
|
|
168
|
+
views: runtimeResolved.pgViews,
|
|
169
|
+
excludeViews: runtimeResolved.pgViewsExclude,
|
|
170
|
+
verbose: runtimeResolved.verbose,
|
|
171
|
+
onProgress: (message) => {
|
|
172
|
+
console.log(message);
|
|
173
|
+
},
|
|
174
|
+
onVerboseProgress,
|
|
175
|
+
};
|
|
176
|
+
const sql = await (0, pg_views_diff_1.generatePgViewsDiffSql)(sourcePool, destPool, diffOptions);
|
|
177
|
+
const output = runtimeResolved.pgViewsOutput;
|
|
178
|
+
fs.writeFileSync(output, sql, "utf-8");
|
|
179
|
+
console.log(`Wrote views diff SQL to ${output}`);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
console.error("Failed to generate pg-views diff.");
|
|
183
|
+
console.error(error.message);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
await sourcePool.end();
|
|
188
|
+
await destPool.end();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
main().catch((err) => {
|
|
192
|
+
console.error("Unhandled error:", err);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
});
|
|
195
|
+
//# sourceMappingURL=pg-views.js.map
|