@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
@@ -1,8 +1,7 @@
1
- import { assertUniqueCodecOwner, dispositionForCategory } from "@prisma-next/framework-components/control";
1
+ import { assertUniqueCodecOwner } from "@prisma-next/framework-components/control";
2
2
  import { ifDefined } from "@prisma-next/utils/defined";
3
3
  import { UNBOUND_NAMESPACE_ID } from "@prisma-next/framework-components/ir";
4
4
  import { StorageTable, isPostgresEnumStorageEntry, isStorageTypeInstance } from "@prisma-next/sql-contract/types";
5
- import { effectiveControlPolicy } from "@prisma-next/contract/types";
6
5
  import { canonicalStringify } from "@prisma-next/utils/canonical-stringify";
7
6
  //#region src/core/assembly.ts
8
7
  function hasCodecControlHooks(descriptor) {
@@ -32,71 +31,6 @@ function extractCodecControlHooks(descriptors) {
32
31
  return hooks;
33
32
  }
34
33
  //#endregion
35
- //#region src/core/schema-verify/verifier-disposition.ts
36
- /**
37
- * Classifies the relational verifier issue kinds the SQL family emits (tables,
38
- * columns, constraints, indexes, defaults, enum types) into the target-neutral
39
- * categories the framework grades. The relational vocabulary lives here, in the
40
- * SQL domain — the framework never switches over `extra_foreign_key` and friends.
41
- */
42
- function classifySqlVerifierIssueKind(kind) {
43
- switch (kind) {
44
- case "extra_column": return "extraNestedElement";
45
- case "extra_primary_key":
46
- case "extra_foreign_key":
47
- case "extra_unique_constraint":
48
- case "extra_index":
49
- case "extra_validator":
50
- case "extra_default": return "extraAuxiliary";
51
- case "extra_table": return "extraTopLevelObject";
52
- case "missing_schema":
53
- case "missing_table":
54
- case "missing_column":
55
- case "type_missing":
56
- case "default_missing": return "declaredMissing";
57
- case "type_values_mismatch":
58
- case "enum_values_changed": return "valueDrift";
59
- case "type_mismatch":
60
- case "nullability_mismatch":
61
- case "primary_key_mismatch":
62
- case "foreign_key_mismatch":
63
- case "unique_constraint_mismatch":
64
- case "index_mismatch":
65
- case "default_mismatch": return "declaredIncompatible";
66
- }
67
- }
68
- function verifierDisposition(controlPolicy, issueKind) {
69
- return dispositionForCategory(controlPolicy, classifySqlVerifierIssueKind(issueKind));
70
- }
71
- //#endregion
72
- //#region src/core/schema-verify/control-verify-emit.ts
73
- /**
74
- * Grades `issue` under `controlPolicy` and, unless suppressed, pushes both the
75
- * issue and a status-stamped verification node. Returns the resolved outcome so
76
- * the caller never re-grades the same issue.
77
- */
78
- function emitIssueAndNodeUnderControlPolicy(controlPolicy, issue, node, issues, nodes) {
79
- const disposition = verifierDisposition(controlPolicy, issue.kind);
80
- if (disposition === "suppress") return disposition;
81
- issues.push(issue);
82
- nodes.push({
83
- ...node,
84
- status: disposition
85
- });
86
- return disposition;
87
- }
88
- /**
89
- * Grades `issue` under `controlPolicy` and, unless suppressed, pushes the issue
90
- * (no verification node). Returns the resolved outcome so the caller maps it to
91
- * a node status itself without re-grading.
92
- */
93
- function emitIssueUnderControlPolicy(controlPolicy, issue, issues) {
94
- const disposition = verifierDisposition(controlPolicy, issue.kind);
95
- if (disposition === "suppress") return disposition;
96
- issues.push(issue);
97
- return disposition;
98
- }
99
- //#endregion
100
34
  //#region src/core/schema-verify/verify-helpers.ts
101
35
  function indexOptionsLooselyEqual(a, b) {
102
36
  const aKeys = a ? Object.keys(a).sort() : [];
@@ -158,27 +92,27 @@ function isIndexSatisfied(indexes, uniques, columns) {
158
92
  * Uses semantic satisfaction: identity is based on (table + kind + columns).
159
93
  * Name differences are ignored by default (names are for DDL/diagnostics, not identity).
160
94
  */
161
- function verifyPrimaryKey(contractPK, schemaPK, tableName, namespaceId, tableControlPolicy, issues) {
95
+ function verifyPrimaryKey(contractPK, schemaPK, tableName, namespaceId, issues) {
162
96
  if (!schemaPK) {
163
- const outcome = emitIssueUnderControlPolicy(tableControlPolicy, {
97
+ issues.push({
164
98
  kind: "primary_key_mismatch",
165
99
  table: tableName,
166
100
  namespaceId,
167
101
  expected: contractPK.columns.join(", "),
168
102
  message: `Table "${tableName}" is missing primary key`
169
- }, issues);
170
- return outcome === "suppress" ? "pass" : outcome;
103
+ });
104
+ return "fail";
171
105
  }
172
106
  if (!arraysEqual(contractPK.columns, schemaPK.columns)) {
173
- const outcome = emitIssueUnderControlPolicy(tableControlPolicy, {
107
+ issues.push({
174
108
  kind: "primary_key_mismatch",
175
109
  table: tableName,
176
110
  namespaceId,
177
111
  expected: contractPK.columns.join(", "),
178
112
  actual: schemaPK.columns.join(", "),
179
113
  message: `Table "${tableName}" has primary key mismatch: expected columns [${contractPK.columns.join(", ")}], got [${schemaPK.columns.join(", ")}]`
180
- }, issues);
181
- return outcome === "suppress" ? "pass" : outcome;
114
+ });
115
+ return "fail";
182
116
  }
183
117
  return "pass";
184
118
  }
@@ -189,7 +123,7 @@ function verifyPrimaryKey(contractPK, schemaPK, tableName, namespaceId, tableCon
189
123
  * Uses semantic satisfaction: identity is based on (table + columns + referenced table + referenced columns).
190
124
  * Name differences are ignored by default (names are for DDL/diagnostics, not identity).
191
125
  */
192
- function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict) {
126
+ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, tablePath, issues, strict) {
193
127
  const nodes = [];
194
128
  for (const contractFK of contractFKs) {
195
129
  const fkPath = `${tablePath}.foreignKeys[${contractFK.source.columns.join(",")}]`;
@@ -197,30 +131,32 @@ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, table
197
131
  const tablesMatch = fk.referencedSchema !== void 0 && contractFK.target.namespaceId !== UNBOUND_NAMESPACE_ID ? fk.referencedSchema === contractFK.target.namespaceId && fk.referencedTable === contractFK.target.tableName : fk.referencedTable === contractFK.target.tableName;
198
132
  return arraysEqual(fk.columns, contractFK.source.columns) && tablesMatch && arraysEqual(fk.referencedColumns, contractFK.target.columns);
199
133
  });
200
- if (!matchingFK) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
201
- kind: "foreign_key_mismatch",
202
- table: tableName,
203
- namespaceId,
204
- expected: `${contractFK.source.columns.join(", ")} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(", ")})`,
205
- message: `Table "${tableName}" is missing foreign key: ${contractFK.source.columns.join(", ")} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(", ")})`
206
- }, {
207
- status: "fail",
208
- kind: "foreignKey",
209
- name: `foreignKey(${contractFK.source.columns.join(", ")})`,
210
- contractPath: fkPath,
211
- code: "foreign_key_mismatch",
212
- message: "Foreign key missing",
213
- expected: contractFK,
214
- actual: void 0,
215
- children: []
216
- }, issues, nodes);
217
- else {
134
+ if (!matchingFK) {
135
+ issues.push({
136
+ kind: "foreign_key_mismatch",
137
+ table: tableName,
138
+ namespaceId,
139
+ expected: `${contractFK.source.columns.join(", ")} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(", ")})`,
140
+ message: `Table "${tableName}" is missing foreign key: ${contractFK.source.columns.join(", ")} -> ${contractFK.target.tableName}(${contractFK.target.columns.join(", ")})`
141
+ });
142
+ nodes.push({
143
+ status: "fail",
144
+ kind: "foreignKey",
145
+ name: `foreignKey(${contractFK.source.columns.join(", ")})`,
146
+ contractPath: fkPath,
147
+ code: "foreign_key_mismatch",
148
+ message: "Foreign key missing",
149
+ expected: contractFK,
150
+ actual: void 0,
151
+ children: []
152
+ });
153
+ } else {
218
154
  const actionMismatches = getReferentialActionMismatches(contractFK, matchingFK);
219
155
  if (actionMismatches.length > 0) {
220
156
  const combinedMessage = actionMismatches.map((m) => m.message).join("; ");
221
157
  const combinedExpected = actionMismatches.map((m) => m.expected).join(", ");
222
158
  const combinedActual = actionMismatches.map((m) => m.actual).join(", ");
223
- emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
159
+ issues.push({
224
160
  kind: "foreign_key_mismatch",
225
161
  table: tableName,
226
162
  namespaceId,
@@ -228,7 +164,8 @@ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, table
228
164
  expected: combinedExpected,
229
165
  actual: combinedActual,
230
166
  message: `Table "${tableName}" foreign key ${contractFK.source.columns.join(", ")} -> ${contractFK.target.tableName}: ${combinedMessage}`
231
- }, {
167
+ });
168
+ nodes.push({
232
169
  status: "fail",
233
170
  kind: "foreignKey",
234
171
  name: `foreignKey(${contractFK.source.columns.join(", ")})`,
@@ -238,7 +175,7 @@ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, table
238
175
  expected: contractFK,
239
176
  actual: matchingFK,
240
177
  children: []
241
- }, issues, nodes);
178
+ });
242
179
  } else nodes.push({
243
180
  status: "pass",
244
181
  kind: "foreignKey",
@@ -256,23 +193,26 @@ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, table
256
193
  for (const schemaFK of schemaFKs) if (!contractFKs.find((fk) => {
257
194
  const tablesMatch = schemaFK.referencedSchema !== void 0 && fk.target.namespaceId !== UNBOUND_NAMESPACE_ID ? schemaFK.referencedSchema === fk.target.namespaceId && schemaFK.referencedTable === fk.target.tableName : schemaFK.referencedTable === fk.target.tableName;
258
195
  return arraysEqual(fk.source.columns, schemaFK.columns) && tablesMatch && arraysEqual(fk.target.columns, schemaFK.referencedColumns);
259
- })) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
260
- kind: "extra_foreign_key",
261
- table: tableName,
262
- namespaceId,
263
- indexOrConstraint: schemaFK.name ?? `fk(${schemaFK.columns.join(",")})`,
264
- message: `Extra foreign key found in database (not in contract): ${schemaFK.columns.join(", ")} -> ${schemaFK.referencedTable}(${schemaFK.referencedColumns.join(", ")})`
265
- }, {
266
- status: "fail",
267
- kind: "foreignKey",
268
- name: `foreignKey(${schemaFK.columns.join(", ")})`,
269
- contractPath: `${tablePath}.foreignKeys[${schemaFK.columns.join(",")}]`,
270
- code: "extra_foreign_key",
271
- message: "Extra foreign key found",
272
- expected: void 0,
273
- actual: schemaFK,
274
- children: []
275
- }, issues, nodes);
196
+ })) {
197
+ issues.push({
198
+ kind: "extra_foreign_key",
199
+ table: tableName,
200
+ namespaceId,
201
+ indexOrConstraint: schemaFK.name ?? `fk(${schemaFK.columns.join(",")})`,
202
+ message: `Extra foreign key found in database (not in contract): ${schemaFK.columns.join(", ")} -> ${schemaFK.referencedTable}(${schemaFK.referencedColumns.join(", ")})`
203
+ });
204
+ nodes.push({
205
+ status: "fail",
206
+ kind: "foreignKey",
207
+ name: `foreignKey(${schemaFK.columns.join(", ")})`,
208
+ contractPath: `${tablePath}.foreignKeys[${schemaFK.columns.join(",")}]`,
209
+ code: "extra_foreign_key",
210
+ message: "Extra foreign key found",
211
+ expected: void 0,
212
+ actual: schemaFK,
213
+ children: []
214
+ });
215
+ }
276
216
  }
