@supabase/pg-delta 1.0.0-alpha.25 → 1.0.0-alpha.26
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/dist/core/catalog.model.js +2 -0
- package/dist/core/expand-replace-dependencies.js +1 -7
- package/dist/core/objects/table/table.diff.js +53 -30
- package/dist/core/plan/hierarchy.js +4 -4
- package/dist/core/postgres-config.d.ts +7 -0
- package/dist/core/postgres-config.js +19 -5
- package/dist/core/sort/debug-visualization.js +1 -1
- package/dist/core/sort/topological-sort.js +2 -2
- package/package.json +34 -33
- package/src/core/catalog.model.ts +4 -3
- package/src/core/catalog.snapshot.test.ts +1 -0
- package/src/core/expand-replace-dependencies.test.ts +12 -0
- package/src/core/expand-replace-dependencies.ts +1 -12
- package/src/core/objects/aggregate/changes/aggregate.base.ts +1 -1
- package/src/core/objects/collation/changes/collation.base.ts +1 -1
- package/src/core/objects/domain/changes/domain.base.ts +1 -1
- package/src/core/objects/extension/changes/extension.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +1 -1
- package/src/core/objects/index/changes/index.base.ts +1 -1
- package/src/core/objects/language/changes/language.base.ts +1 -1
- package/src/core/objects/materialized-view/changes/materialized-view.base.ts +1 -1
- package/src/core/objects/procedure/changes/procedure.base.ts +1 -1
- package/src/core/objects/rls-policy/changes/rls-policy.base.ts +1 -1
- package/src/core/objects/role/changes/role.base.ts +1 -1
- package/src/core/objects/schema/changes/schema.base.ts +1 -1
- package/src/core/objects/sequence/changes/sequence.base.ts +1 -1
- package/src/core/objects/table/changes/table.base.ts +1 -1
- package/src/core/objects/table/changes/table.comment.ts +2 -8
- package/src/core/objects/table/table.diff.test.ts +198 -5
- package/src/core/objects/table/table.diff.ts +63 -34
- package/src/core/objects/trigger/changes/trigger.alter.ts +1 -4
- package/src/core/objects/trigger/changes/trigger.base.ts +1 -1
- package/src/core/objects/type/composite-type/changes/composite-type.base.ts +1 -1
- package/src/core/objects/type/enum/changes/enum.base.ts +1 -1
- package/src/core/objects/type/range/changes/range.base.ts +1 -1
- package/src/core/objects/view/changes/view.base.ts +1 -1
- package/src/core/plan/hierarchy.ts +4 -4
- package/src/core/postgres-config.test.ts +39 -1
- package/src/core/postgres-config.ts +32 -16
- package/src/core/sort/debug-visualization.ts +1 -1
- package/src/core/sort/sort-changes.test.ts +1 -0
- package/src/core/sort/topological-sort.ts +2 -2
|
@@ -147,10 +147,12 @@ async function getPg17Baseline() {
|
|
|
147
147
|
export async function createEmptyCatalog(version, currentUser) {
|
|
148
148
|
if (version >= 170000) {
|
|
149
149
|
const baseline = await getPg17Baseline();
|
|
150
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
150
151
|
return new Catalog({ ...baseline, version, currentUser });
|
|
151
152
|
}
|
|
152
153
|
if (version >= 150000) {
|
|
153
154
|
const baseline = await getPg1516Baseline();
|
|
155
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
154
156
|
return new Catalog({ ...baseline, version, currentUser });
|
|
155
157
|
}
|
|
156
158
|
const publicSchema = new Schema({
|
|
@@ -6,7 +6,7 @@ import { CreateMaterializedView } from "./objects/materialized-view/changes/mate
|
|
|
6
6
|
import { DropMaterializedView } from "./objects/materialized-view/changes/materialized-view.drop.js";
|
|
7
7
|
import { CreateProcedure } from "./objects/procedure/changes/procedure.create.js";
|
|
8
8
|
import { DropProcedure } from "./objects/procedure/changes/procedure.drop.js";
|
|
9
|
-
import { AlterTableAddConstraint
|
|
9
|
+
import { AlterTableAddConstraint } from "./objects/table/changes/table.alter.js";
|
|
10
10
|
import { CreateCommentOnConstraint } from "./objects/table/changes/table.comment.js";
|
|
11
11
|
import { CreateTable } from "./objects/table/changes/table.create.js";
|
|
12
12
|
import { DropTable } from "./objects/table/changes/table.drop.js";
|
|
@@ -312,12 +312,6 @@ function buildReplaceChanges(resolved, options) {
|
|
|
312
312
|
constraint,
|
|
313
313
|
}),
|
|
314
314
|
];
|
|
315
|
-
if (!constraint.validated) {
|
|
316
|
-
items.push(new AlterTableValidateConstraint({
|
|
317
|
-
table: resolved.branch,
|
|
318
|
-
constraint,
|
|
319
|
-
}));
|
|
320
|
-
}
|
|
321
315
|
if (constraint.comment !== null &&
|
|
322
316
|
constraint.comment !== undefined) {
|
|
323
317
|
items.push(new CreateCommentOnConstraint({
|
|
@@ -28,12 +28,6 @@ function createAlterConstraintChange(mainTable, branchTable) {
|
|
|
28
28
|
table: branchTable,
|
|
29
29
|
constraint: c,
|
|
30
30
|
}));
|
|
31
|
-
if (!c.validated) {
|
|
32
|
-
changes.push(new AlterTableValidateConstraint({
|
|
33
|
-
table: branchTable,
|
|
34
|
-
constraint: c,
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
31
|
// Add comment for newly created constraint
|
|
38
32
|
if (c.comment !== null) {
|
|
39
33
|
changes.push(new CreateCommentOnConstraint({
|
|
@@ -53,7 +47,7 @@ function createAlterConstraintChange(mainTable, branchTable) {
|
|
|
53
47
|
changes.push(new AlterTableDropConstraint({ table: mainTable, constraint: c }));
|
|
54
48
|
}
|
|
55
49
|
}
|
|
56
|
-
// Altered constraints -> drop + add
|
|
50
|
+
// Altered constraints -> drop + add (or VALIDATE-only shortcut)
|
|
57
51
|
for (const [name, mainC] of mainByName) {
|
|
58
52
|
const branchC = branchByName.get(name);
|
|
59
53
|
if (!branchC)
|
|
@@ -62,23 +56,57 @@ function createAlterConstraintChange(mainTable, branchTable) {
|
|
|
62
56
|
if (mainC.is_partition_clone || branchC.is_partition_clone) {
|
|
63
57
|
continue;
|
|
64
58
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
mainC.
|
|
69
|
-
mainC.
|
|
70
|
-
mainC.
|
|
71
|
-
mainC.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
mainC.
|
|
77
|
-
mainC.
|
|
78
|
-
mainC.
|
|
79
|
-
mainC.
|
|
80
|
-
|
|
81
|
-
mainC.
|
|
59
|
+
// Cheap scalar `===` checks first; only fall through to JSON.stringify
|
|
60
|
+
// on the array fields when every scalar has already matched.
|
|
61
|
+
const fieldsEqualExceptValidated = mainC.constraint_type === branchC.constraint_type &&
|
|
62
|
+
mainC.deferrable === branchC.deferrable &&
|
|
63
|
+
mainC.initially_deferred === branchC.initially_deferred &&
|
|
64
|
+
mainC.is_local === branchC.is_local &&
|
|
65
|
+
mainC.no_inherit === branchC.no_inherit &&
|
|
66
|
+
mainC.is_temporal === branchC.is_temporal &&
|
|
67
|
+
mainC.foreign_key_table === branchC.foreign_key_table &&
|
|
68
|
+
mainC.foreign_key_schema === branchC.foreign_key_schema &&
|
|
69
|
+
mainC.on_update === branchC.on_update &&
|
|
70
|
+
mainC.on_delete === branchC.on_delete &&
|
|
71
|
+
mainC.match_type === branchC.match_type &&
|
|
72
|
+
mainC.check_expression === branchC.check_expression &&
|
|
73
|
+
JSON.stringify(mainC.key_columns) ===
|
|
74
|
+
JSON.stringify(branchC.key_columns) &&
|
|
75
|
+
JSON.stringify(mainC.foreign_key_columns) ===
|
|
76
|
+
JSON.stringify(branchC.foreign_key_columns);
|
|
77
|
+
// Safe-migration shortcut: when the only difference is `validated`
|
|
78
|
+
// flipping from false to true, emit a single `ALTER TABLE ... VALIDATE
|
|
79
|
+
// CONSTRAINT` instead of drop+add. VALIDATE CONSTRAINT only takes
|
|
80
|
+
// SHARE UPDATE EXCLUSIVE (concurrent reads/writes proceed), whereas
|
|
81
|
+
// dropping and re-adding takes ACCESS EXCLUSIVE for the entire scan.
|
|
82
|
+
// Postgres has no reverse command, so `true -> false` must still go
|
|
83
|
+
// through drop+add below.
|
|
84
|
+
if (fieldsEqualExceptValidated &&
|
|
85
|
+
mainC.validated === false &&
|
|
86
|
+
branchC.validated === true) {
|
|
87
|
+
changes.push(new AlterTableValidateConstraint({
|
|
88
|
+
table: branchTable,
|
|
89
|
+
constraint: branchC,
|
|
90
|
+
}));
|
|
91
|
+
// VALIDATE preserves the constraint OID, so its comment is preserved
|
|
92
|
+
// too. Only emit a comment change if it actually differs.
|
|
93
|
+
if (mainC.comment !== branchC.comment) {
|
|
94
|
+
if (branchC.comment === null) {
|
|
95
|
+
changes.push(new DropCommentOnConstraint({
|
|
96
|
+
table: mainTable,
|
|
97
|
+
constraint: mainC,
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
changes.push(new CreateCommentOnConstraint({
|
|
102
|
+
table: branchTable,
|
|
103
|
+
constraint: branchC,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const changed = mainC.validated !== branchC.validated || !fieldsEqualExceptValidated;
|
|
82
110
|
if (changed) {
|
|
83
111
|
changes.push(new AlterTableDropConstraint({
|
|
84
112
|
table: mainTable,
|
|
@@ -88,12 +116,6 @@ function createAlterConstraintChange(mainTable, branchTable) {
|
|
|
88
116
|
table: branchTable,
|
|
89
117
|
constraint: branchC,
|
|
90
118
|
}));
|
|
91
|
-
if (!branchC.validated) {
|
|
92
|
-
changes.push(new AlterTableValidateConstraint({
|
|
93
|
-
table: branchTable,
|
|
94
|
-
constraint: branchC,
|
|
95
|
-
}));
|
|
96
|
-
}
|
|
97
119
|
// Ensure constraint comment is applied after re-creation
|
|
98
120
|
if (branchC.comment !== null) {
|
|
99
121
|
changes.push(new CreateCommentOnConstraint({
|
|
@@ -163,6 +185,7 @@ export function diffTables(ctx, main, branch) {
|
|
|
163
185
|
changes.push(...createAlterConstraintChange(
|
|
164
186
|
// Create a dummy table with no constraints do diff constraints against
|
|
165
187
|
new Table({
|
|
188
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
166
189
|
...branchTable,
|
|
167
190
|
constraints: [],
|
|
168
191
|
}), branchTable));
|
|
@@ -262,7 +262,7 @@ function addClusterChange(cluster, change) {
|
|
|
262
262
|
break;
|
|
263
263
|
default: {
|
|
264
264
|
const _exhaustive = objectType;
|
|
265
|
-
throw new Error(`Unhandled object type: ${_exhaustive}`);
|
|
265
|
+
throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
}
|
|
@@ -303,7 +303,7 @@ function addChildChange(schema, change) {
|
|
|
303
303
|
break;
|
|
304
304
|
default: {
|
|
305
305
|
const _exhaustive = parentType;
|
|
306
|
-
throw new Error(`Unhandled parent type: ${_exhaustive}`);
|
|
306
|
+
throw new Error(`Unhandled parent type: ${JSON.stringify(_exhaustive)}`);
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
const objectType = change.objectType;
|
|
@@ -351,7 +351,7 @@ function addChildChange(schema, change) {
|
|
|
351
351
|
break;
|
|
352
352
|
default: {
|
|
353
353
|
const _exhaustive = objectType;
|
|
354
|
-
throw new Error(`Unhandled object type: ${_exhaustive}`);
|
|
354
|
+
throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
}
|
|
@@ -482,7 +482,7 @@ function addSchemaLevelChange(schema, change, enrichment) {
|
|
|
482
482
|
break;
|
|
483
483
|
default: {
|
|
484
484
|
const _exhaustive = objectType;
|
|
485
|
-
throw new Error(`Unhandled object type: ${_exhaustive}`);
|
|
485
|
+
throw new Error(`Unhandled object type: ${JSON.stringify(_exhaustive)}`);
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
}
|
|
@@ -30,6 +30,13 @@ export declare function connectWithRetry<T>(opts: {
|
|
|
30
30
|
maxBackoffMs?: number;
|
|
31
31
|
sleep?: (ms: number) => Promise<void>;
|
|
32
32
|
}): Promise<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Race `connect()` against a `timeoutMs` rejection and clear the timer when
|
|
35
|
+
* either side wins. If the timer is left running after a fast connect, the
|
|
36
|
+
* pending `setTimeout` keeps the event loop alive and the process hangs for
|
|
37
|
+
* the rest of `timeoutMs`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function connectWithTimeout<T>(connect: () => Promise<T>, timeoutMs: number, label: "source" | "target"): Promise<T>;
|
|
33
40
|
/**
|
|
34
41
|
* Options for creating a Pool with event listeners.
|
|
35
42
|
*/
|
|
@@ -180,6 +180,24 @@ export async function connectWithRetry(opts) {
|
|
|
180
180
|
// Unreachable: loop either returns or throws.
|
|
181
181
|
throw lastError;
|
|
182
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Race `connect()` against a `timeoutMs` rejection and clear the timer when
|
|
185
|
+
* either side wins. If the timer is left running after a fast connect, the
|
|
186
|
+
* pending `setTimeout` keeps the event loop alive and the process hangs for
|
|
187
|
+
* the rest of `timeoutMs`.
|
|
188
|
+
*/
|
|
189
|
+
export function connectWithTimeout(connect, timeoutMs, label) {
|
|
190
|
+
let timer;
|
|
191
|
+
return Promise.race([
|
|
192
|
+
connect(),
|
|
193
|
+
new Promise((_, reject) => {
|
|
194
|
+
timer = setTimeout(() => reject(new Error(`Connection to ${label} database timed out after ${timeoutMs}ms. ` +
|
|
195
|
+
`The server may require SSL, use an invalid certificate, or be unreachable.`)), timeoutMs);
|
|
196
|
+
}),
|
|
197
|
+
]).finally(() => {
|
|
198
|
+
clearTimeout(timer);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
183
201
|
/**
|
|
184
202
|
* Create a Pool with custom type handlers and optional event listeners.
|
|
185
203
|
*
|
|
@@ -347,11 +365,7 @@ export async function createManagedPool(url, options) {
|
|
|
347
365
|
const timeoutMs = DEFAULT_CONNECT_TIMEOUT_MS;
|
|
348
366
|
try {
|
|
349
367
|
const client = await connectWithRetry({
|
|
350
|
-
connect: () =>
|
|
351
|
-
pool.connect(),
|
|
352
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(`Connection to ${label} database timed out after ${timeoutMs}ms. ` +
|
|
353
|
-
`The server may require SSL, use an invalid certificate, or be unreachable.`)), timeoutMs)),
|
|
354
|
-
]),
|
|
368
|
+
connect: () => connectWithTimeout(() => pool.connect(), timeoutMs, label),
|
|
355
369
|
});
|
|
356
370
|
client.release();
|
|
357
371
|
}
|
|
@@ -139,7 +139,7 @@ export function printDebugGraph(phaseChanges, graphData, edges, dependencyRows,
|
|
|
139
139
|
const mermaidDiagram = generateMermaidDiagram(phaseChanges, graphData, edges, requirementSets, dependenciesByReferencedId);
|
|
140
140
|
debugGraph("\n==== Mermaid (cycle detected) ====\n%s\n==== end ====", mermaidDiagram);
|
|
141
141
|
}
|
|
142
|
-
catch
|
|
142
|
+
catch {
|
|
143
143
|
// ignore debug printing errors
|
|
144
144
|
}
|
|
145
145
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export function performStableTopologicalSort(nodeCount, edges) {
|
|
7
7
|
const adjacencyList = Array.from({ length: nodeCount }, () => new Set());
|
|
8
|
-
const inDegreeCounts =
|
|
8
|
+
const inDegreeCounts = Array.from({ length: nodeCount }, () => 0);
|
|
9
9
|
for (const [sourceIndex, targetIndex] of edges) {
|
|
10
10
|
if (!adjacencyList[sourceIndex].has(targetIndex)) {
|
|
11
11
|
adjacencyList[sourceIndex].add(targetIndex);
|
|
@@ -51,7 +51,7 @@ export function findCycle(nodeCount, edges) {
|
|
|
51
51
|
adjacencyList[sourceIndex].push(targetIndex);
|
|
52
52
|
}
|
|
53
53
|
// 0 = unvisited, 1 = visiting, 2 = completed
|
|
54
|
-
const visitState =
|
|
54
|
+
const visitState = Array.from({ length: nodeCount }, () => 0);
|
|
55
55
|
const pathStack = [];
|
|
56
56
|
let cycleNodeIndexes = null;
|
|
57
57
|
const depthFirstSearch = (nodeIndex) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supabase/pg-delta",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.26",
|
|
4
4
|
"description": "PostgreSQL migrations made easy",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"diff",
|
|
7
|
+
"migrations",
|
|
8
|
+
"pg",
|
|
9
|
+
"pg-delta",
|
|
10
|
+
"pgdelta",
|
|
11
|
+
"postgres"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/supabase/pg-toolbelt",
|
|
14
|
+
"bugs": "https://github.com/supabase/pg-toolbelt/issues",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Supabase",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/supabase/pg-toolbelt.git",
|
|
20
|
+
"directory": "packages/pg-delta"
|
|
21
|
+
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"pgdelta": "./dist/cli/bin/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
5
31
|
"type": "module",
|
|
6
32
|
"sideEffects": false,
|
|
7
33
|
"main": "./dist/index.js",
|
|
@@ -36,40 +62,12 @@
|
|
|
36
62
|
"default": "./dist/core/catalog-export/index.js"
|
|
37
63
|
}
|
|
38
64
|
},
|
|
39
|
-
"bin": {
|
|
40
|
-
"pgdelta": "./dist/cli/bin/cli.js"
|
|
41
|
-
},
|
|
42
|
-
"files": [
|
|
43
|
-
"dist",
|
|
44
|
-
"src",
|
|
45
|
-
"README.md",
|
|
46
|
-
"LICENSE"
|
|
47
|
-
],
|
|
48
|
-
"keywords": [
|
|
49
|
-
"pg",
|
|
50
|
-
"postgres",
|
|
51
|
-
"migrations",
|
|
52
|
-
"diff",
|
|
53
|
-
"pg-delta",
|
|
54
|
-
"pgdelta"
|
|
55
|
-
],
|
|
56
|
-
"author": "Supabase",
|
|
57
|
-
"license": "MIT",
|
|
58
|
-
"homepage": "https://github.com/supabase/pg-toolbelt",
|
|
59
|
-
"repository": {
|
|
60
|
-
"type": "git",
|
|
61
|
-
"url": "https://github.com/supabase/pg-toolbelt.git",
|
|
62
|
-
"directory": "packages/pg-delta"
|
|
63
|
-
},
|
|
64
|
-
"bugs": "https://github.com/supabase/pg-toolbelt/issues",
|
|
65
|
-
"engines": {
|
|
66
|
-
"node": ">=20.0.0"
|
|
67
|
-
},
|
|
68
65
|
"scripts": {
|
|
69
66
|
"build": "tsc --project tsconfig.build.json",
|
|
70
67
|
"check-types": "tsc --noEmit",
|
|
71
68
|
"docs": "typedoc",
|
|
72
|
-
"format-and-lint": "
|
|
69
|
+
"format-and-lint": "oxfmt --check . && oxlint --deny-warnings",
|
|
70
|
+
"format-and-lint:fix": "oxfmt . && oxlint --fix",
|
|
73
71
|
"knip": "knip",
|
|
74
72
|
"pgdelta": "bun src/cli/bin/cli.ts",
|
|
75
73
|
"sync-base-images": "bun scripts/sync-supabase-base-images.ts",
|
|
@@ -77,12 +75,12 @@
|
|
|
77
75
|
"test:unit": "bun run test src/",
|
|
78
76
|
"test:integration": "bun run test tests/",
|
|
79
77
|
"update-empty-baseline": "bun scripts/update-empty-catalog-baseline.ts",
|
|
80
|
-
"version": "changeset version && bun install --no-frozen-lockfile && bun run format-and-lint
|
|
78
|
+
"version": "changeset version && bun install --no-frozen-lockfile && bun run format-and-lint:fix"
|
|
81
79
|
},
|
|
82
80
|
"dependencies": {
|
|
83
81
|
"@stricli/core": "^1.2.4",
|
|
84
|
-
"@ts-safeql/sql-tag": "^0.2.0",
|
|
85
82
|
"@supabase/pg-topo": "^1.0.0-alpha.1",
|
|
83
|
+
"@ts-safeql/sql-tag": "^0.2.0",
|
|
86
84
|
"chalk": "^5.6.2",
|
|
87
85
|
"debug": "^4.3.7",
|
|
88
86
|
"pg": "^8.17.2",
|
|
@@ -103,5 +101,8 @@
|
|
|
103
101
|
"testcontainers": "^11.10.0",
|
|
104
102
|
"typedoc": "^0.28.17",
|
|
105
103
|
"typescript": "^5.9.3"
|
|
104
|
+
},
|
|
105
|
+
"engines": {
|
|
106
|
+
"node": ">=20.0.0"
|
|
106
107
|
}
|
|
107
108
|
}
|
|
@@ -182,9 +182,8 @@ let _pg1516Baseline: Catalog | null = null;
|
|
|
182
182
|
let _pg17Baseline: Catalog | null = null;
|
|
183
183
|
|
|
184
184
|
async function loadBaselineJson(): Promise<Record<string, unknown>> {
|
|
185
|
-
const mod =
|
|
186
|
-
"./fixtures/empty-catalogs/postgres-15-16-baseline.json"
|
|
187
|
-
);
|
|
185
|
+
const mod =
|
|
186
|
+
await import("./fixtures/empty-catalogs/postgres-15-16-baseline.json");
|
|
188
187
|
return mod.default as Record<string, unknown>;
|
|
189
188
|
}
|
|
190
189
|
|
|
@@ -256,10 +255,12 @@ export async function createEmptyCatalog(
|
|
|
256
255
|
): Promise<Catalog> {
|
|
257
256
|
if (version >= 170000) {
|
|
258
257
|
const baseline = await getPg17Baseline();
|
|
258
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
259
259
|
return new Catalog({ ...baseline, version, currentUser });
|
|
260
260
|
}
|
|
261
261
|
if (version >= 150000) {
|
|
262
262
|
const baseline = await getPg1516Baseline();
|
|
263
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
263
264
|
return new Catalog({ ...baseline, version, currentUser });
|
|
264
265
|
}
|
|
265
266
|
|
|
@@ -294,6 +294,7 @@ describe("catalog snapshot serde", () => {
|
|
|
294
294
|
|
|
295
295
|
const sourceCatalog = await createEmptyCatalog(160000, "postgres");
|
|
296
296
|
const targetCatalog = await createEmptyCatalog(160000, "postgres");
|
|
297
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
297
298
|
const source = { ...sourceCatalog };
|
|
298
299
|
|
|
299
300
|
expect(source instanceof Catalog).toBe(false);
|
|
@@ -189,11 +189,13 @@ describe("expandReplaceDependencies", () => {
|
|
|
189
189
|
privileges: [],
|
|
190
190
|
});
|
|
191
191
|
const branchView = new View({
|
|
192
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
192
193
|
...mainView,
|
|
193
194
|
definition: " SELECT count(*) AS n FROM public.members;",
|
|
194
195
|
});
|
|
195
196
|
|
|
196
197
|
const mainCatalog = new Catalog({
|
|
198
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
197
199
|
...baseline,
|
|
198
200
|
tables: { [usersTable.stableId]: usersTable },
|
|
199
201
|
views: { [mainView.stableId]: mainView },
|
|
@@ -206,6 +208,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
206
208
|
],
|
|
207
209
|
});
|
|
208
210
|
const branchCatalog = new Catalog({
|
|
211
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
209
212
|
...baseline,
|
|
210
213
|
views: { [branchView.stableId]: branchView },
|
|
211
214
|
});
|
|
@@ -253,6 +256,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
253
256
|
owner: "postgres",
|
|
254
257
|
});
|
|
255
258
|
const branchSequence = new Sequence({
|
|
259
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
256
260
|
...mainSequence,
|
|
257
261
|
persistence: "p",
|
|
258
262
|
});
|
|
@@ -309,6 +313,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
309
313
|
{ [usersTable.stableId]: usersTable },
|
|
310
314
|
);
|
|
311
315
|
const mainCatalog = new Catalog({
|
|
316
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
312
317
|
...baseline,
|
|
313
318
|
sequences: { [mainSequence.stableId]: mainSequence },
|
|
314
319
|
tables: { [usersTable.stableId]: usersTable },
|
|
@@ -326,6 +331,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
326
331
|
],
|
|
327
332
|
});
|
|
328
333
|
const branchCatalog = new Catalog({
|
|
334
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
329
335
|
...baseline,
|
|
330
336
|
sequences: { [branchSequence.stableId]: branchSequence },
|
|
331
337
|
tables: { [usersTable.stableId]: usersTable },
|
|
@@ -369,6 +375,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
369
375
|
privileges: [],
|
|
370
376
|
});
|
|
371
377
|
const branchEnum = new Enum({
|
|
378
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
372
379
|
...mainEnum,
|
|
373
380
|
labels: [
|
|
374
381
|
{ sort_order: 1, label: "draft" },
|
|
@@ -430,6 +437,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
430
437
|
privileges: [],
|
|
431
438
|
});
|
|
432
439
|
const branchChildren = new Table({
|
|
440
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
433
441
|
...mainChildren,
|
|
434
442
|
columns: [
|
|
435
443
|
{ ...columnTemplate, name: "id", position: 1, not_null: true },
|
|
@@ -522,6 +530,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
522
530
|
];
|
|
523
531
|
|
|
524
532
|
const mainCatalog = new Catalog({
|
|
533
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
525
534
|
...baseline,
|
|
526
535
|
enums: { [mainEnum.stableId]: mainEnum },
|
|
527
536
|
tables: { [mainChildren.stableId]: mainChildren },
|
|
@@ -535,6 +544,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
535
544
|
],
|
|
536
545
|
});
|
|
537
546
|
const branchCatalog = new Catalog({
|
|
547
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
538
548
|
...baseline,
|
|
539
549
|
enums: { [branchEnum.stableId]: branchEnum },
|
|
540
550
|
tables: { [branchChildren.stableId]: branchChildren },
|
|
@@ -657,6 +667,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
657
667
|
];
|
|
658
668
|
|
|
659
669
|
const mainCatalog = new Catalog({
|
|
670
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
660
671
|
...baseline,
|
|
661
672
|
procedures: { [mainProcedure.stableId]: mainProcedure },
|
|
662
673
|
views: { [mainView.stableId]: mainView },
|
|
@@ -669,6 +680,7 @@ describe("expandReplaceDependencies", () => {
|
|
|
669
680
|
],
|
|
670
681
|
});
|
|
671
682
|
const branchCatalog = new Catalog({
|
|
683
|
+
// oxlint-disable-next-line typescript/no-misused-spread
|
|
672
684
|
...baseline,
|
|
673
685
|
procedures: { [branchProcedure.stableId]: branchProcedure },
|
|
674
686
|
views: { [branchView.stableId]: branchView },
|
|
@@ -8,10 +8,7 @@ import { CreateMaterializedView } from "./objects/materialized-view/changes/mate
|
|
|
8
8
|
import { DropMaterializedView } from "./objects/materialized-view/changes/materialized-view.drop.ts";
|
|
9
9
|
import { CreateProcedure } from "./objects/procedure/changes/procedure.create.ts";
|
|
10
10
|
import { DropProcedure } from "./objects/procedure/changes/procedure.drop.ts";
|
|
11
|
-
import {
|
|
12
|
-
AlterTableAddConstraint,
|
|
13
|
-
AlterTableValidateConstraint,
|
|
14
|
-
} from "./objects/table/changes/table.alter.ts";
|
|
11
|
+
import { AlterTableAddConstraint } from "./objects/table/changes/table.alter.ts";
|
|
15
12
|
import { CreateCommentOnConstraint } from "./objects/table/changes/table.comment.ts";
|
|
16
13
|
import { CreateTable } from "./objects/table/changes/table.create.ts";
|
|
17
14
|
import { DropTable } from "./objects/table/changes/table.drop.ts";
|
|
@@ -455,14 +452,6 @@ function buildReplaceChanges(
|
|
|
455
452
|
constraint,
|
|
456
453
|
}),
|
|
457
454
|
];
|
|
458
|
-
if (!constraint.validated) {
|
|
459
|
-
items.push(
|
|
460
|
-
new AlterTableValidateConstraint({
|
|
461
|
-
table: resolved.branch,
|
|
462
|
-
constraint,
|
|
463
|
-
}),
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
455
|
if (
|
|
467
456
|
constraint.comment !== null &&
|
|
468
457
|
constraint.comment !== undefined
|
|
@@ -8,7 +8,7 @@ abstract class BaseAggregateChange extends BaseChange {
|
|
|
8
8
|
| "comment"
|
|
9
9
|
| "privilege"
|
|
10
10
|
| "security_label";
|
|
11
|
-
readonly objectType
|
|
11
|
+
readonly objectType = "aggregate" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateAggregateChange extends BaseAggregateChange {
|
|
@@ -4,7 +4,7 @@ import type { Collation } from "../collation.model.ts";
|
|
|
4
4
|
abstract class BaseCollationChange extends BaseChange {
|
|
5
5
|
abstract readonly collation: Collation;
|
|
6
6
|
abstract readonly scope: "object" | "comment";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "collation" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateCollationChange extends BaseCollationChange {
|
|
@@ -8,7 +8,7 @@ abstract class BaseDomainChange extends BaseChange {
|
|
|
8
8
|
| "comment"
|
|
9
9
|
| "privilege"
|
|
10
10
|
| "security_label";
|
|
11
|
-
readonly objectType
|
|
11
|
+
readonly objectType = "domain" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateDomainChange extends BaseDomainChange {
|
|
@@ -4,7 +4,7 @@ import type { Extension } from "../extension.model.ts";
|
|
|
4
4
|
abstract class BaseExtensionChange extends BaseChange {
|
|
5
5
|
abstract readonly extension: Extension;
|
|
6
6
|
abstract readonly scope: "object" | "comment";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "extension" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateExtensionChange extends BaseExtensionChange {
|
|
@@ -4,7 +4,7 @@ import type { ForeignDataWrapper } from "../foreign-data-wrapper.model.ts";
|
|
|
4
4
|
abstract class BaseForeignDataWrapperChange extends BaseChange {
|
|
5
5
|
abstract readonly foreignDataWrapper: ForeignDataWrapper;
|
|
6
6
|
abstract readonly scope: "object" | "comment" | "privilege";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "foreign_data_wrapper" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateForeignDataWrapperChange extends BaseForeignDataWrapperChange {
|
|
@@ -8,7 +8,7 @@ abstract class BaseForeignTableChange extends BaseChange {
|
|
|
8
8
|
| "comment"
|
|
9
9
|
| "privilege"
|
|
10
10
|
| "security_label";
|
|
11
|
-
readonly objectType
|
|
11
|
+
readonly objectType = "foreign_table" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateForeignTableChange extends BaseForeignTableChange {
|
|
@@ -4,7 +4,7 @@ import type { Server } from "../server.model.ts";
|
|
|
4
4
|
abstract class BaseServerChange extends BaseChange {
|
|
5
5
|
abstract readonly server: Server;
|
|
6
6
|
abstract readonly scope: "object" | "comment" | "privilege";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "server" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateServerChange extends BaseServerChange {
|
|
@@ -4,7 +4,7 @@ import type { UserMapping } from "../user-mapping.model.ts";
|
|
|
4
4
|
abstract class BaseUserMappingChange extends BaseChange {
|
|
5
5
|
abstract readonly userMapping: UserMapping;
|
|
6
6
|
abstract readonly scope: "object";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "user_mapping" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateUserMappingChange extends BaseUserMappingChange {
|
|
@@ -4,7 +4,7 @@ import type { Index } from "../index.model.ts";
|
|
|
4
4
|
abstract class BaseIndexChange extends BaseChange {
|
|
5
5
|
abstract readonly index: Index;
|
|
6
6
|
abstract readonly scope: "object" | "comment";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "index" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateIndexChange extends BaseIndexChange {
|
|
@@ -4,7 +4,7 @@ import type { Language } from "../language.model.ts";
|
|
|
4
4
|
abstract class BaseLanguageChange extends BaseChange {
|
|
5
5
|
abstract readonly language: Language;
|
|
6
6
|
abstract readonly scope: "object" | "comment" | "privilege";
|
|
7
|
-
readonly objectType
|
|
7
|
+
readonly objectType = "language" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export abstract class CreateLanguageChange extends BaseLanguageChange {
|
|
@@ -8,7 +8,7 @@ abstract class BaseMaterializedViewChange extends BaseChange {
|
|
|
8
8
|
| "comment"
|
|
9
9
|
| "privilege"
|
|
10
10
|
| "security_label";
|
|
11
|
-
readonly objectType
|
|
11
|
+
readonly objectType = "materialized_view" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateMaterializedViewChange extends BaseMaterializedViewChange {
|
|
@@ -8,7 +8,7 @@ abstract class BaseProcedureChange extends BaseChange {
|
|
|
8
8
|
| "comment"
|
|
9
9
|
| "privilege"
|
|
10
10
|
| "security_label";
|
|
11
|
-
readonly objectType
|
|
11
|
+
readonly objectType = "procedure" as const;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export abstract class CreateProcedureChange extends BaseProcedureChange {
|