@supabase/pg-delta 1.0.0-alpha.20 → 1.0.0-alpha.22

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 (81) hide show
  1. package/dist/core/catalog.diff.js +4 -4
  2. package/dist/core/catalog.model.d.ts +8 -1
  3. package/dist/core/catalog.model.js +9 -8
  4. package/dist/core/expand-replace-dependencies.js +23 -0
  5. package/dist/core/objects/extract-with-retry.d.ts +36 -0
  6. package/dist/core/objects/extract-with-retry.js +51 -0
  7. package/dist/core/objects/index/index.diff.js +0 -1
  8. package/dist/core/objects/index/index.model.d.ts +2 -3
  9. package/dist/core/objects/index/index.model.js +17 -6
  10. package/dist/core/objects/materialized-view/materialized-view.model.d.ts +2 -1
  11. package/dist/core/objects/materialized-view/materialized-view.model.js +20 -4
  12. package/dist/core/objects/procedure/procedure.model.d.ts +2 -1
  13. package/dist/core/objects/procedure/procedure.model.js +20 -4
  14. package/dist/core/objects/publication/changes/publication.alter.d.ts +1 -1
  15. package/dist/core/objects/rls-policy/rls-policy.diff.js +13 -1
  16. package/dist/core/objects/rule/rule.model.d.ts +2 -1
  17. package/dist/core/objects/rule/rule.model.js +20 -3
  18. package/dist/core/objects/sequence/sequence.diff.d.ts +2 -1
  19. package/dist/core/objects/sequence/sequence.diff.js +41 -9
  20. package/dist/core/objects/table/changes/table.alter.d.ts +16 -1
  21. package/dist/core/objects/table/changes/table.alter.js +39 -6
  22. package/dist/core/objects/table/table.diff.js +40 -17
  23. package/dist/core/objects/table/table.model.d.ts +6 -1
  24. package/dist/core/objects/table/table.model.js +50 -12
  25. package/dist/core/objects/trigger/trigger.model.d.ts +2 -1
  26. package/dist/core/objects/trigger/trigger.model.js +20 -4
  27. package/dist/core/objects/utils.d.ts +1 -0
  28. package/dist/core/objects/utils.js +3 -0
  29. package/dist/core/objects/view/view.model.d.ts +2 -1
  30. package/dist/core/objects/view/view.model.js +20 -4
  31. package/dist/core/plan/create.js +3 -1
  32. package/dist/core/plan/types.d.ts +8 -0
  33. package/dist/core/post-diff-normalization.d.ts +36 -0
  34. package/dist/core/post-diff-normalization.js +202 -0
  35. package/dist/core/sort/cycle-breakers.d.ts +15 -0
  36. package/dist/core/sort/cycle-breakers.js +269 -0
  37. package/dist/core/sort/sort-changes.js +97 -43
  38. package/dist/core/sort/utils.d.ts +10 -0
  39. package/dist/core/sort/utils.js +28 -0
  40. package/package.json +1 -1
  41. package/src/core/catalog.diff.ts +4 -3
  42. package/src/core/catalog.model.ts +20 -8
  43. package/src/core/expand-replace-dependencies.test.ts +139 -5
  44. package/src/core/expand-replace-dependencies.ts +24 -0
  45. package/src/core/objects/extract-with-retry.test.ts +143 -0
  46. package/src/core/objects/extract-with-retry.ts +87 -0
  47. package/src/core/objects/index/index.diff.ts +0 -1
  48. package/src/core/objects/index/index.model.test.ts +37 -1
  49. package/src/core/objects/index/index.model.ts +25 -6
  50. package/src/core/objects/materialized-view/materialized-view.model.test.ts +93 -0
  51. package/src/core/objects/materialized-view/materialized-view.model.ts +27 -4
  52. package/src/core/objects/procedure/procedure.model.test.ts +117 -0
  53. package/src/core/objects/procedure/procedure.model.ts +28 -5
  54. package/src/core/objects/publication/changes/publication.alter.ts +1 -1
  55. package/src/core/objects/rls-policy/rls-policy.diff.ts +19 -1
  56. package/src/core/objects/rule/rule.model.test.ts +99 -0
  57. package/src/core/objects/rule/rule.model.ts +28 -4
  58. package/src/core/objects/sequence/sequence.diff.test.ts +93 -1
  59. package/src/core/objects/sequence/sequence.diff.ts +43 -10
  60. package/src/core/objects/table/changes/table.alter.test.ts +26 -23
  61. package/src/core/objects/table/changes/table.alter.ts +66 -10
  62. package/src/core/objects/table/table.diff.test.ts +43 -0
  63. package/src/core/objects/table/table.diff.ts +52 -23
  64. package/src/core/objects/table/table.model.test.ts +209 -0
  65. package/src/core/objects/table/table.model.ts +62 -14
  66. package/src/core/objects/trigger/trigger.model.test.ts +113 -0
  67. package/src/core/objects/trigger/trigger.model.ts +28 -5
  68. package/src/core/objects/utils.ts +3 -0
  69. package/src/core/objects/view/view.model.test.ts +90 -0
  70. package/src/core/objects/view/view.model.ts +28 -5
  71. package/src/core/plan/create.ts +3 -1
  72. package/src/core/plan/types.ts +8 -0
  73. package/src/core/{post-diff-cycle-breaking.test.ts → post-diff-normalization.test.ts} +168 -160
  74. package/src/core/post-diff-normalization.ts +260 -0
  75. package/src/core/sort/cycle-breakers.test.ts +476 -0
  76. package/src/core/sort/cycle-breakers.ts +311 -0
  77. package/src/core/sort/sort-changes.ts +135 -50
  78. package/src/core/sort/utils.ts +38 -0
  79. package/dist/core/post-diff-cycle-breaking.d.ts +0 -29
  80. package/dist/core/post-diff-cycle-breaking.js +0 -209
  81. package/src/core/post-diff-cycle-breaking.ts +0 -317