277
217
  return nodes;
278
218
  }
@@ -287,30 +227,32 @@ function verifyForeignKeys(contractFKs, schemaFKs, tableName, namespaceId, table
287
227
  *
288
228
  * Name differences are ignored by default (names are for DDL/diagnostics, not identity).
289
229
  */
290
- function verifyUniqueConstraints(contractUniques, schemaUniques, schemaIndexes, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict) {
230
+ function verifyUniqueConstraints(contractUniques, schemaUniques, schemaIndexes, tableName, namespaceId, tablePath, issues, strict) {
291
231
  const nodes = [];
292
232
  for (const contractUnique of contractUniques) {
293
233
  const uniquePath = `${tablePath}.uniques[${contractUnique.columns.join(",")}]`;
294
234
  const matchingUnique = schemaUniques.find((u) => arraysEqual(u.columns, contractUnique.columns));
295
235
  const matchingUniqueIndex = !matchingUnique && schemaIndexes.find((idx) => idx.unique && arraysEqual(idx.columns, contractUnique.columns));
296
- if (!matchingUnique && !matchingUniqueIndex) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
297
- kind: "unique_constraint_mismatch",
298
- table: tableName,
299
- namespaceId,
300
- expected: contractUnique.columns.join(", "),
301
- message: `Table "${tableName}" is missing unique constraint: ${contractUnique.columns.join(", ")}`
302
- }, {
303
- status: "fail",
304
- kind: "unique",
305
- name: `unique(${contractUnique.columns.join(", ")})`,
306
- contractPath: uniquePath,
307
- code: "unique_constraint_mismatch",
308
- message: "Unique constraint missing",
309
- expected: contractUnique,
310
- actual: void 0,
311
- children: []
312
- }, issues, nodes);
313
- else nodes.push({
236
+ if (!matchingUnique && !matchingUniqueIndex) {
237
+ issues.push({
238
+ kind: "unique_constraint_mismatch",
239
+ table: tableName,
240
+ namespaceId,
241
+ expected: contractUnique.columns.join(", "),
242
+ message: `Table "${tableName}" is missing unique constraint: ${contractUnique.columns.join(", ")}`
243
+ });
244
+ nodes.push({
245
+ status: "fail",
246
+ kind: "unique",
247
+ name: `unique(${contractUnique.columns.join(", ")})`,
248
+ contractPath: uniquePath,
249
+ code: "unique_constraint_mismatch",
250
+ message: "Unique constraint missing",
251
+ expected: contractUnique,
252
+ actual: void 0,
253
+ children: []
254
+ });
255
+ } else nodes.push({
314
256
  status: "pass",
315
257
  kind: "unique",
316
258
  name: `unique(${contractUnique.columns.join(", ")})`,
@@ -323,23 +265,26 @@ function verifyUniqueConstraints(contractUniques, schemaUniques, schemaIndexes,
323
265
  });
324
266
  }
325
267
  if (strict) {
326
- for (const schemaUnique of schemaUniques) if (!contractUniques.find((u) => arraysEqual(u.columns, schemaUnique.columns))) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
327
- kind: "extra_unique_constraint",
328
- table: tableName,
329
- namespaceId,
330
- indexOrConstraint: schemaUnique.name ?? `unique(${schemaUnique.columns.join(",")})`,
331
- message: `Extra unique constraint found in database (not in contract): ${schemaUnique.columns.join(", ")}`
332
- }, {
333
- status: "fail",
334
- kind: "unique",
335
- name: `unique(${schemaUnique.columns.join(", ")})`,
336
- contractPath: `${tablePath}.uniques[${schemaUnique.columns.join(",")}]`,
337
- code: "extra_unique_constraint",
338
- message: "Extra unique constraint found",
339
- expected: void 0,
340
- actual: schemaUnique,
341
- children: []
342
- }, issues, nodes);
268
+ for (const schemaUnique of schemaUniques) if (!contractUniques.find((u) => arraysEqual(u.columns, schemaUnique.columns))) {
269
+ issues.push({
270
+ kind: "extra_unique_constraint",
271
+ table: tableName,
272
+ namespaceId,
273
+ indexOrConstraint: schemaUnique.name ?? `unique(${schemaUnique.columns.join(",")})`,
274
+ message: `Extra unique constraint found in database (not in contract): ${schemaUnique.columns.join(", ")}`
275
+ });
276
+ nodes.push({
277
+ status: "fail",
278
+ kind: "unique",
279
+ name: `unique(${schemaUnique.columns.join(", ")})`,
280
+ contractPath: `${tablePath}.uniques[${schemaUnique.columns.join(",")}]`,
281
+ code: "extra_unique_constraint",
282
+ message: "Extra unique constraint found",
283
+ expected: void 0,
284
+ actual: schemaUnique,
285
+ children: []
286
+ });
287
+ }
343
288
  }
344
289
  return nodes;
345
290
  }
@@ -354,30 +299,32 @@ function verifyUniqueConstraints(contractUniques, schemaUniques, schemaIndexes,
354
299
  *
355
300
  * Name differences are ignored by default (names are for DDL/diagnostics, not identity).
356
301
  */
357
- function verifyIndexes(contractIndexes, schemaIndexes, schemaUniques, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict) {
302
+ function verifyIndexes(contractIndexes, schemaIndexes, schemaUniques, tableName, namespaceId, tablePath, issues, strict) {
358
303
  const nodes = [];
359
304
  for (const contractIndex of contractIndexes) {
360
305
  const indexPath = `${tablePath}.indexes[${contractIndex.columns.join(",")}]`;
361
306
  const matchingIndex = schemaIndexes.find((idx) => arraysEqual(idx.columns, contractIndex.columns) && indexExtrasMatch(contractIndex, idx));
362
307
  const matchingUniqueConstraint = !matchingIndex && contractIndex.type === void 0 && contractIndex.options === void 0 && schemaUniques.find((u) => arraysEqual(u.columns, contractIndex.columns));
363
- if (!matchingIndex && !matchingUniqueConstraint) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
364
- kind: "index_mismatch",
365
- table: tableName,
366
- namespaceId,
367
- expected: contractIndex.columns.join(", "),
368
- message: `Table "${tableName}" is missing index: ${contractIndex.columns.join(", ")}`
369
- }, {
370
- status: "fail",
371
- kind: "index",
372
- name: `index(${contractIndex.columns.join(", ")})`,
373
- contractPath: indexPath,
374
- code: "index_mismatch",
375
- message: "Index missing",
376
- expected: contractIndex,
377
- actual: void 0,
378
- children: []
379
- }, issues, nodes);
380
- else nodes.push({
308
+ if (!matchingIndex && !matchingUniqueConstraint) {
309
+ issues.push({
310
+ kind: "index_mismatch",
311
+ table: tableName,
312
+ namespaceId,
313
+ expected: contractIndex.columns.join(", "),
314
+ message: `Table "${tableName}" is missing index: ${contractIndex.columns.join(", ")}`
315
+ });
316
+ nodes.push({
317
+ status: "fail",
318
+ kind: "index",
319
+ name: `index(${contractIndex.columns.join(", ")})`,
320
+ contractPath: indexPath,
321
+ code: "index_mismatch",
322
+ message: "Index missing",
323
+ expected: contractIndex,
324
+ actual: void 0,
325
+ children: []
326
+ });
327
+ } else nodes.push({
381
328
  status: "pass",
382
329
  kind: "index",
383
330
  name: `index(${contractIndex.columns.join(", ")})`,
@@ -391,23 +338,26 @@ function verifyIndexes(contractIndexes, schemaIndexes, schemaUniques, tableName,
391
338
  }
392
339
  if (strict) for (const schemaIndex of schemaIndexes) {
393
340
  if (schemaIndex.unique) continue;
394
- if (!contractIndexes.find((idx) => arraysEqual(idx.columns, schemaIndex.columns) && indexExtrasMatch(idx, schemaIndex))) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
395
- kind: "extra_index",
396
- table: tableName,
397
- namespaceId,
398
- indexOrConstraint: schemaIndex.name ?? `idx(${schemaIndex.columns.join(",")})`,
399
- message: `Extra index found in database (not in contract): ${schemaIndex.columns.join(", ")}`
400
- }, {
401
- status: "fail",
402
- kind: "index",
403
- name: `index(${schemaIndex.columns.join(", ")})`,
404
- contractPath: `${tablePath}.indexes[${schemaIndex.columns.join(",")}]`,
405
- code: "extra_index",
406
- message: "Extra index found",
407
- expected: void 0,
408
- actual: schemaIndex,
409
- children: []
410
- }, issues, nodes);
341
+ if (!contractIndexes.find((idx) => arraysEqual(idx.columns, schemaIndex.columns) && indexExtrasMatch(idx, schemaIndex))) {
342
+ issues.push({
343
+ kind: "extra_index",
344
+ table: tableName,
345
+ namespaceId,
346
+ indexOrConstraint: schemaIndex.name ?? `idx(${schemaIndex.columns.join(",")})`,
347
+ message: `Extra index found in database (not in contract): ${schemaIndex.columns.join(", ")}`
348
+ });
349
+ nodes.push({
350
+ status: "fail",
351
+ kind: "index",
352
+ name: `index(${schemaIndex.columns.join(", ")})`,
353
+ contractPath: `${tablePath}.indexes[${schemaIndex.columns.join(",")}]`,
354
+ code: "extra_index",
355
+ message: "Extra index found",
356
+ expected: void 0,
357
+ actual: schemaIndex,
358
+ children: []
359
+ });
360
+ }
411
361
  }
412
362
  return nodes;
413
363
  }
@@ -479,7 +429,7 @@ function normalizeReferentialAction(action) {
479
429
  * @returns VerifyDatabaseSchemaResult with verification tree and issues
480
430
  */
481
431
  function verifySqlSchema(options) {
482
- const { contract, schema, strict, context, typeMetadataRegistry, normalizeDefault, normalizeNativeType, resolveExistingEnumValues, columnsCompatible } = options;
432
+ const { contract, schema, strict, context, typeMetadataRegistry, normalizeDefault, normalizeNativeType, resolveExistingEnumValues } = options;
483
433
  const startTime = Date.now();
484
434
  const codecHooks = extractCodecControlHooks(options.frameworkComponents);
485
435
  const { contractStorageHash, contractProfileHash, contractTarget } = extractContractMetadata(contract);
@@ -496,31 +446,19 @@ function verifySqlSchema(options) {
496
446
  codecHooks,
497
447
  storageTypes: allStorageTypesMap,
498
448
  ...ifDefined("normalizeDefault", normalizeDefault),
499
- ...ifDefined("normalizeNativeType", normalizeNativeType),
500
- ...ifDefined("columnsCompatible", columnsCompatible)
449
+ ...ifDefined("normalizeNativeType", normalizeNativeType)
501
450
  });
502
451
  validateFrameworkComponentsForExtensions(contract, options.frameworkComponents);
503
452
  const typeNodes = [];
504
- const pushTypeNode = (typeName, contractPath, typeIssues, controlPolicy) => {
505
- let status = "pass";
506
- let code = "";
507
- let emitted = 0;
508
- for (const issue of typeIssues) {
509
- const disposition = verifierDisposition(controlPolicy, issue.kind);
510
- if (disposition === "suppress") continue;
511
- issues.push(issue);
512
- emitted += 1;
513
- if (code === "") code = issue.kind;
514
- if (disposition === "fail") status = "fail";
515
- else if (disposition === "warn" && status !== "fail") status = "warn";
516
- }
453
+ const pushTypeNode = (typeName, contractPath, typeIssues) => {
454
+ if (typeIssues.length > 0) issues.push(...typeIssues);
517
455
  typeNodes.push({
518
- status,
456
+ status: typeIssues.length > 0 ? "fail" : "pass",
519
457
  kind: "storageType",
520
458
  name: `type ${typeName}`,
521
459
  contractPath,
522
- code: status === "pass" ? "" : code,
523
- message: emitted > 0 ? `${emitted} issue${emitted === 1 ? "" : "s"}` : "",
460
+ code: typeIssues.length > 0 ? typeIssues[0]?.kind ?? "" : "",
461
+ message: typeIssues.length > 0 ? `${typeIssues.length} issue${typeIssues.length === 1 ? "" : "s"}` : "",
524
462
  expected: void 0,
525
463
  actual: void 0,
526
464
  children: []
@@ -532,14 +470,14 @@ function verifySqlSchema(options) {
532
470
  schema,
533
471
  resolveExistingEnumValues,
534
472
  namespaceId: UNBOUND_NAMESPACE_ID
535
- }), effectiveControlPolicy(typeInstance.control, contract.defaultControl));
473
+ }));
536
474
  else if (isStorageTypeInstance(typeInstance)) {
537
475
  const hook = codecHooks.get(typeInstance.codecId);
538
476
  pushTypeNode(typeName, `storage.types.${typeName}`, hook?.verifyType ? hook.verifyType({
539
477
  typeName,
540
478
  typeInstance,
541
479
  schema
542
- }) : [], effectiveControlPolicy(void 0, contract.defaultControl));
480
+ }) : []);
543
481
  }
544
482
  for (const nsId of Object.keys(contract.storage.namespaces)) {
545
483
  const ns = contract.storage.namespaces[nsId];
@@ -554,11 +492,11 @@ function verifySqlSchema(options) {
554
492
  schema,
555
493
  resolveExistingEnumValues,
556
494
  namespaceId: nsId
557
- }), effectiveControlPolicy(entry.control, contract.defaultControl));
495
+ }));
558
496
  }
