@prisma-next/family-sql 0.3.0-dev.5 → 0.3.0-dev.53
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 +12 -6
- package/dist/assembly-BVS641kd.mjs +106 -0
- package/dist/assembly-BVS641kd.mjs.map +1 -0
- package/dist/control-adapter.d.mts +60 -0
- package/dist/control-adapter.d.mts.map +1 -0
- package/dist/control-adapter.mjs +1 -0
- package/dist/control-instance-CWKSpACr.d.mts +292 -0
- package/dist/control-instance-CWKSpACr.d.mts.map +1 -0
- package/dist/control.d.mts +64 -0
- package/dist/control.d.mts.map +1 -0
- package/dist/control.mjs +536 -0
- package/dist/control.mjs.map +1 -0
- package/dist/runtime.d.mts +27 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +38 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/schema-verify.d.mts +48 -0
- package/dist/schema-verify.d.mts.map +1 -0
- package/dist/schema-verify.mjs +3 -0
- package/dist/test-utils.d.mts +2 -0
- package/dist/test-utils.mjs +3 -0
- package/dist/verify-BfMETJcM.mjs +108 -0
- package/dist/verify-BfMETJcM.mjs.map +1 -0
- package/dist/verify-sql-schema-CpAVEi8A.mjs +1058 -0
- package/dist/verify-sql-schema-CpAVEi8A.mjs.map +1 -0
- package/dist/verify-sql-schema-DhHnkpPa.d.mts +67 -0
- package/dist/verify-sql-schema-DhHnkpPa.d.mts.map +1 -0
- package/dist/verify.d.mts +31 -0
- package/dist/verify.d.mts.map +1 -0
- package/dist/verify.mjs +3 -0
- package/package.json +36 -47
- package/src/core/assembly.ts +158 -59
- package/src/core/control-adapter.ts +15 -0
- package/src/core/control-descriptor.ts +37 -0
- package/src/core/{instance.ts → control-instance.ts} +108 -241
- package/src/core/migrations/types.ts +62 -163
- package/src/core/runtime-descriptor.ts +19 -41
- package/src/core/runtime-instance.ts +11 -133
- package/src/core/schema-verify/verify-helpers.ts +187 -97
- package/src/core/schema-verify/verify-sql-schema.ts +910 -392
- package/src/core/verify.ts +4 -13
- package/src/exports/control.ts +9 -6
- package/src/exports/runtime.ts +2 -6
- package/src/exports/schema-verify.ts +10 -2
- package/src/exports/test-utils.ts +0 -1
- package/dist/chunk-6K3RPBDP.js +0 -580
- package/dist/chunk-6K3RPBDP.js.map +0 -1
- package/dist/chunk-BHEGVBY7.js +0 -772
- package/dist/chunk-BHEGVBY7.js.map +0 -1
- package/dist/chunk-SU7LN2UH.js +0 -96
- package/dist/chunk-SU7LN2UH.js.map +0 -1
- package/dist/core/assembly.d.ts +0 -25
- package/dist/core/assembly.d.ts.map +0 -1
- package/dist/core/control-adapter.d.ts +0 -42
- package/dist/core/control-adapter.d.ts.map +0 -1
- package/dist/core/descriptor.d.ts +0 -31
- package/dist/core/descriptor.d.ts.map +0 -1
- package/dist/core/instance.d.ts +0 -142
- package/dist/core/instance.d.ts.map +0 -1
- package/dist/core/migrations/plan-helpers.d.ts +0 -20
- package/dist/core/migrations/plan-helpers.d.ts.map +0 -1
- package/dist/core/migrations/policies.d.ts +0 -6
- package/dist/core/migrations/policies.d.ts.map +0 -1
- package/dist/core/migrations/types.d.ts +0 -280
- package/dist/core/migrations/types.d.ts.map +0 -1
- package/dist/core/runtime-descriptor.d.ts +0 -19
- package/dist/core/runtime-descriptor.d.ts.map +0 -1
- package/dist/core/runtime-instance.d.ts +0 -54
- package/dist/core/runtime-instance.d.ts.map +0 -1
- package/dist/core/schema-verify/verify-helpers.d.ts +0 -50
- package/dist/core/schema-verify/verify-helpers.d.ts.map +0 -1
- package/dist/core/schema-verify/verify-sql-schema.d.ts +0 -45
- package/dist/core/schema-verify/verify-sql-schema.d.ts.map +0 -1
- package/dist/core/verify.d.ts +0 -39
- package/dist/core/verify.d.ts.map +0 -1
- package/dist/exports/control-adapter.d.ts +0 -2
- package/dist/exports/control-adapter.d.ts.map +0 -1
- package/dist/exports/control-adapter.js +0 -1
- package/dist/exports/control-adapter.js.map +0 -1
- package/dist/exports/control.d.ts +0 -13
- package/dist/exports/control.d.ts.map +0 -1
- package/dist/exports/control.js +0 -149
- package/dist/exports/control.js.map +0 -1
- package/dist/exports/runtime.d.ts +0 -8
- package/dist/exports/runtime.d.ts.map +0 -1
- package/dist/exports/runtime.js +0 -64
- package/dist/exports/runtime.js.map +0 -1
- package/dist/exports/schema-verify.d.ts +0 -11
- package/dist/exports/schema-verify.d.ts.map +0 -1
- package/dist/exports/schema-verify.js +0 -11
- package/dist/exports/schema-verify.js.map +0 -1
- package/dist/exports/test-utils.d.ts +0 -7
- package/dist/exports/test-utils.d.ts.map +0 -1
- package/dist/exports/test-utils.js +0 -17
- package/dist/exports/test-utils.js.map +0 -1
- package/dist/exports/verify.d.ts +0 -2
- package/dist/exports/verify.d.ts.map +0 -1
- package/dist/exports/verify.js +0 -11
- package/dist/exports/verify.js.map +0 -1
- package/src/core/descriptor.ts +0 -37
|
@@ -33,9 +33,71 @@ export function arraysEqual(a: readonly string[], b: readonly string[]): boolean
|
|
|
33
33
|
return true;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Semantic Satisfaction Predicates
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// These predicates implement the "stronger satisfies weaker" logic for storage
|
|
40
|
+
// objects. They are used by both verification and migration planning to ensure
|
|
41
|
+
// consistent behavior across the control plane.
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if a unique constraint requirement is satisfied by the given columns.
|
|
45
|
+
*
|
|
46
|
+
* Semantic satisfaction: a unique constraint requirement can be satisfied by:
|
|
47
|
+
* - A unique constraint with the same columns, OR
|
|
48
|
+
* - A unique index with the same columns
|
|
49
|
+
*
|
|
50
|
+
* @param uniques - The unique constraints in the schema table
|
|
51
|
+
* @param indexes - The indexes in the schema table
|
|
52
|
+
* @param columns - The columns required by the unique constraint
|
|
53
|
+
* @returns true if the requirement is satisfied
|
|
54
|
+
*/
|
|
55
|
+
export function isUniqueConstraintSatisfied(
|
|
56
|
+
uniques: readonly SqlUniqueIR[],
|
|
57
|
+
indexes: readonly SqlIndexIR[],
|
|
58
|
+
columns: readonly string[],
|
|
59
|
+
): boolean {
|
|
60
|
+
// Check for matching unique constraint
|
|
61
|
+
const hasConstraint = uniques.some((unique) => arraysEqual(unique.columns, columns));
|
|
62
|
+
if (hasConstraint) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
// Check for matching unique index (semantic satisfaction)
|
|
66
|
+
return indexes.some((index) => index.unique && arraysEqual(index.columns, columns));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Checks if an index requirement is satisfied by the given columns.
|
|
71
|
+
*
|
|
72
|
+
* Semantic satisfaction: a non-unique index requirement can be satisfied by:
|
|
73
|
+
* - Any index (unique or non-unique) with the same columns, OR
|
|
74
|
+
* - A unique constraint with the same columns (stronger satisfies weaker)
|
|
75
|
+
*
|
|
76
|
+
* @param indexes - The indexes in the schema table
|
|
77
|
+
* @param uniques - The unique constraints in the schema table
|
|
78
|
+
* @param columns - The columns required by the index
|
|
79
|
+
* @returns true if the requirement is satisfied
|
|
80
|
+
*/
|
|
81
|
+
export function isIndexSatisfied(
|
|
82
|
+
indexes: readonly SqlIndexIR[],
|
|
83
|
+
uniques: readonly SqlUniqueIR[],
|
|
84
|
+
columns: readonly string[],
|
|
85
|
+
): boolean {
|
|
86
|
+
// Check for any matching index (unique or non-unique)
|
|
87
|
+
const hasMatchingIndex = indexes.some((index) => arraysEqual(index.columns, columns));
|
|
88
|
+
if (hasMatchingIndex) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
// Check for matching unique constraint (semantic satisfaction)
|
|
92
|
+
return uniques.some((unique) => arraysEqual(unique.columns, columns));
|
|
93
|
+
}
|
|
94
|
+
|
|
36
95
|
/**
|
|
37
96
|
* Verifies primary key matches between contract and schema.
|
|
38
97
|
* Returns 'pass' or 'fail'.
|
|
98
|
+
*
|
|
99
|
+
* Uses semantic satisfaction: identity is based on (table + kind + columns).
|
|
100
|
+
* Name differences are ignored by default (names are for DDL/diagnostics, not identity).
|
|
39
101
|
*/
|
|
40
102
|
export function verifyPrimaryKey(
|
|
41
103
|
contractPK: PrimaryKey,
|
|
@@ -64,18 +126,8 @@ export function verifyPrimaryKey(
|
|
|
64
126
|
return 'fail';
|
|
65
127
|
}
|
|
66
128
|
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
issues.push({
|
|
70
|
-
kind: 'primary_key_mismatch',
|
|
71
|
-
table: tableName,
|
|
72
|
-
indexOrConstraint: contractPK.name,
|
|
73
|
-
expected: contractPK.name,
|
|
74
|
-
actual: schemaPK.name,
|
|
75
|
-
message: `Table "${tableName}" has primary key name mismatch: expected "${contractPK.name}", got "${schemaPK.name}"`,
|
|
76
|
-
});
|
|
77
|
-
return 'fail';
|
|
78
|
-
}
|
|
129
|
+
// Name differences are ignored for semantic satisfaction.
|
|
130
|
+
// Names are persisted for deterministic DDL and diagnostics but are not identity.
|
|
79
131
|
|
|
80
132
|
return 'pass';
|
|
81
133
|
}
|
|
@@ -83,6 +135,9 @@ export function verifyPrimaryKey(
|
|
|
83
135
|
/**
|
|
84
136
|
* Verifies foreign keys match between contract and schema.
|
|
85
137
|
* Returns verification nodes for the tree.
|
|
138
|
+
*
|
|
139
|
+
* Uses semantic satisfaction: identity is based on (table + columns + referenced table + referenced columns).
|
|
140
|
+
* Name differences are ignored by default (names are for DDL/diagnostics, not identity).
|
|
86
141
|
*/
|
|
87
142
|
export function verifyForeignKeys(
|
|
88
143
|
contractFKs: readonly ForeignKey[],
|
|
@@ -124,15 +179,20 @@ export function verifyForeignKeys(
|
|
|
124
179
|
children: [],
|
|
125
180
|
});
|
|
126
181
|
} else {
|
|
127
|
-
|
|
128
|
-
if (
|
|
182
|
+
const actionMismatches = getReferentialActionMismatches(contractFK, matchingFK);
|
|
183
|
+
if (actionMismatches.length > 0) {
|
|
184
|
+
const combinedMessage = actionMismatches.map((m) => m.message).join('; ');
|
|
185
|
+
const combinedExpected = actionMismatches.map((m) => m.expected).join(', ');
|
|
186
|
+
const combinedActual = actionMismatches.map((m) => m.actual).join(', ');
|
|
129
187
|
issues.push({
|
|
130
188
|
kind: 'foreign_key_mismatch',
|
|
131
189
|
table: tableName,
|
|
132
|
-
indexOrConstraint
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
190
|
+
// Set indexOrConstraint so the planner classifies this as a non-additive
|
|
191
|
+
// conflict (existing FK with wrong actions cannot be fixed additively).
|
|
192
|
+
indexOrConstraint: matchingFK.name ?? `fk(${contractFK.columns.join(',')})`,
|
|
193
|
+
expected: combinedExpected,
|
|
194
|
+
actual: combinedActual,
|
|
195
|
+
message: `Table "${tableName}" foreign key ${contractFK.columns.join(', ')} -> ${contractFK.references.table}: ${combinedMessage}`,
|
|
136
196
|
});
|
|
137
197
|
nodes.push({
|
|
138
198
|
status: 'fail',
|
|
@@ -140,9 +200,9 @@ export function verifyForeignKeys(
|
|
|
140
200
|
name: `foreignKey(${contractFK.columns.join(', ')})`,
|
|
141
201
|
contractPath: fkPath,
|
|
142
202
|
code: 'foreign_key_mismatch',
|
|
143
|
-
message:
|
|
144
|
-
expected: contractFK
|
|
145
|
-
actual: matchingFK
|
|
203
|
+
message: combinedMessage,
|
|
204
|
+
expected: contractFK,
|
|
205
|
+
actual: matchingFK,
|
|
146
206
|
children: [],
|
|
147
207
|
});
|
|
148
208
|
} else {
|
|
@@ -199,10 +259,18 @@ export function verifyForeignKeys(
|
|
|
199
259
|
/**
|
|
200
260
|
* Verifies unique constraints match between contract and schema.
|
|
201
261
|
* Returns verification nodes for the tree.
|
|
262
|
+
*
|
|
263
|
+
* Uses semantic satisfaction: identity is based on (table + kind + columns).
|
|
264
|
+
* A unique constraint requirement can be satisfied by either:
|
|
265
|
+
* - A unique constraint with the same columns, or
|
|
266
|
+
* - A unique index with the same columns
|
|
267
|
+
*
|
|
268
|
+
* Name differences are ignored by default (names are for DDL/diagnostics, not identity).
|
|
202
269
|
*/
|
|
203
270
|
export function verifyUniqueConstraints(
|
|
204
271
|
contractUniques: readonly UniqueConstraint[],
|
|
205
272
|
schemaUniques: readonly SqlUniqueIR[],
|
|
273
|
+
schemaIndexes: readonly SqlIndexIR[],
|
|
206
274
|
tableName: string,
|
|
207
275
|
tablePath: string,
|
|
208
276
|
issues: SchemaIssue[],
|
|
@@ -213,11 +281,18 @@ export function verifyUniqueConstraints(
|
|
|
213
281
|
// Check each contract unique exists in schema
|
|
214
282
|
for (const contractUnique of contractUniques) {
|
|
215
283
|
const uniquePath = `${tablePath}.uniques[${contractUnique.columns.join(',')}]`;
|
|
284
|
+
|
|
285
|
+
// First check for a matching unique constraint
|
|
216
286
|
const matchingUnique = schemaUniques.find((u) =>
|
|
217
287
|
arraysEqual(u.columns, contractUnique.columns),
|
|
218
288
|
);
|
|
219
289
|
|
|
220
|
-
|
|
290
|
+
// If no matching constraint, check for a unique index with the same columns
|
|
291
|
+
const matchingUniqueIndex =
|
|
292
|
+
!matchingUnique &&
|
|
293
|
+
schemaIndexes.find((idx) => idx.unique && arraysEqual(idx.columns, contractUnique.columns));
|
|
294
|
+
|
|
295
|
+
if (!matchingUnique && !matchingUniqueIndex) {
|
|
221
296
|
issues.push({
|
|
222
297
|
kind: 'unique_constraint_mismatch',
|
|
223
298
|
table: tableName,
|
|
@@ -236,44 +311,19 @@ export function verifyUniqueConstraints(
|
|
|
236
311
|
children: [],
|
|
237
312
|
});
|
|
238
313
|
} else {
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
});
|
|
253
|
-
nodes.push({
|
|
254
|
-
status: 'fail',
|
|
255
|
-
kind: 'unique',
|
|
256
|
-
name: `unique(${contractUnique.columns.join(', ')})`,
|
|
257
|
-
contractPath: uniquePath,
|
|
258
|
-
code: 'unique_constraint_mismatch',
|
|
259
|
-
message: 'Unique constraint name mismatch',
|
|
260
|
-
expected: contractUnique.name,
|
|
261
|
-
actual: matchingUnique.name,
|
|
262
|
-
children: [],
|
|
263
|
-
});
|
|
264
|
-
} else {
|
|
265
|
-
nodes.push({
|
|
266
|
-
status: 'pass',
|
|
267
|
-
kind: 'unique',
|
|
268
|
-
name: `unique(${contractUnique.columns.join(', ')})`,
|
|
269
|
-
contractPath: uniquePath,
|
|
270
|
-
code: '',
|
|
271
|
-
message: '',
|
|
272
|
-
expected: undefined,
|
|
273
|
-
actual: undefined,
|
|
274
|
-
children: [],
|
|
275
|
-
});
|
|
276
|
-
}
|
|
314
|
+
// Name differences are ignored for semantic satisfaction.
|
|
315
|
+
// Names are persisted for deterministic DDL and diagnostics but are not identity.
|
|
316
|
+
nodes.push({
|
|
317
|
+
status: 'pass',
|
|
318
|
+
kind: 'unique',
|
|
319
|
+
name: `unique(${contractUnique.columns.join(', ')})`,
|
|
320
|
+
contractPath: uniquePath,
|
|
321
|
+
code: '',
|
|
322
|
+
message: '',
|
|
323
|
+
expected: undefined,
|
|
324
|
+
actual: undefined,
|
|
325
|
+
children: [],
|
|
326
|
+
});
|
|
277
327
|
}
|
|
278
328
|
}
|
|
279
329
|
|
|
@@ -311,10 +361,18 @@ export function verifyUniqueConstraints(
|
|
|
311
361
|
/**
|
|
312
362
|
* Verifies indexes match between contract and schema.
|
|
313
363
|
* Returns verification nodes for the tree.
|
|
364
|
+
*
|
|
365
|
+
* Uses semantic satisfaction: identity is based on (table + kind + columns).
|
|
366
|
+
* A non-unique index requirement can be satisfied by either:
|
|
367
|
+
* - A non-unique index with the same columns, or
|
|
368
|
+
* - A unique index with the same columns (stronger satisfies weaker)
|
|
369
|
+
*
|
|
370
|
+
* Name differences are ignored by default (names are for DDL/diagnostics, not identity).
|
|
314
371
|
*/
|
|
315
372
|
export function verifyIndexes(
|
|
316
373
|
contractIndexes: readonly Index[],
|
|
317
374
|
schemaIndexes: readonly SqlIndexIR[],
|
|
375
|
+
schemaUniques: readonly SqlUniqueIR[],
|
|
318
376
|
tableName: string,
|
|
319
377
|
tablePath: string,
|
|
320
378
|
issues: SchemaIssue[],
|
|
@@ -325,11 +383,18 @@ export function verifyIndexes(
|
|
|
325
383
|
// Check each contract index exists in schema
|
|
326
384
|
for (const contractIndex of contractIndexes) {
|
|
327
385
|
const indexPath = `${tablePath}.indexes[${contractIndex.columns.join(',')}]`;
|
|
328
|
-
|
|
329
|
-
|
|
386
|
+
|
|
387
|
+
// Check for any matching index (unique or non-unique)
|
|
388
|
+
// A unique index can satisfy a non-unique index requirement (stronger satisfies weaker)
|
|
389
|
+
const matchingIndex = schemaIndexes.find((idx) =>
|
|
390
|
+
arraysEqual(idx.columns, contractIndex.columns),
|
|
330
391
|
);
|
|
331
392
|
|
|
332
|
-
if
|
|
393
|
+
// Also check if a unique constraint satisfies the index requirement
|
|
394
|
+
const matchingUniqueConstraint =
|
|
395
|
+
!matchingIndex && schemaUniques.find((u) => arraysEqual(u.columns, contractIndex.columns));
|
|
396
|
+
|
|
397
|
+
if (!matchingIndex && !matchingUniqueConstraint) {
|
|
333
398
|
issues.push({
|
|
334
399
|
kind: 'index_mismatch',
|
|
335
400
|
table: tableName,
|
|
@@ -348,40 +413,19 @@ export function verifyIndexes(
|
|
|
348
413
|
children: [],
|
|
349
414
|
});
|
|
350
415
|
} else {
|
|
351
|
-
//
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
name: `index(${contractIndex.columns.join(', ')})`,
|
|
365
|
-
contractPath: indexPath,
|
|
366
|
-
code: 'index_mismatch',
|
|
367
|
-
message: 'Index name mismatch',
|
|
368
|
-
expected: contractIndex.name,
|
|
369
|
-
actual: matchingIndex.name,
|
|
370
|
-
children: [],
|
|
371
|
-
});
|
|
372
|
-
} else {
|
|
373
|
-
nodes.push({
|
|
374
|
-
status: 'pass',
|
|
375
|
-
kind: 'index',
|
|
376
|
-
name: `index(${contractIndex.columns.join(', ')})`,
|
|
377
|
-
contractPath: indexPath,
|
|
378
|
-
code: '',
|
|
379
|
-
message: '',
|
|
380
|
-
expected: undefined,
|
|
381
|
-
actual: undefined,
|
|
382
|
-
children: [],
|
|
383
|
-
});
|
|
384
|
-
}
|
|
416
|
+
// Name differences are ignored for semantic satisfaction.
|
|
417
|
+
// Names are persisted for deterministic DDL and diagnostics but are not identity.
|
|
418
|
+
nodes.push({
|
|
419
|
+
status: 'pass',
|
|
420
|
+
kind: 'index',
|
|
421
|
+
name: `index(${contractIndex.columns.join(', ')})`,
|
|
422
|
+
contractPath: indexPath,
|
|
423
|
+
code: '',
|
|
424
|
+
message: '',
|
|
425
|
+
expected: undefined,
|
|
426
|
+
actual: undefined,
|
|
427
|
+
children: [],
|
|
428
|
+
});
|
|
385
429
|
}
|
|
386
430
|
}
|
|
387
431
|
|
|
@@ -512,3 +556,49 @@ export function computeCounts(node: SchemaVerificationNode): {
|
|
|
512
556
|
totalNodes: pass + warn + fail,
|
|
513
557
|
};
|
|
514
558
|
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Compares referential actions between a contract FK and a schema FK.
|
|
562
|
+
* Only compares when the contract FK explicitly specifies onDelete or onUpdate.
|
|
563
|
+
* Returns all mismatches (both onDelete and onUpdate) so both are reported at once.
|
|
564
|
+
*
|
|
565
|
+
* Note: 'noAction' in the contract is semantically equivalent to undefined in the
|
|
566
|
+
* schema IR, because the introspection adapter omits 'NO ACTION' (the database default)
|
|
567
|
+
* to keep the IR sparse. We normalize both sides before comparing.
|
|
568
|
+
*/
|
|
569
|
+
function getReferentialActionMismatches(
|
|
570
|
+
contractFK: ForeignKey,
|
|
571
|
+
schemaFK: SqlForeignKeyIR,
|
|
572
|
+
): ReadonlyArray<{ expected: string; actual: string; message: string }> {
|
|
573
|
+
const mismatches: Array<{ expected: string; actual: string; message: string }> = [];
|
|
574
|
+
|
|
575
|
+
const contractOnDelete = normalizeReferentialAction(contractFK.onDelete);
|
|
576
|
+
const schemaOnDelete = normalizeReferentialAction(schemaFK.onDelete);
|
|
577
|
+
if (contractOnDelete !== undefined && contractOnDelete !== schemaOnDelete) {
|
|
578
|
+
mismatches.push({
|
|
579
|
+
expected: `onDelete: ${contractFK.onDelete}`,
|
|
580
|
+
actual: `onDelete: ${schemaFK.onDelete ?? 'noAction (default)'}`,
|
|
581
|
+
message: `onDelete mismatch: expected ${contractFK.onDelete}, got ${schemaFK.onDelete ?? 'noAction (default)'}`,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const contractOnUpdate = normalizeReferentialAction(contractFK.onUpdate);
|
|
586
|
+
const schemaOnUpdate = normalizeReferentialAction(schemaFK.onUpdate);
|
|
587
|
+
if (contractOnUpdate !== undefined && contractOnUpdate !== schemaOnUpdate) {
|
|
588
|
+
mismatches.push({
|
|
589
|
+
expected: `onUpdate: ${contractFK.onUpdate}`,
|
|
590
|
+
actual: `onUpdate: ${schemaFK.onUpdate ?? 'noAction (default)'}`,
|
|
591
|
+
message: `onUpdate mismatch: expected ${contractFK.onUpdate}, got ${schemaFK.onUpdate ?? 'noAction (default)'}`,
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return mismatches;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Normalizes a referential action value for comparison.
|
|
600
|
+
* 'noAction' is the database default and equivalent to undefined (omitted) in the sparse IR.
|
|
601
|
+
*/
|
|
602
|
+
function normalizeReferentialAction(action: string | undefined): string | undefined {
|
|
603
|
+
return action === 'noAction' ? undefined : action;
|
|
604
|
+
}
|