@prisma-next/family-sql 0.12.0-dev.17 → 0.12.0-dev.2

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 (34) hide show
  1. package/dist/control-adapter.d.mts +109 -2
  2. package/dist/control-adapter.d.mts.map +1 -0
  3. package/dist/control.d.mts +2 -2
  4. package/dist/control.mjs +13 -20
  5. package/dist/control.mjs.map +1 -1
  6. package/dist/migration.d.mts +1 -1
  7. package/dist/runtime.d.mts +1 -3
  8. package/dist/runtime.d.mts.map +1 -1
  9. package/dist/runtime.mjs +1 -3
  10. package/dist/runtime.mjs.map +1 -1
  11. package/dist/schema-verify.d.mts +1 -1
  12. package/dist/schema-verify.d.mts.map +1 -1
  13. package/dist/schema-verify.mjs +1 -1
  14. package/dist/{types-BQiqw6kR.d.mts → types-CeeCStqw.d.mts} +5 -14
  15. package/dist/types-CeeCStqw.d.mts.map +1 -0
  16. package/dist/{verify-sql-schema-Cj3c2t5Z.d.mts → verify-sql-schema-CN7pPoTC.d.mts} +2 -8
  17. package/dist/verify-sql-schema-CN7pPoTC.d.mts.map +1 -0
  18. package/dist/{verify-sql-schema-CXW_D9dW.mjs → verify-sql-schema-CYLsGCFO.mjs} +310 -403
  19. package/dist/verify-sql-schema-CYLsGCFO.mjs.map +1 -0
  20. package/package.json +21 -21
  21. package/src/core/control-adapter.ts +3 -44
  22. package/src/core/control-instance.ts +41 -40
  23. package/src/core/migrations/types.ts +1 -8
  24. package/src/core/schema-verify/verify-helpers.ts +110 -151
  25. package/src/core/schema-verify/verify-sql-schema.ts +155 -291
  26. package/src/exports/runtime.ts +0 -7
  27. package/dist/control-adapter-8tV9WgWK.d.mts +0 -134
  28. package/dist/control-adapter-8tV9WgWK.d.mts.map +0 -1
  29. package/dist/types-BQiqw6kR.d.mts.map +0 -1
  30. package/dist/verify-sql-schema-CXW_D9dW.mjs.map +0 -1
  31. package/dist/verify-sql-schema-Cj3c2t5Z.d.mts.map +0 -1
  32. package/src/core/default-namespace.ts +0 -9
  33. package/src/core/schema-verify/control-verify-emit.ts +0 -46
  34. package/src/core/schema-verify/verifier-disposition.ts +0 -53
@@ -3,7 +3,6 @@
3
3
  * These functions verify schema IR against contract requirements.
4
4
  */
5
5
 