559
497
  }
560
498
  if (typeNodes.length > 0) {
561
- const typesStatus = typeNodes.some((n) => n.status === "fail") ? "fail" : typeNodes.some((n) => n.status === "warn") ? "warn" : "pass";
499
+ const typesStatus = typeNodes.some((n) => n.status === "fail") ? "fail" : "pass";
562
500
  rootChildren.push({
563
501
  status: typesStatus,
564
502
  kind: "storageTypes",
@@ -642,8 +580,7 @@ function extractContractMetadata(contract) {
642
580
  };
643
581
  }
644
582
  function verifySchemaTables(options) {
645
- const { contract, schema, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType, columnsCompatible } = options;
646
- const contractDefaultControl = contract.defaultControl;
583
+ const { contract, schema, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType } = options;
647
584
  const issues = [];
648
585
  const rootChildren = [];
649
586
  const schemaTables = schema.tables;
@@ -654,16 +591,16 @@ function verifySchemaTables(options) {
654
591
  for (const [tableName, contractTableRaw] of Object.entries(ns.tables)) {
655
592
  if (!(contractTableRaw instanceof StorageTable)) throw new Error(`verifySqlSchema: expected StorageTable at storage.namespaces.${namespaceId}.tables.${tableName}`);
656
593
  const contractTable = contractTableRaw;
657
- const tableControlPolicy = effectiveControlPolicy(contractTable.control, contractDefaultControl);
658
594
  const schemaTable = schemaTables[tableName];
659
595
  const tablePath = `storage.namespaces.${namespaceId}.tables.${tableName}`;
660
596
  if (!schemaTable) {
661
- emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
597
+ issues.push({
662
598
  kind: "missing_table",
663
599
  table: tableName,
664
600
  namespaceId,
665
601
  message: `Table "${tableName}" is missing from database`
666
- }, {
602
+ });
603
+ rootChildren.push({
667
604
  status: "fail",
668
605
  kind: "table",
669
606
  name: `table ${tableName}`,
@@ -673,7 +610,7 @@ function verifySchemaTables(options) {
673
610
  expected: void 0,
674
611
  actual: void 0,
675
612
  children: []
676
- }, issues, rootChildren);
613
+ });
677
614
  continue;
678
615
  }
679
616
  const tableChildren = verifyTableChildren({
@@ -682,35 +619,36 @@ function verifySchemaTables(options) {
682
619
  tableName,
683
620
  namespaceId,
684
621
  tablePath,
685
- tableControlPolicy,
686
622
  issues,
687
623
  strict,
688
624
  typeMetadataRegistry,
689
625
  codecHooks,
690
626
  storageTypes,
691
627
  ...ifDefined("normalizeDefault", normalizeDefault),
692
- ...ifDefined("normalizeNativeType", normalizeNativeType),
693
- ...ifDefined("columnsCompatible", columnsCompatible)
628
+ ...ifDefined("normalizeNativeType", normalizeNativeType)
694
629
  });
695
630
  rootChildren.push(buildTableNode(tableName, tablePath, tableChildren));
696
631
  }
697
632
  }
698
633
  if (strict) {
699
- for (const tableName of Object.keys(schemaTables)) if (!namespaceIds.some((namespaceId) => contract.storage.namespaces[namespaceId]?.tables[tableName] !== void 0)) emitIssueAndNodeUnderControlPolicy(effectiveControlPolicy(void 0, contractDefaultControl), {
700
- kind: "extra_table",
701
- table: tableName,
702
- message: `Extra table "${tableName}" found in database (not in contract)`
703
- }, {
704
- status: "fail",
705
- kind: "table",
706
- name: `table ${tableName}`,
707
- contractPath: `storage.namespaces.*.tables.${tableName}`,
708
- code: "extra_table",
709
- message: `Extra table "${tableName}" found`,
710
- expected: void 0,
711
- actual: void 0,
712
- children: []
713
- }, issues, rootChildren);
634
+ for (const tableName of Object.keys(schemaTables)) if (!namespaceIds.some((namespaceId) => contract.storage.namespaces[namespaceId]?.tables[tableName] !== void 0)) {
635
+ issues.push({
636
+ kind: "extra_table",
637
+ table: tableName,
638
+ message: `Extra table "${tableName}" found in database (not in contract)`
639
+ });
640
+ rootChildren.push({
641
+ status: "fail",
642
+ kind: "table",
643
+ name: `table ${tableName}`,
644
+ contractPath: `storage.namespaces.*.tables.${tableName}`,
645
+ code: "extra_table",
646
+ message: `Extra table "${tableName}" found`,
647
+ expected: void 0,
648
+ actual: void 0,
649
+ children: []
650
+ });
651
+ }
714
652
  }
715
653
  return {
716
654
  issues,
@@ -718,7 +656,7 @@ function verifySchemaTables(options) {
718
656
  };
719
657
  }
720
658
  function verifyTableChildren(options) {
721
- const { contractTable, schemaTable, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType, columnsCompatible } = options;
659
+ const { contractTable, schemaTable, tableName, namespaceId, tablePath, issues, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType } = options;
722
660
  const tableChildren = [];
723
661
  const columnNodes = collectContractColumnNodes({
724
662
  contractTable,
@@ -726,15 +664,13 @@ function verifyTableChildren(options) {
726
664
  tableName,
727
665
  namespaceId,
728
666
  tablePath,
729
- tableControlPolicy,
730
667
  issues,
731
668
  strict,
732
669
  typeMetadataRegistry,
733
670
  codecHooks,
734
671
  storageTypes,
735
672
  ...ifDefined("normalizeDefault", normalizeDefault),
736
- ...ifDefined("normalizeNativeType", normalizeNativeType),
737
- ...ifDefined("columnsCompatible", columnsCompatible)
673
+ ...ifDefined("normalizeNativeType", normalizeNativeType)
738
674
  });
739
675
  if (columnNodes.length > 0) tableChildren.push(buildColumnsNode(tablePath, columnNodes));
740
676
  if (strict) appendExtraColumnNodes({
@@ -743,87 +679,77 @@ function verifyTableChildren(options) {
743
679
  tableName,
744
680
  namespaceId,
745
681
  tablePath,
746
- tableControlPolicy,
747
682
  issues,
748
683
  columnNodes
749
684
  });
750
- if (contractTable.primaryKey) {
751
- const pkStatus = verifyPrimaryKey(contractTable.primaryKey, schemaTable.primaryKey, tableName, namespaceId, tableControlPolicy, issues);
752
- if (pkStatus === "fail") tableChildren.push({
753
- status: "fail",
754
- kind: "primaryKey",
755
- name: `primary key: ${contractTable.primaryKey.columns.join(", ")}`,
756
- contractPath: `${tablePath}.primaryKey`,
757
- code: "primary_key_mismatch",
758
- message: "Primary key mismatch",
759
- expected: contractTable.primaryKey,
760
- actual: schemaTable.primaryKey,
761
- children: []
762
- });
763
- else if (pkStatus === "warn") tableChildren.push({
764
- status: "warn",
765
- kind: "primaryKey",
766
- name: `primary key: ${contractTable.primaryKey.columns.join(", ")}`,
767
- contractPath: `${tablePath}.primaryKey`,
768
- code: "primary_key_mismatch",
769
- message: "Primary key mismatch",
770
- expected: contractTable.primaryKey,
771
- actual: schemaTable.primaryKey,
772
- children: []
685
+ if (contractTable.primaryKey) if (verifyPrimaryKey(contractTable.primaryKey, schemaTable.primaryKey, tableName, namespaceId, issues) === "fail") tableChildren.push({
686
+ status: "fail",
687
+ kind: "primaryKey",
688
+ name: `primary key: ${contractTable.primaryKey.columns.join(", ")}`,
689
+ contractPath: `${tablePath}.primaryKey`,
690
+ code: "primary_key_mismatch",
691
+ message: "Primary key mismatch",
692
+ expected: contractTable.primaryKey,
693
+ actual: schemaTable.primaryKey,
694
+ children: []
695
+ });
696
+ else tableChildren.push({
697
+ status: "pass",
698
+ kind: "primaryKey",
699
+ name: `primary key: ${contractTable.primaryKey.columns.join(", ")}`,
700
+ contractPath: `${tablePath}.primaryKey`,
701
+ code: "",
702
+ message: "",
703
+ expected: void 0,
704
+ actual: void 0,
705
+ children: []
706
+ });
707
+ else if (schemaTable.primaryKey && strict) {
708
+ issues.push({
709
+ kind: "extra_primary_key",
710
+ table: tableName,
711
+ namespaceId,
712
+ message: "Extra primary key found in database (not in contract)"
773
713
  });
774
- else tableChildren.push({
775
- status: "pass",
714
+ tableChildren.push({
715
+ status: "fail",
776
716
  kind: "primaryKey",
777
- name: `primary key: ${contractTable.primaryKey.columns.join(", ")}`,
717
+ name: `primary key: ${schemaTable.primaryKey.columns.join(", ")}`,
778
718
  contractPath: `${tablePath}.primaryKey`,
779
- code: "",
780
- message: "",
719
+ code: "extra_primary_key",
720
+ message: "Extra primary key found",
781
721
  expected: void 0,
782
- actual: void 0,
722
+ actual: schemaTable.primaryKey,
783
723
  children: []
784
724
  });
785
- } else if (schemaTable.primaryKey && strict) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
786
- kind: "extra_primary_key",
787
- table: tableName,
788
- namespaceId,
789
- message: "Extra primary key found in database (not in contract)"
790
- }, {
791
- status: "fail",
792
- kind: "primaryKey",
793
- name: `primary key: ${schemaTable.primaryKey.columns.join(", ")}`,
794
- contractPath: `${tablePath}.primaryKey`,
795
- code: "extra_primary_key",
796
- message: "Extra primary key found",
797
- expected: void 0,
798
- actual: schemaTable.primaryKey,
799
- children: []
800
- }, issues, tableChildren);
725
+ }
801
726
  const constraintFks = contractTable.foreignKeys.filter((fk) => fk.constraint === true);
802
727
  if (constraintFks.length > 0 || strict) {
803
- const fkStatuses = verifyForeignKeys(constraintFks, schemaTable.foreignKeys, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict);
728
+ const fkStatuses = verifyForeignKeys(constraintFks, schemaTable.foreignKeys, tableName, namespaceId, tablePath, issues, strict);
804
729
  tableChildren.push(...fkStatuses);
805
730
  }
806
- const uniqueStatuses = verifyUniqueConstraints(contractTable.uniques, schemaTable.uniques, schemaTable.indexes, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict);
731
+ const uniqueStatuses = verifyUniqueConstraints(contractTable.uniques, schemaTable.uniques, schemaTable.indexes, tableName, namespaceId, tablePath, issues, strict);
807
732
  tableChildren.push(...uniqueStatuses);
808
733
  const fkBackingIndexes = contractTable.foreignKeys.filter((fk) => fk.index === true && !contractTable.indexes.some((idx) => arraysEqual(idx.columns, fk.source.columns))).map((fk) => ({ columns: fk.source.columns }));
809
- const indexStatuses = verifyIndexes([...contractTable.indexes, ...fkBackingIndexes], schemaTable.indexes, schemaTable.uniques, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict);
734
+ const indexStatuses = verifyIndexes([...contractTable.indexes, ...fkBackingIndexes], schemaTable.indexes, schemaTable.uniques, tableName, namespaceId, tablePath, issues, strict);
810
735
  tableChildren.push(...indexStatuses);
811
736
  return tableChildren;
812
737
  }
813
738
  function collectContractColumnNodes(options) {
814
- const { contractTable, schemaTable, tableName, namespaceId, tablePath, tableControlPolicy, issues, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType, columnsCompatible } = options;
739
+ const { contractTable, schemaTable, tableName, namespaceId, tablePath, issues, strict, typeMetadataRegistry, codecHooks, storageTypes, normalizeDefault, normalizeNativeType } = options;
815
740
  const columnNodes = [];
816
741
  for (const [columnName, contractColumn] of Object.entries(contractTable.columns)) {
817
742
  const schemaColumn = schemaTable.columns[columnName];
818
743
  const columnPath = `${tablePath}.columns.${columnName}`;
819
744
  if (!schemaColumn) {
820
- emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
745
+ issues.push({
821
746
  kind: "missing_column",
822
747
  table: tableName,
823
748
  namespaceId,
824
749
  column: columnName,
825
750
  message: `Column "${tableName}"."${columnName}" is missing from database`
826
- }, {
751
+ });
752
+ columnNodes.push({
827
753
  status: "fail",
828
754
  kind: "column",
829
755
  name: `${columnName}: missing`,
@@ -833,7 +759,7 @@ function collectContractColumnNodes(options) {
833
759
  expected: void 0,
834
760
  actual: void 0,
835
761
  children: []
836
- }, issues, columnNodes);
762
+ });
837
763
  continue;
838
764
  }
839
765
  columnNodes.push(verifyColumn({
@@ -843,41 +769,42 @@ function collectContractColumnNodes(options) {
843
769
  contractColumn,
844
770
  schemaColumn,
845
771
  columnPath,
846
- tableControlPolicy,
847
772
  issues,
848
773
  strict,
849
774
  typeMetadataRegistry,
850
775
  codecHooks,
851
776
  storageTypes,
852
777
  ...ifDefined("normalizeDefault", normalizeDefault),
853
- ...ifDefined("normalizeNativeType", normalizeNativeType),
854
- ...ifDefined("columnsCompatible", columnsCompatible)
778
+ ...ifDefined("normalizeNativeType", normalizeNativeType)
855
779
  }));
856
780
  }
857
781
  return columnNodes;
858
782
  }
859
783
  function appendExtraColumnNodes(options) {
860
- const { contractTable, schemaTable, tableName, namespaceId, tablePath, tableControlPolicy, issues, columnNodes } = options;
861
- for (const [columnName, { nativeType }] of Object.entries(schemaTable.columns)) if (!contractTable.columns[columnName]) emitIssueAndNodeUnderControlPolicy(tableControlPolicy, {
862
- kind: "extra_column",
863
- table: tableName,
864
- namespaceId,
865
- column: columnName,
866
- message: `Extra column "${tableName}"."${columnName}" found in database (not in contract)`
867
- }, {
868
- status: "fail",
869
- kind: "column",
870
- name: `${columnName}: extra`,
871
- contractPath: `${tablePath}.columns.${columnName}`,
872
- code: "extra_column",
873
- message: `Extra column "${columnName}" found`,
874
- expected: void 0,
875
- actual: nativeType,
876
- children: []
877
- }, issues, columnNodes);
784
+ const { contractTable, schemaTable, tableName, namespaceId, tablePath, issues, columnNodes } = options;
785
+ for (const [columnName, { nativeType }] of Object.entries(schemaTable.columns)) if (!contractTable.columns[columnName]) {
786
+ issues.push({
787
+ kind: "extra_column",
788
+ table: tableName,
789
+ namespaceId,
790
+ column: columnName,
791
+ message: `Extra column "${tableName}"."${columnName}" found in database (not in contract)`
792
+ });
793
+ columnNodes.push({
794
+ status: "fail",
795
+ kind: "column",
796
+ name: `${columnName}: extra`,
797
+ contractPath: `${tablePath}.columns.${columnName}`,
798
+ code: "extra_column",
799
+ message: `Extra column "${columnName}" found`,
800
+ expected: void 0,
801
+ actual: nativeType,
802
+ children: []
803
+ });
804
+ }
878
805
  }
879
806
  function verifyColumn(options) {
880
- const { tableName, namespaceId, columnName, contractColumn, schemaColumn, columnPath, tableControlPolicy, issues, strict, codecHooks, storageTypes, normalizeDefault, normalizeNativeType, columnsCompatible } = options;
807
+ const { tableName, namespaceId, columnName, contractColumn, schemaColumn, columnPath, issues, strict, codecHooks, storageTypes, normalizeDefault, normalizeNativeType } = options;
881
808
  const columnChildren = [];
882
809
  let columnStatus = "pass";
883
810
  const resolvedContractColumn = resolveContractColumnTypeMetadata(contractColumn, storageTypes, {
@@ -889,8 +816,8 @@ function verifyColumn(options) {
889
816
  columnName
890
817
  });
891
818
  const schemaNativeType = normalizeNativeType?.(schemaColumn.nativeType) ?? schemaColumn.nativeType;
892
- if (!(contractNativeType === schemaNativeType || tableControlPolicy === "external" && (columnsCompatible?.(contractNativeType, schemaNativeType) ?? contractNativeType === schemaNativeType))) {
893
- const issue = {
819
+ if (contractNativeType !== schemaNativeType) {
820
+ issues.push({
894
821
  kind: "type_mismatch",
895
822
  table: tableName,
896
823
  namespaceId,
@@ -898,23 +825,19 @@ function verifyColumn(options) {
898
825
  expected: contractNativeType,
899
826
  actual: schemaNativeType,
900
827
  message: `Column "${tableName}"."${columnName}" has type mismatch: expected "${contractNativeType}", got "${schemaNativeType}"`
901
- };
902
- const disposition = verifierDisposition(tableControlPolicy, issue.kind);
903
- if (disposition !== "suppress") {
904
- issues.push(issue);
905
- columnChildren.push({
906
- status: disposition,
907
- kind: "type",
908
- name: "type",
909
- contractPath: `${columnPath}.nativeType`,
910
- code: "type_mismatch",
911
- message: `Type mismatch: expected ${contractNativeType}, got ${schemaNativeType}`,
912
- expected: contractNativeType,
913
- actual: schemaNativeType,
914
- children: []
915
- });
916
- columnStatus = disposition;
917
- }
828
+ });
829
+ columnChildren.push({
830
+ status: "fail",
831
+ kind: "type",
832
+ name: "type",
833
+ contractPath: `${columnPath}.nativeType`,
834
+ code: "type_mismatch",
835
+ message: `Type mismatch: expected ${contractNativeType}, got ${schemaNativeType}`,
836
+ expected: contractNativeType,
837
+ actual: schemaNativeType,
838
+ children: []
839
+ });
840
+ columnStatus = "fail";
918
841
  }
919
842
  if (resolvedContractColumn.codecId) {
920
843
  const typeMetadata = options.typeMetadataRegistry.get(resolvedContractColumn.codecId);
@@ -942,7 +865,7 @@ function verifyColumn(options) {
942
865
  });
943
866
  }
944
867
  if (contractColumn.nullable !== schemaColumn.nullable) {
945
- const issue = {
868
+ issues.push({
946
869
  kind: "nullability_mismatch",
947
870
  table: tableName,
948
871
  namespaceId,
@@ -950,55 +873,47 @@ function verifyColumn(options) {
950
873
  expected: String(contractColumn.nullable),
951
874
  actual: String(schemaColumn.nullable),
952
875
  message: `Column "${tableName}"."${columnName}" has nullability mismatch: expected ${contractColumn.nullable ? "nullable" : "not null"}, got ${schemaColumn.nullable ? "nullable" : "not null"}`
953
- };
954
- const disposition = verifierDisposition(tableControlPolicy, issue.kind);
955
- if (disposition !== "suppress") {
956
- issues.push(issue);
957
- columnChildren.push({
958
- status: disposition,
959
- kind: "nullability",
960
- name: "nullability",
961
- contractPath: `${columnPath}.nullable`,
962
- code: "nullability_mismatch",
963
- message: `Nullability mismatch: expected ${contractColumn.nullable ? "nullable" : "not null"}, got ${schemaColumn.nullable ? "nullable" : "not null"}`,
964
- expected: contractColumn.nullable,
965
- actual: schemaColumn.nullable,
966
- children: []
967
- });
968
- columnStatus = disposition;
969
- }
876
+ });
877
+ columnChildren.push({
878
+ status: "fail",
879
+ kind: "nullability",
880
+ name: "nullability",
881
+ contractPath: `${columnPath}.nullable`,
882
+ code: "nullability_mismatch",
883
+ message: `Nullability mismatch: expected ${contractColumn.nullable ? "nullable" : "not null"}, got ${schemaColumn.nullable ? "nullable" : "not null"}`,
884
+ expected: contractColumn.nullable,
885
+ actual: schemaColumn.nullable,
886
+ children: []
887
+ });
888
+ columnStatus = "fail";
970
889
  }
971
890
  if (contractColumn.default) {
972
891
  if (!schemaColumn.default) {
973
892
  const defaultDescription = describeColumnDefault(contractColumn.default);
974
- const issue = {
893
+ issues.push({
975
894
  kind: "default_missing",
976
895
  table: tableName,
977
896
  namespaceId,
978
897
  column: columnName,
979
898
  expected: defaultDescription,
980
899
  message: `Column "${tableName}"."${columnName}" should have default ${defaultDescription} but database has no default`
981
- };
982
- const disposition = verifierDisposition(tableControlPolicy, issue.kind);
983
- if (disposition !== "suppress") {
984
- issues.push(issue);
985
- columnChildren.push({
986
- status: disposition,
987
- kind: "default",
988
- name: "default",
989
- contractPath: `${columnPath}.default`,
990
- code: "default_missing",
991
- message: `Default missing: expected ${defaultDescription}`,
992
- expected: defaultDescription,
993
- actual: void 0,
994
- children: []
995
- });
996
- columnStatus = disposition;
997
- }
900
+ });
901
+ columnChildren.push({
902
+ status: "fail",
903
+ kind: "default",
904
+ name: "default",
905
+ contractPath: `${columnPath}.default`,
906
+ code: "default_missing",
907
+ message: `Default missing: expected ${defaultDescription}`,
908
+ expected: defaultDescription,
909
+ actual: void 0,
910
+ children: []
911
+ });
912
+ columnStatus = "fail";
998
913
  } else if (!columnDefaultsEqual(contractColumn.default, schemaColumn.default, normalizeDefault, schemaNativeType)) {
999
914
  const expectedDescription = describeColumnDefault(contractColumn.default);
1000
915
  const actualDescription = schemaColumn.default;
1001
- const issue = {
916
+ issues.push({
1002
917
  kind: "default_mismatch",
1003
918
  table: tableName,
1004
919
  namespaceId,
@@ -1006,49 +921,41 @@ function verifyColumn(options) {
1006
921
  expected: expectedDescription,
1007
922
  actual: actualDescription,
1008
923
  message: `Column "${tableName}"."${columnName}" has default mismatch: expected ${expectedDescription}, got ${actualDescription}`
1009
- };
1010
- const disposition = verifierDisposition(tableControlPolicy, issue.kind);
1011
- if (disposition !== "suppress") {
1012
- issues.push(issue);
1013
- columnChildren.push({
1014
- status: disposition,
1015
- kind: "default",
1016
- name: "default",
1017
- contractPath: `${columnPath}.default`,
1018
- code: "default_mismatch",
1019
- message: `Default mismatch: expected ${expectedDescription}, got ${actualDescription}`,
1020
- expected: expectedDescription,
1021
- actual: actualDescription,
1022
- children: []
1023
- });
1024
- columnStatus = disposition;
1025
- }
924
+ });
925
+ columnChildren.push({
926
+ status: "fail",
927
+ kind: "default",
928
+ name: "default",
929
+ contractPath: `${columnPath}.default`,
930
+ code: "default_mismatch",
931
+ message: `Default mismatch: expected ${expectedDescription}, got ${actualDescription}`,
932
+ expected: expectedDescription,
933
+ actual: actualDescription,
934
+ children: []
935
+ });
936
+ columnStatus = "fail";
1026
937
  }
1027
938
  } else if (strict && schemaColumn.default) {
1028
- const issue = {
939
+ issues.push({
1029
940
  kind: "extra_default",
1030
941
  table: tableName,
1031
942
  namespaceId,
1032
943
  column: columnName,
1033
944
  actual: schemaColumn.default,
1034
945
  message: `Column "${tableName}"."${columnName}" has default ${schemaColumn.default} in database but contract specifies no default`
1035
- };
1036
- const disposition = verifierDisposition(tableControlPolicy, issue.kind);
1037
- if (disposition !== "suppress") {
1038
- issues.push(issue);
1039
- columnChildren.push({
1040
- status: disposition,
1041
- kind: "default",
1042
- name: "default",
1043
- contractPath: `${columnPath}.default`,
1044
- code: "extra_default",
1045
- message: `Extra default: ${schemaColumn.default}`,
1046
- expected: void 0,
1047
- actual: schemaColumn.default,
1048
- children: []
1049
- });
1050
- columnStatus = disposition;
1051
- }
946
+ });
947
+ columnChildren.push({
948
+ status: "fail",
949
+ kind: "default",
950
+ name: "default",
951
+ contractPath: `${columnPath}.default`,
952
+ code: "extra_default",
953
+ message: `Extra default: ${schemaColumn.default}`,
954
+ expected: void 0,
955
+ actual: schemaColumn.default,
956
+ children: []
957
+ });
958
+ columnStatus = "fail";
1052
959
  }
1053
960
  const aggregated = aggregateChildState(columnChildren, columnStatus);
1054
961
  const nullableText = contractColumn.nullable ? "nullable" : "not nullable";
@@ -1247,4 +1154,4 @@ function formatLiteralValue(value) {
1247
1154
  //#endregion
1248
1155
  export { extractCodecControlHooks as a, isUniqueConstraintSatisfied as i, arraysEqual as n, isIndexSatisfied as r, verifySqlSchema as t };
1249
1156
 
1250
- //# sourceMappingURL=verify-sql-schema-CXW_D9dW.mjs.map
1157
+ //# sourceMappingURL=verify-sql-schema-CYLsGCFO.mjs.map