@@ -1,209 +0,0 @@
1
- import { AlterTableAddConstraint, AlterTableDropColumn, AlterTableDropConstraint, AlterTableValidateConstraint, } from "./objects/table/changes/table.alter.js";
2
- import { CreateCommentOnConstraint } from "./objects/table/changes/table.comment.js";
3
- import { DropTable } from "./objects/table/changes/table.drop.js";
4
- import { stableId } from "./objects/utils.js";
5
- function constraintStableId(table, constraintName) {
6
- return stableId.constraint(table.schema, table.name, constraintName);
7
- }
8
- /**
9
- * Yield FK constraints on `table` whose referenced table is also dropped in the
10
- * final plan. Self-references are left alone because the sort phase already
11
- * handles the resulting self-loop correctly.
12
- */
13
- function* iterCrossDropFkConstraints(table, droppedSet) {
14
- for (const constraint of table.constraints) {
15
- if (constraint.constraint_type !== "f")
16
- continue;
17
- if (constraint.is_partition_clone)
18
- continue;
19
- if (!constraint.foreign_key_schema || !constraint.foreign_key_table) {
20
- continue;
21
- }
22
- const referencedId = stableId.table(constraint.foreign_key_schema, constraint.foreign_key_table);
23
- if (referencedId === table.stableId)
24
- continue;
25
- if (!droppedSet.has(referencedId))
26
- continue;
27
- yield { constraint, referencedId };
28
- }
29
- }
30
- function isSupersededByTableReplacement(change, replacedTableIds) {
31
- if (!(change instanceof AlterTableDropColumn) &&
32
- !(change instanceof AlterTableDropConstraint)) {
33
- return false;
34
- }
35
- return replacedTableIds.has(change.table.stableId);
36
- }
37
- /**
38
- * Drop earlier duplicates of `AlterTableAddConstraint` /
39
- * `AlterTableValidateConstraint` / `CreateCommentOnConstraint` targeting
40
- * replaced tables, keeping only the last occurrence of each
41
- * `(changeType, table.stableId, constraint.name)`.
42
- *
43
- * When `expandReplaceDependencies()` promotes a table to a full
44
- * `DropTable + CreateTable` pair, it also emits one
45
- * `AlterTableAddConstraint` (plus optional `VALIDATE CONSTRAINT` /
46
- * `COMMENT ON CONSTRAINT`) per branch constraint. If `diffTables()` already
47
- * emitted the same change for a shape flip or a new constraint on that
48
- * table, the plan ends up with two identical `ALTER TABLE ... ADD
49
- * CONSTRAINT ...` statements and PostgreSQL fails at apply time with
50
- * `constraint "..." for relation "..." already exists`. Because
51
- * `expandReplaceDependencies()` appends its additions after the original
52
- * `diffTables()` output, the last occurrence is the expansion's emission —
53
- * keeping it preserves correctness while removing the duplicate.
54
- */
55
- function dropReplacedTableDuplicateConstraintChanges(changes, replacedTableIds) {
56
- if (replacedTableIds.size === 0)
57
- return changes;
58
- const keyFor = (change) => {
59
- if (!(change instanceof AlterTableAddConstraint) &&
60
- !(change instanceof AlterTableValidateConstraint) &&
61
- !(change instanceof CreateCommentOnConstraint)) {
62
- return null;
63
- }
64
- if (!replacedTableIds.has(change.table.stableId))
65
- return null;
66
- const tag = change instanceof AlterTableAddConstraint
67
- ? "add"
68
- : change instanceof AlterTableValidateConstraint
69
- ? "validate"
70
- : "comment";
71
- return `${tag}:${constraintStableId(change.table, change.constraint.name)}`;
72
- };
73
- const seen = new Set();
74
- const reversedKept = [];
75
- let mutated = false;
76
- // Walk backwards: the first encounter of each key corresponds to its LAST
77
- // occurrence in the original order. `expandReplaceDependencies()` appends
78
- // additions after the original changes, so "last wins" keeps the
79
- // expansion's emission and drops the earlier diffTables duplicate.
80
- for (let i = changes.length - 1; i >= 0; i--) {
81
- const change = changes[i];
82
- const key = keyFor(change);
83
- if (key !== null) {
84
- if (seen.has(key)) {
85
- mutated = true;
86
- continue;
87
- }
88
- seen.add(key);
89
- }
90
- reversedKept.push(change);
91
- }
92
- return mutated ? reversedKept.reverse() : changes;
93
- }
94
- function collectExplicitConstraintDropIds(changes) {
95
- const explicitConstraintDropIds = new Set();
96
- for (const change of changes) {
97
- if (!(change instanceof AlterTableDropConstraint))
98
- continue;
99
- explicitConstraintDropIds.add(constraintStableId(change.table, change.constraint.name));
100
- }
101
- return explicitConstraintDropIds;
102
- }
103
- function hasSameEntries(left, right) {
104
- if (left.size !== right.size)
105
- return false;
106
- for (const value of left) {
107
- if (!right.has(value))
108
- return false;
109
- }
110
- return true;
111
- }
112
- /**
113
- * Normalize change-list cycles that only become apparent after all object
114
- * diffs have been collected.
115
- *
116
- * This pass intentionally handles whole-plan interactions only:
117
- * - If replace expansion added `DropTable(T)+CreateTable(T)`, targeted
118
- * `AlterTableDropColumn(T.*)` / `AlterTableDropConstraint(T.*)` changes are
119
- * redundant and create an unbreakable drop-phase cycle, so we elide them.
120
- * - When the same `DropTable+CreateTable` pair is present, the expansion
121
- * also emits one `AlterTableAddConstraint` / `AlterTableValidateConstraint`
122
- * / `CreateCommentOnConstraint` per branch constraint, which may collide
123
- * with the same change already emitted by `diffTables()` (for example on a
124
- * shape flip or a new constraint). We dedupe these keeping only the last
125
- * occurrence so the expansion's emission survives and the diffTables
126
- * duplicate is removed.
127
- * - If two dropped tables reference each other via FK, we insert dedicated
128
- * `AlterTableDropConstraint` changes and teach the paired `DropTable`
129
- * changes not to claim those FK stable IDs.
130
- *
131
- * Object-local PostgreSQL semantics (for example owned-sequence cascades) stay
132
- * in the corresponding `diff*` function instead of this pass.
133
- */
134
- export function normalizePostDiffCycles({ changes, mainCatalog, replacedTableIds = new Set(), }) {
135
- const dedupedChanges = dropReplacedTableDuplicateConstraintChanges(changes, replacedTableIds);
136
- const structurallyNormalizedChanges = replacedTableIds.size === 0
137
- ? dedupedChanges
138
- : dedupedChanges.filter((change) => !isSupersededByTableReplacement(change, replacedTableIds));
139
- const dropTableChanges = structurallyNormalizedChanges.filter((change) => change instanceof DropTable);
140
- if (dropTableChanges.length < 2) {
141
- return structurallyNormalizedChanges;
142
- }
143
- const droppedSet = new Set(dropTableChanges.map((change) => change.table.stableId));
144
- const droppedFkTargets = new Map();
145
- for (const dropTableChange of dropTableChanges) {
146
- const mainTable = mainCatalog.tables[dropTableChange.table.stableId] ??
147
- dropTableChange.table;
148
- const targets = new Set();
149
- for (const { referencedId } of iterCrossDropFkConstraints(mainTable, droppedSet)) {
150
- targets.add(referencedId);
151
- }
152
- droppedFkTargets.set(mainTable.stableId, targets);
153
- }
154
- const explicitConstraintDropIds = collectExplicitConstraintDropIds(structurallyNormalizedChanges);
155
- const injectedConstraintDropsByTableId = new Map();
156
- const externallyDroppedConstraintsByTableId = new Map();
157
- let didMutate = structurallyNormalizedChanges !== changes;
158
- for (const dropTableChange of dropTableChanges) {
159
- const mainTable = mainCatalog.tables[dropTableChange.table.stableId] ??
160
- dropTableChange.table;
161
- const externallyDroppedConstraints = new Set(dropTableChange.externallyDroppedConstraints);
162
- for (const { constraint, referencedId } of iterCrossDropFkConstraints(mainTable, droppedSet)) {
163
- const isMutual = droppedFkTargets.get(referencedId)?.has(mainTable.stableId) === true;
164
- if (!isMutual)
165
- continue;
166
- const droppedConstraintStableId = constraintStableId(mainTable, constraint.name);
167
- externallyDroppedConstraints.add(constraint.name);
168
- if (!explicitConstraintDropIds.has(droppedConstraintStableId)) {
169
- const injectedDrop = new AlterTableDropConstraint({
170
- table: mainTable,
171
- constraint,
172
- });
173
- const existingDrops = injectedConstraintDropsByTableId.get(mainTable.stableId) ?? [];
174
- existingDrops.push(injectedDrop);
175
- injectedConstraintDropsByTableId.set(mainTable.stableId, existingDrops);
176
- explicitConstraintDropIds.add(droppedConstraintStableId);
177
- didMutate = true;
178
- }
179
- }
180
- if (!hasSameEntries(dropTableChange.externallyDroppedConstraints, externallyDroppedConstraints)) {
181
- externallyDroppedConstraintsByTableId.set(mainTable.stableId, externallyDroppedConstraints);
182
- didMutate = true;
183
- }
184
- }
185
- if (!didMutate) {
186
- return changes;
187
- }
188
- const normalizedChanges = [];
189
- for (const change of structurallyNormalizedChanges) {
190
- if (!(change instanceof DropTable)) {
191
- normalizedChanges.push(change);
192
- continue;
193
- }
194
- const injectedConstraintDrops = injectedConstraintDropsByTableId.get(change.table.stableId) ?? [];
195
- if (injectedConstraintDrops.length > 0) {
196
- normalizedChanges.push(...injectedConstraintDrops);
197
- }
198
- const externallyDroppedConstraints = externallyDroppedConstraintsByTableId.get(change.table.stableId);
199
- if (!externallyDroppedConstraints) {
200
- normalizedChanges.push(change);
201
- continue;
202
- }
203
- normalizedChanges.push(new DropTable({
204
- table: change.table,
205
- externallyDroppedConstraints,
206
- }));
207
- }
208
- return normalizedChanges;
209
- }
@@ -1,317 +0,0 @@
1
- import type { Catalog } from "./catalog.model.ts";
2
- import type { Change } from "./change.types.ts";
3
- import {
4
- AlterTableAddConstraint,
5
- AlterTableDropColumn,
6
- AlterTableDropConstraint,
7
- AlterTableValidateConstraint,
8
- } from "./objects/table/changes/table.alter.ts";
9
- import { CreateCommentOnConstraint } from "./objects/table/changes/table.comment.ts";
10
- import { DropTable } from "./objects/table/changes/table.drop.ts";
11
- import { stableId } from "./objects/utils.ts";
12
-
13
- function constraintStableId(
14
- table: { schema: string; name: string },
15
- constraintName: string,
16
- ) {
17
- return stableId.constraint(table.schema, table.name, constraintName);
18
- }
19
-
20
- /**
21
- * Yield FK constraints on `table` whose referenced table is also dropped in the
22
- * final plan. Self-references are left alone because the sort phase already
23
- * handles the resulting self-loop correctly.
24
- */
25
- function* iterCrossDropFkConstraints(
26
- table: Catalog["tables"][string],
27
- droppedSet: ReadonlySet<string>,
28
- ) {
29
- for (const constraint of table.constraints) {
30
- if (constraint.constraint_type !== "f") continue;
31
- if (constraint.is_partition_clone) continue;
32
- if (!constraint.foreign_key_schema || !constraint.foreign_key_table) {
33
- continue;
34
- }
35
- const referencedId = stableId.table(
36
- constraint.foreign_key_schema,
37
- constraint.foreign_key_table,
38
- );
39
- if (referencedId === table.stableId) continue;
40
- if (!droppedSet.has(referencedId)) continue;
41
- yield { constraint, referencedId };
42
- }
43
- }
44
-
45
- function isSupersededByTableReplacement(
46
- change: Change,
47
- replacedTableIds: ReadonlySet<string>,
48
- ): boolean {
49
- if (
50
- !(change instanceof AlterTableDropColumn) &&
51
- !(change instanceof AlterTableDropConstraint)
52
- ) {
53
- return false;
54
- }
55
- return replacedTableIds.has(change.table.stableId);
56
- }
57
-
58
- /**
59
- * Drop earlier duplicates of `AlterTableAddConstraint` /
60
- * `AlterTableValidateConstraint` / `CreateCommentOnConstraint` targeting
61
- * replaced tables, keeping only the last occurrence of each
62
- * `(changeType, table.stableId, constraint.name)`.
63
- *
64
- * When `expandReplaceDependencies()` promotes a table to a full
65
- * `DropTable + CreateTable` pair, it also emits one
66
- * `AlterTableAddConstraint` (plus optional `VALIDATE CONSTRAINT` /
67
- * `COMMENT ON CONSTRAINT`) per branch constraint. If `diffTables()` already
68
- * emitted the same change for a shape flip or a new constraint on that
69
- * table, the plan ends up with two identical `ALTER TABLE ... ADD
70
- * CONSTRAINT ...` statements and PostgreSQL fails at apply time with
71
- * `constraint "..." for relation "..." already exists`. Because
72
- * `expandReplaceDependencies()` appends its additions after the original
73
- * `diffTables()` output, the last occurrence is the expansion's emission —
74
- * keeping it preserves correctness while removing the duplicate.
75
- */
76
- function dropReplacedTableDuplicateConstraintChanges(
77
- changes: Change[],
78
- replacedTableIds: ReadonlySet<string>,
79
- ): Change[] {
80
- if (replacedTableIds.size === 0) return changes;
81
-
82
- const keyFor = (change: Change): string | null => {
83
- if (
84
- !(change instanceof AlterTableAddConstraint) &&
85
- !(change instanceof AlterTableValidateConstraint) &&
86
- !(change instanceof CreateCommentOnConstraint)
87
- ) {
88
- return null;
89
- }
90
- if (!replacedTableIds.has(change.table.stableId)) return null;
91
- const tag =
92
- change instanceof AlterTableAddConstraint
93
- ? "add"
94
- : change instanceof AlterTableValidateConstraint
95
- ? "validate"
96
- : "comment";
97
- return `${tag}:${constraintStableId(change.table, change.constraint.name)}`;
98
- };
99
-
100
- const seen = new Set<string>();
101
- const reversedKept: Change[] = [];
102
- let mutated = false;
103
-
104
- // Walk backwards: the first encounter of each key corresponds to its LAST
105
- // occurrence in the original order. `expandReplaceDependencies()` appends
106
- // additions after the original changes, so "last wins" keeps the
107
- // expansion's emission and drops the earlier diffTables duplicate.
108
- for (let i = changes.length - 1; i >= 0; i--) {
109
- const change = changes[i] as Change;
110
- const key = keyFor(change);
111
- if (key !== null) {
112
- if (seen.has(key)) {
113
- mutated = true;
114
- continue;
115
- }
116
- seen.add(key);
117
- }
118
- reversedKept.push(change);
119
- }
120
-
121
- return mutated ? reversedKept.reverse() : changes;
122
- }
123
-
124
- function collectExplicitConstraintDropIds(changes: Change[]) {
125
- const explicitConstraintDropIds = new Set<string>();
126
-
127
- for (const change of changes) {
128
- if (!(change instanceof AlterTableDropConstraint)) continue;
129
- explicitConstraintDropIds.add(
130
- constraintStableId(change.table, change.constraint.name),
131
- );
132
- }
133
-
134
- return explicitConstraintDropIds;
135
- }
136
-
137
- function hasSameEntries(
138
- left: ReadonlySet<string>,
139
- right: ReadonlySet<string>,
140
- ): boolean {
141
- if (left.size !== right.size) return false;
142
- for (const value of left) {
143
- if (!right.has(value)) return false;
144
- }
145
- return true;
146
- }
147
-
148
- /**
149
- * Normalize change-list cycles that only become apparent after all object
150
- * diffs have been collected.
151
- *
152
- * This pass intentionally handles whole-plan interactions only:
153
- * - If replace expansion added `DropTable(T)+CreateTable(T)`, targeted
154
- * `AlterTableDropColumn(T.*)` / `AlterTableDropConstraint(T.*)` changes are
155
- * redundant and create an unbreakable drop-phase cycle, so we elide them.
156
- * - When the same `DropTable+CreateTable` pair is present, the expansion
157
- * also emits one `AlterTableAddConstraint` / `AlterTableValidateConstraint`
158
- * / `CreateCommentOnConstraint` per branch constraint, which may collide
159
- * with the same change already emitted by `diffTables()` (for example on a
160
- * shape flip or a new constraint). We dedupe these keeping only the last
161
- * occurrence so the expansion's emission survives and the diffTables
162
- * duplicate is removed.
163
- * - If two dropped tables reference each other via FK, we insert dedicated
164
- * `AlterTableDropConstraint` changes and teach the paired `DropTable`
165
- * changes not to claim those FK stable IDs.
166
- *
167
- * Object-local PostgreSQL semantics (for example owned-sequence cascades) stay
168
- * in the corresponding `diff*` function instead of this pass.
169
- */
170
- export function normalizePostDiffCycles({
171
- changes,
172
- mainCatalog,
173
- replacedTableIds = new Set<string>(),
174
- }: {
175
- changes: Change[];
176
- mainCatalog: Catalog;
177
- replacedTableIds?: ReadonlySet<string>;
178
- }): Change[] {
179
- const dedupedChanges = dropReplacedTableDuplicateConstraintChanges(
180
- changes,
181
- replacedTableIds,
182
- );
183
-
184
- const structurallyNormalizedChanges =
185
- replacedTableIds.size === 0
186
- ? dedupedChanges
187
- : dedupedChanges.filter(
188
- (change) => !isSupersededByTableReplacement(change, replacedTableIds),
189
- );
190
-
191
- const dropTableChanges = structurallyNormalizedChanges.filter(
192
- (change): change is DropTable => change instanceof DropTable,
193
- );
194
-
195
- if (dropTableChanges.length < 2) {
196
- return structurallyNormalizedChanges;
197
- }
198
-
199
- const droppedSet = new Set(
200
- dropTableChanges.map((change) => change.table.stableId),
201
- );
202
- const droppedFkTargets = new Map<string, Set<string>>();
203
-
204
- for (const dropTableChange of dropTableChanges) {
205
- const mainTable =
206
- mainCatalog.tables[dropTableChange.table.stableId] ??
207
- dropTableChange.table;
208
- const targets = new Set<string>();
209
-
210
- for (const { referencedId } of iterCrossDropFkConstraints(
211
- mainTable,
212
- droppedSet,
213
- )) {
214
- targets.add(referencedId);
215
- }
216
-
217
- droppedFkTargets.set(mainTable.stableId, targets);
218
- }
219
-
220
- const explicitConstraintDropIds = collectExplicitConstraintDropIds(
221
- structurallyNormalizedChanges,
222
- );
223
- const injectedConstraintDropsByTableId = new Map<
224
- string,
225
- AlterTableDropConstraint[]
226
- >();
227
- const externallyDroppedConstraintsByTableId = new Map<
228
- string,
229
- ReadonlySet<string>
230
- >();
231
- let didMutate = structurallyNormalizedChanges !== changes;
232
-
233
- for (const dropTableChange of dropTableChanges) {
234
- const mainTable =
235
- mainCatalog.tables[dropTableChange.table.stableId] ??
236
- dropTableChange.table;
237
- const externallyDroppedConstraints = new Set(
238
- dropTableChange.externallyDroppedConstraints,
239
- );
240
-
241
- for (const { constraint, referencedId } of iterCrossDropFkConstraints(
242
- mainTable,
243
- droppedSet,
244
- )) {
245
- const isMutual =
246
- droppedFkTargets.get(referencedId)?.has(mainTable.stableId) === true;
247
- if (!isMutual) continue;
248
-
249
- const droppedConstraintStableId = constraintStableId(
250
- mainTable,
251
- constraint.name,
252
- );
253
- externallyDroppedConstraints.add(constraint.name);
254
-
255
- if (!explicitConstraintDropIds.has(droppedConstraintStableId)) {
256
- const injectedDrop = new AlterTableDropConstraint({
257
- table: mainTable,
258
- constraint,
259
- });
260
- const existingDrops =
261
- injectedConstraintDropsByTableId.get(mainTable.stableId) ?? [];
262
- existingDrops.push(injectedDrop);
263
- injectedConstraintDropsByTableId.set(mainTable.stableId, existingDrops);
264
- explicitConstraintDropIds.add(droppedConstraintStableId);
265
- didMutate = true;
266
- }
267
- }
268
-
269
- if (
270
- !hasSameEntries(
271
- dropTableChange.externallyDroppedConstraints,
272
- externallyDroppedConstraints,
273
- )
274
- ) {
275
- externallyDroppedConstraintsByTableId.set(
276
- mainTable.stableId,
277
- externallyDroppedConstraints,
278
- );
279
- didMutate = true;
280
- }
281
- }
282
-
283
- if (!didMutate) {
284
- return changes;
285
- }
286
-
287
- const normalizedChanges: Change[] = [];
288
-
289
- for (const change of structurallyNormalizedChanges) {
290
- if (!(change instanceof DropTable)) {
291
- normalizedChanges.push(change);
292
- continue;
293
- }
294
-
295
- const injectedConstraintDrops =
296
- injectedConstraintDropsByTableId.get(change.table.stableId) ?? [];
297
- if (injectedConstraintDrops.length > 0) {
298
- normalizedChanges.push(...injectedConstraintDrops);
299
- }
300
-
301
- const externallyDroppedConstraints =
302
- externallyDroppedConstraintsByTableId.get(change.table.stableId);
303
- if (!externallyDroppedConstraints) {
304
- normalizedChanges.push(change);
305
- continue;
306
- }
307
-
308
- normalizedChanges.push(
309
- new DropTable({
310
- table: change.table,
311
- externallyDroppedConstraints,
312
- }),
313
- );
314
- }
315
-
316
- return normalizedChanges;
317
- }