6
- import type { ControlPolicy } from '@prisma-next/contract/types';
7
6
  import type {
8
7
  SchemaIssue,
9
8
  SchemaVerificationNode,
@@ -16,10 +15,6 @@ import type {
16
15
  UniqueConstraint,
17
16
  } from '@prisma-next/sql-contract/types';
18
17
  import type { SqlForeignKeyIR, SqlIndexIR, SqlUniqueIR } from '@prisma-next/sql-schema-ir/types';
19
- import {
20
- emitIssueAndNodeUnderControlPolicy,
21
- emitIssueUnderControlPolicy,
22
- } from './control-verify-emit';
23
18
 
24
19
  function indexOptionsLooselyEqual(
25
20
  a: Record<string, unknown> | undefined,
@@ -140,34 +135,34 @@ export function verifyPrimaryKey(
140
135
  schemaPK: PrimaryKey | undefined,
141
136
  tableName: string,
142
137
  namespaceId: string,
143
- tableControlPolicy: ControlPolicy,
144
138
  issues: SchemaIssue[],
145
- ): 'pass' | 'warn' | 'fail' {
139
+ ): 'pass' | 'fail' {
146
140
  if (!schemaPK) {
147
- const issue: SchemaIssue = {
141
+ issues.push({
148
142
  kind: 'primary_key_mismatch',
149
143
  table: tableName,
150
144
  namespaceId,
151
145
  expected: contractPK.columns.join(', '),
152
146
  message: `Table "${tableName}" is missing primary key`,
153
- };
154
- const outcome = emitIssueUnderControlPolicy(tableControlPolicy, issue, issues);
155
- return outcome === 'suppress' ? 'pass' : outcome;
147
+ });
148
+ return 'fail';
156
149
  }
157
150
 
158
151
  if (!arraysEqual(contractPK.columns, schemaPK.columns)) {
159
- const issue: SchemaIssue = {
152
+ issues.push({
160
153
  kind: 'primary_key_mismatch',
161
154
  table: tableName,
162
155
  namespaceId,
163
156
  expected: contractPK.columns.join(', '),
164
157
  actual: schemaPK.columns.join(', '),
165
158
  message: `Table "${tableName}" has primary key mismatch: expected columns [${contractPK.columns.join(', ')}], got [${schemaPK.columns.join(', ')}]`,
166
- };
167
- const outcome = emitIssueUnderControlPolicy(tableControlPolicy, issue, issues);
168
- return outcome === 'suppress' ? 'pass' : outcome;
159
+ });
160
+ return 'fail';
169
161
  }
170
162
 
163
+ // Name differences are ignored for semantic satisfaction.
164
+ // Names are persisted for deterministic DDL and diagnostics but are not identity.
165
+
171
166
  return 'pass';
172
167
  }
173
168
 
@@ -184,7 +179,6 @@ export function verifyForeignKeys(
184
179
  tableName: string,
185
180
  namespaceId: string,
186
181
  tablePath: string,
187
- tableControlPolicy: ControlPolicy,
188
182
  issues: SchemaIssue[],
189
183
  strict: boolean,
190
184
  ): SchemaVerificationNode[] {
@@ -213,62 +207,52 @@ export function verifyForeignKeys(
213
207
  });
214
208
 
215
209
  if (!matchingFK) {
216
- const issue: SchemaIssue = {
210
+ issues.push({
217
211
  kind: 'foreign_key_mismatch',
218
212
  table: tableName,
219
213
  namespaceId,
220
214
  expected: `${contractFK.source.columns.join(', ')} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(', ')})`,
221
215
  message: `Table "${tableName}" is missing foreign key: ${contractFK.source.columns.join(', ')} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(', ')})`,
222
- };
223
- emitIssueAndNodeUnderControlPolicy(
224
- tableControlPolicy,
225
- issue,
226
- {
227
- status: 'fail',
228
- kind: 'foreignKey',
229
- name: `foreignKey(${contractFK.source.columns.join(', ')})`,
230
- contractPath: fkPath,
231
- code: 'foreign_key_mismatch',
232
- message: 'Foreign key missing',
233
- expected: contractFK,
234
- actual: undefined,
235
- children: [],
236
- },
237
- issues,
238
- nodes,
239
- );
216
+ });
217
+ nodes.push({
218
+ status: 'fail',
219
+ kind: 'foreignKey',
220
+ name: `foreignKey(${contractFK.source.columns.join(', ')})`,
221
+ contractPath: fkPath,
222
+ code: 'foreign_key_mismatch',
223
+ message: 'Foreign key missing',
224
+ expected: contractFK,
225
+ actual: undefined,
226
+ children: [],
227
+ });
240
228
  } else {
241
229
  const actionMismatches = getReferentialActionMismatches(contractFK, matchingFK);
242
230
  if (actionMismatches.length > 0) {
243
231
  const combinedMessage = actionMismatches.map((m) => m.message).join('; ');
244
232
  const combinedExpected = actionMismatches.map((m) => m.expected).join(', ');
245
233
  const combinedActual = actionMismatches.map((m) => m.actual).join(', ');
246
- const issue: SchemaIssue = {
234
+ issues.push({
247
235
  kind: 'foreign_key_mismatch',
248
236
  table: tableName,
249
237
  namespaceId,
238
+ // Set indexOrConstraint so the planner classifies this as a non-additive
239
+ // conflict (existing FK with wrong actions cannot be fixed additively).
250
240
  indexOrConstraint: matchingFK.name ?? `fk(${contractFK.source.columns.join(',')})`,
251
241
  expected: combinedExpected,
252
242
  actual: combinedActual,
253
243
  message: `Table "${tableName}" foreign key ${contractFK.source.columns.join(', ')} -> ${contractFK.target.tableName}: ${combinedMessage}`,
254
- };
255
- emitIssueAndNodeUnderControlPolicy(
256
- tableControlPolicy,
257
- issue,
258
- {
259
- status: 'fail',
260
- kind: 'foreignKey',
261
- name: `foreignKey(${contractFK.source.columns.join(', ')})`,
262
- contractPath: fkPath,
263
- code: 'foreign_key_mismatch',
264
- message: combinedMessage,
265
- expected: contractFK,
266
- actual: matchingFK,
267
- children: [],
268
- },
269
- issues,
270
- nodes,
271
- );
244
+ });
245
+ nodes.push({
246
+ status: 'fail',
247
+ kind: 'foreignKey',
248
+ name: `foreignKey(${contractFK.source.columns.join(', ')})`,
249
+ contractPath: fkPath,
250
+ code: 'foreign_key_mismatch',
251
+ message: combinedMessage,
252
+ expected: contractFK,
253
+ actual: matchingFK,
254
+ children: [],
255
+ });
272
256
  } else {
273
257
  nodes.push({
274
258
  status: 'pass',
@@ -302,30 +286,24 @@ export function verifyForeignKeys(
302
286
  });
303
287
 
304
288
  if (!matchingFK) {
305
- const issue: SchemaIssue = {
289
+ issues.push({
306
290
  kind: 'extra_foreign_key',
307
291
  table: tableName,
308
292
  namespaceId,
309
293
  indexOrConstraint: schemaFK.name ?? `fk(${schemaFK.columns.join(',')})`,
310
294
  message: `Extra foreign key found in database (not in contract): ${schemaFK.columns.join(', ')} -> ${schemaFK.referencedTable}(${schemaFK.referencedColumns.join(', ')})`,
311
- };
312
- emitIssueAndNodeUnderControlPolicy(
313
- tableControlPolicy,
314
- issue,
315
- {
316
- status: 'fail',
317
- kind: 'foreignKey',
318
- name: `foreignKey(${schemaFK.columns.join(', ')})`,
319
- contractPath: `${tablePath}.foreignKeys[${schemaFK.columns.join(',')}]`,
320
- code: 'extra_foreign_key',
321
- message: 'Extra foreign key found',
322
- expected: undefined,
323
- actual: schemaFK,
324
- children: [],
325
- },
326
- issues,
327
- nodes,
328
- );
295
+ });
296
+ nodes.push({
297
+ status: 'fail',
298
+ kind: 'foreignKey',
299
+ name: `foreignKey(${schemaFK.columns.join(', ')})`,
300
+ contractPath: `${tablePath}.foreignKeys[${schemaFK.columns.join(',')}]`,
301
+ code: 'extra_foreign_key',
302
+ message: 'Extra foreign key found',
303
+ expected: undefined,
304
+ actual: schemaFK,
305
+ children: [],
306
+ });
329
307
  }
330
308
  }
331
309
  }
@@ -351,7 +329,6 @@ export function verifyUniqueConstraints(
351
329
  tableName: string,
352
330
  namespaceId: string,
353
331
  tablePath: string,
354
- tableControlPolicy: ControlPolicy,
355
332
  issues: SchemaIssue[],
356
333
  strict: boolean,
357
334
  ): SchemaVerificationNode[] {
@@ -372,31 +349,27 @@ export function verifyUniqueConstraints(
372
349
  schemaIndexes.find((idx) => idx.unique && arraysEqual(idx.columns, contractUnique.columns));
373
350
 
374
351
  if (!matchingUnique && !matchingUniqueIndex) {
375
- const issue: SchemaIssue = {
352
+ issues.push({
376
353
  kind: 'unique_constraint_mismatch',
377
354
  table: tableName,
378
355
  namespaceId,
379
356
  expected: contractUnique.columns.join(', '),
380
357
  message: `Table "${tableName}" is missing unique constraint: ${contractUnique.columns.join(', ')}`,
381
- };
382
- emitIssueAndNodeUnderControlPolicy(
383
- tableControlPolicy,
384
- issue,
385
- {
386
- status: 'fail',
387
- kind: 'unique',
388
- name: `unique(${contractUnique.columns.join(', ')})`,
389
- contractPath: uniquePath,
390
- code: 'unique_constraint_mismatch',
391
- message: 'Unique constraint missing',
392
- expected: contractUnique,
393
- actual: undefined,
394
- children: [],
395
- },
396
- issues,
397
- nodes,
398
- );
358
+ });
359
+ nodes.push({
360
+ status: 'fail',
361
+ kind: 'unique',
362
+ name: `unique(${contractUnique.columns.join(', ')})`,
363
+ contractPath: uniquePath,
364
+ code: 'unique_constraint_mismatch',
365
+ message: 'Unique constraint missing',
366
+ expected: contractUnique,
367
+ actual: undefined,
368
+ children: [],
369
+ });
399
370
  } else {
371
+ // Name differences are ignored for semantic satisfaction.
372
+ // Names are persisted for deterministic DDL and diagnostics but are not identity.
400
373
  nodes.push({
401
374
  status: 'pass',
402
375
  kind: 'unique',
@@ -411,6 +384,7 @@ export function verifyUniqueConstraints(
411
384
  }
412
385
  }
413
386
 
387
+ // Check for extra uniques in strict mode
414
388
  if (strict) {
415
389
  for (const schemaUnique of schemaUniques) {
416
390
  const matchingUnique = contractUniques.find((u) =>
@@ -418,30 +392,24 @@ export function verifyUniqueConstraints(
418
392
  );
419
393
 
420
394
  if (!matchingUnique) {
421
- const issue: SchemaIssue = {
395
+ issues.push({
422
396
  kind: 'extra_unique_constraint',
423
397
  table: tableName,
424
398
  namespaceId,
425
399
  indexOrConstraint: schemaUnique.name ?? `unique(${schemaUnique.columns.join(',')})`,
426
400
  message: `Extra unique constraint found in database (not in contract): ${schemaUnique.columns.join(', ')}`,
427
- };
428
- emitIssueAndNodeUnderControlPolicy(
429
- tableControlPolicy,
430
- issue,
431
- {
432
- status: 'fail',
433
- kind: 'unique',
434
- name: `unique(${schemaUnique.columns.join(', ')})`,
435
- contractPath: `${tablePath}.uniques[${schemaUnique.columns.join(',')}]`,
436
- code: 'extra_unique_constraint',
437
- message: 'Extra unique constraint found',
438
- expected: undefined,
439
- actual: schemaUnique,
440
- children: [],
441
- },
442
- issues,
443
- nodes,
444
- );
401
+ });
402
+ nodes.push({
403
+ status: 'fail',
404
+ kind: 'unique',
405
+ name: `unique(${schemaUnique.columns.join(', ')})`,
406
+ contractPath: `${tablePath}.uniques[${schemaUnique.columns.join(',')}]`,
407
+ code: 'extra_unique_constraint',
408
+ message: 'Extra unique constraint found',
409
+ expected: undefined,
410
+ actual: schemaUnique,
411
+ children: [],
412
+ });
445
413
  }
446
414
  }
447
415
  }
@@ -467,7 +435,6 @@ export function verifyIndexes(
467
435
  tableName: string,
468
436
  namespaceId: string,
469
437
  tablePath: string,
470
- tableControlPolicy: ControlPolicy,
471
438
  issues: SchemaIssue[],
472
439
  strict: boolean,
473
440
  ): SchemaVerificationNode[] {
@@ -494,31 +461,27 @@ export function verifyIndexes(
494
461
  schemaUniques.find((u) => arraysEqual(u.columns, contractIndex.columns));
495
462
 
496
463
  if (!matchingIndex && !matchingUniqueConstraint) {
497
- const issue: SchemaIssue = {
464
+ issues.push({
498
465
  kind: 'index_mismatch',
499
466
  table: tableName,
500
467
  namespaceId,
501
468
  expected: contractIndex.columns.join(', '),
502
469
  message: `Table "${tableName}" is missing index: ${contractIndex.columns.join(', ')}`,
503
- };
504
- emitIssueAndNodeUnderControlPolicy(
505
- tableControlPolicy,
506
- issue,
507
- {
508
- status: 'fail',
509
- kind: 'index',
510
- name: `index(${contractIndex.columns.join(', ')})`,
511
- contractPath: indexPath,
512
- code: 'index_mismatch',
513
- message: 'Index missing',
514
- expected: contractIndex,
515
- actual: undefined,
516
- children: [],
517
- },
518
- issues,
519
- nodes,
520
- );
470
+ });
471
+ nodes.push({
472
+ status: 'fail',
473
+ kind: 'index',
474
+ name: `index(${contractIndex.columns.join(', ')})`,
475
+ contractPath: indexPath,
476
+ code: 'index_mismatch',
477
+ message: 'Index missing',
478
+ expected: contractIndex,
479
+ actual: undefined,
480
+ children: [],
481
+ });
521
482
  } else {
483
+ // Name differences are ignored for semantic satisfaction.
484
+ // Names are persisted for deterministic DDL and diagnostics but are not identity.
522
485
  nodes.push({
523
486
  status: 'pass',
524
487
  kind: 'index',
@@ -533,8 +496,10 @@ export function verifyIndexes(
533
496
  }
534
497
  }
535
498
 
499
+ // Check for extra indexes in strict mode
536
500
  if (strict) {
537
501
  for (const schemaIndex of schemaIndexes) {
502
+ // Skip unique indexes (they're handled as unique constraints)
538
503
  if (schemaIndex.unique) {
539
504
  continue;
540
505
  }
@@ -545,30 +510,24 @@ export function verifyIndexes(
545
510
  );
546
511
 
547
512
  if (!matchingIndex) {
548
- const issue: SchemaIssue = {
513
+ issues.push({
549
514
  kind: 'extra_index',
550
515
  table: tableName,
551
516
  namespaceId,
552
517
  indexOrConstraint: schemaIndex.name ?? `idx(${schemaIndex.columns.join(',')})`,
553
518
  message: `Extra index found in database (not in contract): ${schemaIndex.columns.join(', ')}`,
554
- };
555
- emitIssueAndNodeUnderControlPolicy(
556
- tableControlPolicy,
557
- issue,
558
- {
559
- status: 'fail',
560
- kind: 'index',
561
- name: `index(${schemaIndex.columns.join(', ')})`,
562
- contractPath: `${tablePath}.indexes[${schemaIndex.columns.join(',')}]`,
563
- code: 'extra_index',
564
- message: 'Extra index found',
565
- expected: undefined,
566
- actual: schemaIndex,
567
- children: [],
568
- },
569
- issues,
570
- nodes,
571
- );
519
+ });
520
+ nodes.push({
521
+ status: 'fail',
522
+ kind: 'index',
523
+ name: `index(${schemaIndex.columns.join(', ')})`,
524
+ contractPath: `${tablePath}.indexes[${schemaIndex.columns.join(',')}]`,
525
+ code: 'extra_index',
526
+ message: 'Extra index found',
527
+ expected: undefined,
528
+ actual: schemaIndex,
529
+ children: [],
530
+ });
572
531
  }
573
532
  }
574
533
  }