@prisma-next/family-sql 0.14.0-dev.39 → 0.14.0-dev.40

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 (46) hide show
  1. package/dist/contract-to-schema-ir-S-evq8E6.mjs +264 -0
  2. package/dist/contract-to-schema-ir-S-evq8E6.mjs.map +1 -0
  3. package/dist/{control-adapter-B2q9WN1V.d.mts → control-adapter-DHYFuOBy.d.mts} +14 -17
  4. package/dist/{control-adapter-B2q9WN1V.d.mts.map → control-adapter-DHYFuOBy.d.mts.map} +1 -1
  5. package/dist/control-adapter.d.mts +1 -1
  6. package/dist/control.d.mts +17 -2
  7. package/dist/control.d.mts.map +1 -1
  8. package/dist/control.mjs +42 -943
  9. package/dist/control.mjs.map +1 -1
  10. package/dist/{schema-verify.d.mts → diff.d.mts} +4 -4
  11. package/dist/diff.d.mts.map +1 -0
  12. package/dist/{verify-sql-schema-CEY7b78t.mjs → diff.mjs} +154 -244
  13. package/dist/diff.mjs.map +1 -0
  14. package/dist/migration.d.mts +1 -1
  15. package/dist/psl-infer.d.mts +80 -0
  16. package/dist/psl-infer.d.mts.map +1 -0
  17. package/dist/psl-infer.mjs +334 -0
  18. package/dist/psl-infer.mjs.map +1 -0
  19. package/dist/{verify-sql-schema-B8uEjw2s.d.mts → sql-schema-diff-6z36dZt6.d.mts} +43 -4
  20. package/dist/sql-schema-diff-6z36dZt6.d.mts.map +1 -0
  21. package/dist/{types-BxsFkHYv.d.mts → types-CkOIJXxU.d.mts} +83 -16
  22. package/dist/types-CkOIJXxU.d.mts.map +1 -0
  23. package/package.json +23 -22
  24. package/src/core/control-adapter.ts +12 -24
  25. package/src/core/control-instance.ts +113 -45
  26. package/src/core/{schema-verify/verify-sql-schema.ts → diff/sql-schema-diff.ts} +196 -8
  27. package/src/core/{schema-verify → diff}/verify-helpers.ts +12 -0
  28. package/src/core/migrations/contract-to-schema-ir.ts +48 -13
  29. package/src/core/migrations/field-event-planner.ts +3 -8
  30. package/src/core/migrations/schema-differ.ts +40 -0
  31. package/src/core/migrations/types.ts +43 -2
  32. package/src/core/psl-contract-infer/printer-config.ts +0 -6
  33. package/src/exports/control.ts +1 -0
  34. package/src/exports/diff.ts +18 -0
  35. package/src/exports/psl-infer.ts +36 -0
  36. package/dist/schema-verify.d.mts.map +0 -1
  37. package/dist/schema-verify.mjs +0 -2
  38. package/dist/types-BxsFkHYv.d.mts.map +0 -1
  39. package/dist/verify-sql-schema-B8uEjw2s.d.mts.map +0 -1
  40. package/dist/verify-sql-schema-CEY7b78t.mjs.map +0 -1
  41. package/src/core/psl-contract-infer/postgres-default-mapping.ts +0 -16
  42. package/src/core/psl-contract-infer/postgres-type-map.ts +0 -157
  43. package/src/core/psl-contract-infer/sql-schema-ir-to-psl-ast.ts +0 -795
  44. package/src/exports/schema-verify.ts +0 -18
  45. /package/src/core/{schema-verify → diff}/control-verify-emit.ts +0 -0
  46. /package/src/core/{schema-verify → diff}/verifier-disposition.ts +0 -0
@@ -0,0 +1,334 @@
1
+ //#region src/core/psl-contract-infer/default-mapping.ts
2
+ const DEFAULT_FUNCTION_ATTRIBUTES = {
3
+ "autoincrement()": "@default(autoincrement())",
4
+ "now()": "@default(now())"
5
+ };
6
+ function mapDefault(columnDefault, options) {
7
+ switch (columnDefault.kind) {
8
+ case "literal": return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };
9
+ case "function": {
10
+ const attribute = options?.functionAttributes?.[columnDefault.expression] ?? DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ?? options?.fallbackFunctionAttribute?.(columnDefault.expression);
11
+ return attribute ? { attribute } : { comment: `// Raw default: ${columnDefault.expression.replace(/[\r\n]+/g, " ")}` };
12
+ }
13
+ }
14
+ }
15
+ function formatLiteralValue(value) {
16
+ if (value === null) return "null";
17
+ switch (typeof value) {
18
+ case "boolean":
19
+ case "number": return String(value);
20
+ case "string": return quoteString(value);
21
+ default: return quoteString(JSON.stringify(value));
22
+ }
23
+ }
24
+ function quoteString(str) {
25
+ return `"${escapeString(str)}"`;
26
+ }
27
+ function escapeString(str) {
28
+ return JSON.stringify(str).slice(1, -1);
29
+ }
30
+ //#endregion
31
+ //#region src/core/psl-contract-infer/name-transforms.ts
32
+ const PSL_RESERVED_WORDS = new Set([
33
+ "model",
34
+ "enum",
35
+ "types",
36
+ "type",
37
+ "generator",
38
+ "datasource"
39
+ ]);
40
+ const IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;
41
+ function hasSeparators(input) {
42
+ return /[^A-Za-z0-9]/.test(input);
43
+ }
44
+ function extractIdentifierParts(input) {
45
+ return input.match(IDENTIFIER_PART_PATTERN) ?? [];
46
+ }
47
+ function createSyntheticIdentifier(input) {
48
+ let hash = 2166136261;
49
+ for (const char of input) {
50
+ hash ^= char.codePointAt(0) ?? 0;
51
+ hash = Math.imul(hash, 16777619);
52
+ }
53
+ return `x${(hash >>> 0).toString(16)}`;
54
+ }
55
+ function sanitizeIdentifierCharacters(input) {
56
+ const sanitized = input.replace(/[^\w]/g, "");
57
+ return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);
58
+ }
59
+ function capitalize(word) {
60
+ return word.charAt(0).toUpperCase() + word.slice(1);
61
+ }
62
+ function snakeToPascalCase(input) {
63
+ const parts = extractIdentifierParts(input);
64
+ if (parts.length === 0) return capitalize(sanitizeIdentifierCharacters(input));
65
+ return parts.map(capitalize).join("");
66
+ }
67
+ function snakeToCamelCase(input) {
68
+ const parts = extractIdentifierParts(input);
69
+ if (parts.length === 0) return sanitizeIdentifierCharacters(input);
70
+ const [firstPart = input, ...rest] = parts;
71
+ return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join("");
72
+ }
73
+ function needsEscaping(name) {
74
+ return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\d/.test(name);
75
+ }
76
+ function escapeName(name) {
77
+ return `_${name}`;
78
+ }
79
+ function escapeIfNeeded(name) {
80
+ return needsEscaping(name) ? escapeName(name) : name;
81
+ }
82
+ function toModelName(tableName) {
83
+ let name;
84
+ if (hasSeparators(tableName)) name = snakeToPascalCase(tableName);
85
+ else name = tableName.charAt(0).toUpperCase() + tableName.slice(1);
86
+ if (needsEscaping(name)) return {
87
+ name: escapeName(name),
88
+ map: tableName
89
+ };
90
+ if (name !== tableName) return {
91
+ name,
92
+ map: tableName
93
+ };
94
+ return { name };
95
+ }
96
+ function toFieldName(columnName) {
97
+ let name;
98
+ if (hasSeparators(columnName)) name = snakeToCamelCase(columnName);
99
+ else name = columnName.charAt(0).toLowerCase() + columnName.slice(1);
100
+ if (needsEscaping(name)) return {
101
+ name: escapeName(name),
102
+ map: columnName
103
+ };
104
+ if (name !== columnName) return {
105
+ name,
106
+ map: columnName
107
+ };
108
+ return { name };
109
+ }
110
+ function toEnumName(pgTypeName) {
111
+ let name;
112
+ if (hasSeparators(pgTypeName)) name = snakeToPascalCase(pgTypeName);
113
+ else name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);
114
+ if (needsEscaping(name)) return {
115
+ name: escapeName(name),
116
+ map: pgTypeName
117
+ };
118
+ if (name !== pgTypeName) return {
119
+ name,
120
+ map: pgTypeName
121
+ };
122
+ return { name };
123
+ }
124
+ function pluralize(word) {
125
+ if (word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch") || word.endsWith("sh")) return `${word}es`;
126
+ if (word.endsWith("y") && !/[aeiou]y$/i.test(word)) return `${word.slice(0, -1)}ies`;
127
+ return `${word}s`;
128
+ }
129
+ function deriveRelationFieldName(fkColumns, referencedTableName) {
130
+ if (fkColumns.length === 1) {
131
+ const [col = referencedTableName] = fkColumns;
132
+ const stripped = col.replace(/_id$/i, "").replace(/Id$/, "");
133
+ if (stripped.length > 0 && stripped !== col) return escapeIfNeeded(snakeToCamelCase(stripped));
134
+ return escapeIfNeeded(snakeToCamelCase(referencedTableName));
135
+ }
136
+ return escapeIfNeeded(snakeToCamelCase(referencedTableName));
137
+ }
138
+ function deriveBackRelationFieldName(childModelName, isOneToOne) {
139
+ const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);
140
+ return isOneToOne ? base : pluralize(base);
141
+ }
142
+ function toNamedTypeName(columnName) {
143
+ let name;
144
+ if (hasSeparators(columnName)) name = snakeToPascalCase(columnName);
145
+ else name = columnName.charAt(0).toUpperCase() + columnName.slice(1);
146
+ return escapeIfNeeded(name);
147
+ }
148
+ //#endregion
149
+ //#region src/core/psl-contract-infer/raw-default-parser.ts
150
+ const NEXTVAL_PATTERN = /^nextval\s*\(/i;
151
+ const NOW_FUNCTION_PATTERN = /^(now\s*\(\s*\)|CURRENT_TIMESTAMP)$/i;
152
+ const CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\s*\(\s*\)$/i;
153
+ const TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\s+(?:with|without)\s+time\s+zone)?$/i;
154
+ const TEXT_CAST_SUFFIX = /::text$/i;
155
+ const NOW_LITERAL_PATTERN = /^'now'$/i;
156
+ const UUID_PATTERN = /^gen_random_uuid\s*\(\s*\)$/i;
157
+ const UUID_OSSP_PATTERN = /^uuid_generate_v4\s*\(\s*\)$/i;
158
+ const NULL_PATTERN = /^NULL(?:::.+)?$/i;
159
+ const TRUE_PATTERN = /^true$/i;
160
+ const FALSE_PATTERN = /^false$/i;
161
+ const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
162
+ const JSON_CAST_SUFFIX = /::jsonb?$/i;
163
+ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
164
+ function canonicalizeTimestampDefault(expr) {
165
+ if (NOW_FUNCTION_PATTERN.test(expr)) return "now()";
166
+ if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return "clock_timestamp()";
167
+ if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return void 0;
168
+ let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, "").trim();
169
+ if (inner.startsWith("(") && inner.endsWith(")")) inner = inner.slice(1, -1).trim();
170
+ if (NOW_FUNCTION_PATTERN.test(inner)) return "now()";
171
+ if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return "clock_timestamp()";
172
+ inner = inner.replace(TEXT_CAST_SUFFIX, "").trim();
173
+ if (NOW_LITERAL_PATTERN.test(inner)) return "now()";
174
+ }
175
+ function parseRawDefault(rawDefault, nativeType) {
176
+ const trimmed = rawDefault.trim();
177
+ const normalizedType = nativeType?.toLowerCase();
178
+ if (NEXTVAL_PATTERN.test(trimmed)) return {
179
+ kind: "function",
180
+ expression: "autoincrement()"
181
+ };
182
+ const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
183
+ if (canonicalTimestamp) return {
184
+ kind: "function",
185
+ expression: canonicalTimestamp
186
+ };
187
+ if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) return {
188
+ kind: "function",
189
+ expression: "gen_random_uuid()"
190
+ };
191
+ if (NULL_PATTERN.test(trimmed)) return {
192
+ kind: "literal",
193
+ value: null
194
+ };
195
+ if (TRUE_PATTERN.test(trimmed)) return {
196
+ kind: "literal",
197
+ value: true
198
+ };
199
+ if (FALSE_PATTERN.test(trimmed)) return {
200
+ kind: "literal",
201
+ value: false
202
+ };
203
+ if (NUMERIC_PATTERN.test(trimmed)) return {
204
+ kind: "literal",
205
+ value: Number(trimmed)
206
+ };
207
+ const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
208
+ if (stringMatch?.[1] !== void 0) {
209
+ const unescaped = stringMatch[1].replace(/''/g, "'");
210
+ if (normalizedType === "json" || normalizedType === "jsonb") {
211
+ if (JSON_CAST_SUFFIX.test(trimmed)) return {
212
+ kind: "function",
213
+ expression: trimmed
214
+ };
215
+ try {
216
+ return {
217
+ kind: "literal",
218
+ value: JSON.parse(unescaped)
219
+ };
220
+ } catch {}
221
+ }
222
+ return {
223
+ kind: "literal",
224
+ value: unescaped
225
+ };
226
+ }
227
+ return {
228
+ kind: "function",
229
+ expression: trimmed
230
+ };
231
+ }
232
+ //#endregion
233
+ //#region src/core/psl-contract-infer/relation-inference.ts
234
+ const DEFAULT_ON_DELETE = "noAction";
235
+ const DEFAULT_ON_UPDATE = "noAction";
236
+ const REFERENTIAL_ACTION_PSL = {
237
+ noAction: "NoAction",
238
+ restrict: "Restrict",
239
+ cascade: "Cascade",
240
+ setNull: "SetNull",
241
+ setDefault: "SetDefault"
242
+ };
243
+ function inferRelations(tables, modelNameMap) {
244
+ const relationsByTable = /* @__PURE__ */ new Map();
245
+ const fkCountByPair = /* @__PURE__ */ new Map();
246
+ for (const table of Object.values(tables)) for (const fk of table.foreignKeys) {
247
+ const pairKey = `${table.name}→${fk.referencedTable}`;
248
+ fkCountByPair.set(pairKey, (fkCountByPair.get(pairKey) ?? 0) + 1);
249
+ }
250
+ const usedFieldNames = /* @__PURE__ */ new Map();
251
+ for (const table of Object.values(tables)) {
252
+ const names = /* @__PURE__ */ new Set();
253
+ for (const col of Object.values(table.columns)) names.add(col.name);
254
+ usedFieldNames.set(table.name, names);
255
+ }
256
+ for (const table of Object.values(tables)) for (const fk of table.foreignKeys) {
257
+ const childTableName = table.name;
258
+ const parentTableName = fk.referencedTable;
259
+ const childUsed = usedFieldNames.get(childTableName);
260
+ const childModelName = modelNameMap.get(childTableName) ?? childTableName;
261
+ const parentModelName = modelNameMap.get(parentTableName) ?? parentTableName;
262
+ const pairKey = `${childTableName}→${parentTableName}`;
263
+ const isSelfRelation = childTableName === parentTableName;
264
+ const needsRelationName = fkCountByPair.get(pairKey) > 1 || isSelfRelation;
265
+ const isOneToOne = detectOneToOne(fk, table);
266
+ const childRelFieldName = resolveUniqueFieldName(deriveRelationFieldName(fk.columns, parentTableName), childUsed, parentModelName);
267
+ const relationName = needsRelationName ? deriveRelationName(fk, childRelFieldName, parentModelName, isSelfRelation) : void 0;
268
+ addRelationField(relationsByTable, childTableName, buildChildRelationField(childRelFieldName, parentModelName, fk, fk.columns.some((columnName) => table.columns[columnName]?.nullable ?? false), relationName));
269
+ childUsed.add(childRelFieldName);
270
+ const parentUsed = usedFieldNames.get(parentTableName) ?? /* @__PURE__ */ new Set();
271
+ usedFieldNames.set(parentTableName, parentUsed);
272
+ const backRelFieldName = resolveUniqueFieldName(deriveBackRelationFieldName(childModelName, isOneToOne), parentUsed, childModelName);
273
+ addRelationField(relationsByTable, parentTableName, {
274
+ fieldName: backRelFieldName,
275
+ typeName: childModelName,
276
+ optional: isOneToOne,
277
+ list: !isOneToOne,
278
+ relationName
279
+ });
280
+ parentUsed.add(backRelFieldName);
281
+ }
282
+ return { relationsByTable };
283
+ }
284
+ function detectOneToOne(fk, table) {
285
+ const fkCols = [...fk.columns].sort();
286
+ if (table.primaryKey) {
287
+ const pkCols = [...table.primaryKey.columns].sort();
288
+ if (pkCols.length === fkCols.length && pkCols.every((c, i) => c === fkCols[i])) return true;
289
+ }
290
+ for (const unique of table.uniques) {
291
+ const uniqueCols = [...unique.columns].sort();
292
+ if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) return true;
293
+ }
294
+ return false;
295
+ }
296
+ function deriveRelationName(fk, childRelationFieldName, parentModelName, isSelfRelation) {
297
+ if (fk.name) return fk.name;
298
+ if (isSelfRelation) return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;
299
+ return fk.columns.join("_");
300
+ }
301
+ function buildChildRelationField(fieldName, parentModelName, fk, optional, relationName) {
302
+ const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : void 0;
303
+ const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : void 0;
304
+ return {
305
+ fieldName,
306
+ typeName: parentModelName,
307
+ referencedTableName: fk.referencedTable,
308
+ optional,
309
+ list: false,
310
+ relationName,
311
+ fkName: fk.name,
312
+ fields: fk.columns,
313
+ references: fk.referencedColumns,
314
+ onDelete: onDelete ? REFERENTIAL_ACTION_PSL[onDelete] : void 0,
315
+ onUpdate: onUpdate ? REFERENTIAL_ACTION_PSL[onUpdate] : void 0
316
+ };
317
+ }
318
+ function resolveUniqueFieldName(desired, usedNames, fallbackSuffix) {
319
+ if (!usedNames.has(desired)) return desired;
320
+ const withSuffix = `${desired}${fallbackSuffix}`;
321
+ if (!usedNames.has(withSuffix)) return withSuffix;
322
+ let counter = 2;
323
+ while (usedNames.has(`${desired}${counter}`)) counter++;
324
+ return `${desired}${counter}`;
325
+ }
326
+ function addRelationField(map, tableName, field) {
327
+ const existing = map.get(tableName);
328
+ if (existing) existing.push(field);
329
+ else map.set(tableName, [field]);
330
+ }
331
+ //#endregion
332
+ export { deriveBackRelationFieldName, deriveRelationFieldName, inferRelations, mapDefault, parseRawDefault, pluralize, toEnumName, toFieldName, toModelName, toNamedTypeName };
333
+
334
+ //# sourceMappingURL=psl-infer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"psl-infer.mjs","names":[],"sources":["../src/core/psl-contract-infer/default-mapping.ts","../src/core/psl-contract-infer/name-transforms.ts","../src/core/psl-contract-infer/raw-default-parser.ts","../src/core/psl-contract-infer/relation-inference.ts"],"sourcesContent":["import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst DEFAULT_FUNCTION_ATTRIBUTES: Readonly<Record<string, string>> = {\n 'autoincrement()': '@default(autoincrement())',\n 'now()': '@default(now())',\n};\n\nexport interface DefaultMappingOptions {\n readonly functionAttributes?: Readonly<Record<string, string>>;\n readonly fallbackFunctionAttribute?: ((expression: string) => string | undefined) | undefined;\n}\n\nexport type DefaultMappingResult = { readonly attribute: string } | { readonly comment: string };\n\nexport function mapDefault(\n columnDefault: ColumnDefault,\n options?: DefaultMappingOptions,\n): DefaultMappingResult {\n switch (columnDefault.kind) {\n case 'literal':\n return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };\n case 'function': {\n const attribute =\n options?.functionAttributes?.[columnDefault.expression] ??\n DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ??\n options?.fallbackFunctionAttribute?.(columnDefault.expression);\n return attribute\n ? { attribute }\n : { comment: `// Raw default: ${columnDefault.expression.replace(/[\\r\\n]+/g, ' ')}` };\n }\n }\n}\n\nfunction formatLiteralValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n switch (typeof value) {\n case 'boolean':\n case 'number':\n return String(value);\n case 'string':\n return quoteString(value);\n default:\n return quoteString(JSON.stringify(value));\n }\n}\n\nfunction quoteString(str: string): string {\n return `\"${escapeString(str)}\"`;\n}\n\nfunction escapeString(str: string): string {\n return JSON.stringify(str).slice(1, -1);\n}\n","const PSL_RESERVED_WORDS = new Set(['model', 'enum', 'types', 'type', 'generator', 'datasource']);\n\nconst IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;\n\ntype NameResult = {\n readonly name: string;\n readonly map?: string;\n};\n\nfunction hasSeparators(input: string): boolean {\n return /[^A-Za-z0-9]/.test(input);\n}\n\nfunction extractIdentifierParts(input: string): string[] {\n return input.match(IDENTIFIER_PART_PATTERN) ?? [];\n}\n\nfunction createSyntheticIdentifier(input: string): string {\n let hash = 2166136261;\n\n for (const char of input) {\n hash ^= char.codePointAt(0) ?? 0;\n hash = Math.imul(hash, 16777619);\n }\n\n return `x${(hash >>> 0).toString(16)}`;\n}\n\nfunction sanitizeIdentifierCharacters(input: string): string {\n const sanitized = input.replace(/[^\\w]/g, '');\n return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);\n}\n\nfunction capitalize(word: string): string {\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\nfunction snakeToPascalCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return capitalize(sanitizeIdentifierCharacters(input));\n }\n return parts.map(capitalize).join('');\n}\n\nfunction snakeToCamelCase(input: string): string {\n const parts = extractIdentifierParts(input);\n if (parts.length === 0) {\n return sanitizeIdentifierCharacters(input);\n }\n const [firstPart = input, ...rest] = parts;\n return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join('');\n}\n\nfunction needsEscaping(name: string): boolean {\n return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\\d/.test(name);\n}\n\nfunction escapeName(name: string): string {\n return `_${name}`;\n}\n\nfunction escapeIfNeeded(name: string): string {\n return needsEscaping(name) ? escapeName(name) : name;\n}\n\nexport function toModelName(tableName: string): NameResult {\n let name: string;\n\n if (hasSeparators(tableName)) {\n name = snakeToPascalCase(tableName);\n } else {\n name = tableName.charAt(0).toUpperCase() + tableName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: tableName };\n }\n\n if (name !== tableName) {\n return { name, map: tableName };\n }\n\n return { name };\n}\n\nexport function toFieldName(columnName: string): NameResult {\n let name: string;\n\n if (hasSeparators(columnName)) {\n name = snakeToCamelCase(columnName);\n } else {\n name = columnName.charAt(0).toLowerCase() + columnName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: columnName };\n }\n\n if (name !== columnName) {\n return { name, map: columnName };\n }\n\n return { name };\n}\n\nexport function toEnumName(pgTypeName: string): NameResult {\n let name: string;\n\n if (hasSeparators(pgTypeName)) {\n name = snakeToPascalCase(pgTypeName);\n } else {\n name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);\n }\n\n if (needsEscaping(name)) {\n const escaped = escapeName(name);\n return { name: escaped, map: pgTypeName };\n }\n\n if (name !== pgTypeName) {\n return { name, map: pgTypeName };\n }\n\n return { name };\n}\n\nexport function pluralize(word: string): string {\n if (\n word.endsWith('s') ||\n word.endsWith('x') ||\n word.endsWith('z') ||\n word.endsWith('ch') ||\n word.endsWith('sh')\n ) {\n return `${word}es`;\n }\n if (word.endsWith('y') && !/[aeiou]y$/i.test(word)) {\n return `${word.slice(0, -1)}ies`;\n }\n return `${word}s`;\n}\n\nexport function deriveRelationFieldName(\n fkColumns: readonly string[],\n referencedTableName: string,\n): string {\n if (fkColumns.length === 1) {\n const [col = referencedTableName] = fkColumns;\n const stripped = col.replace(/_id$/i, '').replace(/Id$/, '');\n\n if (stripped.length > 0 && stripped !== col) {\n return escapeIfNeeded(snakeToCamelCase(stripped));\n }\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n }\n\n return escapeIfNeeded(snakeToCamelCase(referencedTableName));\n}\n\nexport function deriveBackRelationFieldName(childModelName: string, isOneToOne: boolean): string {\n const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);\n return isOneToOne ? base : pluralize(base);\n}\n\nexport function toNamedTypeName(columnName: string): string {\n let name: string;\n\n if (hasSeparators(columnName)) {\n name = snakeToPascalCase(columnName);\n } else {\n name = columnName.charAt(0).toUpperCase() + columnName.slice(1);\n }\n\n return escapeIfNeeded(name);\n}\n","import type { ColumnDefault } from '@prisma-next/contract/types';\n\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst NOW_FUNCTION_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP)$/i;\nconst CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\\s*\\(\\s*\\)$/i;\nconst TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\\s+(?:with|without)\\s+time\\s+zone)?$/i;\nconst TEXT_CAST_SUFFIX = /::text$/i;\nconst NOW_LITERAL_PATTERN = /^'now'$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst NULL_PATTERN = /^NULL(?:::.+)?$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst JSON_CAST_SUFFIX = /::jsonb?$/i;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\nfunction canonicalizeTimestampDefault(expr: string): string | undefined {\n if (NOW_FUNCTION_PATTERN.test(expr)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return 'clock_timestamp()';\n\n if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return undefined;\n\n let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, '').trim();\n if (inner.startsWith('(') && inner.endsWith(')')) {\n inner = inner.slice(1, -1).trim();\n }\n\n if (NOW_FUNCTION_PATTERN.test(inner)) return 'now()';\n if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return 'clock_timestamp()';\n\n inner = inner.replace(TEXT_CAST_SUFFIX, '').trim();\n if (NOW_LITERAL_PATTERN.test(inner)) return 'now()';\n\n return undefined;\n}\n\nexport function parseRawDefault(\n rawDefault: string,\n nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = nativeType?.toLowerCase();\n\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);\n if (canonicalTimestamp) {\n return { kind: 'function', expression: canonicalTimestamp };\n }\n\n if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n if (NULL_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: null };\n }\n\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n if (NUMERIC_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n if (JSON_CAST_SUFFIX.test(trimmed)) {\n return { kind: 'function', expression: trimmed };\n }\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Fall through to the string form for malformed/non-JSON values.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n return { kind: 'function', expression: trimmed };\n}\n","import type { SqlForeignKeyIR, SqlTableIR } from '@prisma-next/sql-schema-ir/types';\nimport { deriveBackRelationFieldName, deriveRelationFieldName, pluralize } from './name-transforms';\nimport type { RelationField } from './printer-config';\n\nconst DEFAULT_ON_DELETE = 'noAction';\nconst DEFAULT_ON_UPDATE = 'noAction';\n\nconst REFERENTIAL_ACTION_PSL: Record<string, string> = {\n noAction: 'NoAction',\n restrict: 'Restrict',\n cascade: 'Cascade',\n setNull: 'SetNull',\n setDefault: 'SetDefault',\n};\n\nexport type InferredRelations = {\n readonly relationsByTable: ReadonlyMap<string, readonly RelationField[]>;\n};\n\nexport function inferRelations(\n tables: Record<string, SqlTableIR>,\n modelNameMap: ReadonlyMap<string, string>,\n): InferredRelations {\n const relationsByTable = new Map<string, RelationField[]>();\n\n const fkCountByPair = new Map<string, number>();\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const pairKey = `${table.name}→${fk.referencedTable}`;\n fkCountByPair.set(pairKey, (fkCountByPair.get(pairKey) ?? 0) + 1);\n }\n }\n\n const usedFieldNames = new Map<string, Set<string>>();\n for (const table of Object.values(tables)) {\n const names = new Set<string>();\n for (const col of Object.values(table.columns)) {\n names.add(col.name);\n }\n usedFieldNames.set(table.name, names);\n }\n\n for (const table of Object.values(tables)) {\n for (const fk of table.foreignKeys) {\n const childTableName = table.name;\n const parentTableName = fk.referencedTable;\n const childUsed = usedFieldNames.get(childTableName) as Set<string>;\n const childModelName = modelNameMap.get(childTableName) ?? childTableName;\n const parentModelName = modelNameMap.get(parentTableName) ?? parentTableName;\n const pairKey = `${childTableName}→${parentTableName}`;\n const isSelfRelation = childTableName === parentTableName;\n const needsRelationName = (fkCountByPair.get(pairKey) as number) > 1 || isSelfRelation;\n\n const isOneToOne = detectOneToOne(fk, table);\n\n const childRelFieldName = resolveUniqueFieldName(\n deriveRelationFieldName(fk.columns, parentTableName),\n childUsed,\n parentModelName,\n );\n const relationName = needsRelationName\n ? deriveRelationName(fk, childRelFieldName, parentModelName, isSelfRelation)\n : undefined;\n const childOptional = fk.columns.some(\n (columnName) => table.columns[columnName]?.nullable ?? false,\n );\n\n const childRelField = buildChildRelationField(\n childRelFieldName,\n parentModelName,\n fk,\n childOptional,\n relationName,\n );\n\n addRelationField(relationsByTable, childTableName, childRelField);\n childUsed.add(childRelFieldName);\n\n const parentUsed = usedFieldNames.get(parentTableName) ?? new Set();\n usedFieldNames.set(parentTableName, parentUsed);\n\n const backRelFieldName = resolveUniqueFieldName(\n deriveBackRelationFieldName(childModelName, isOneToOne),\n parentUsed,\n childModelName,\n );\n\n const backRelField: RelationField = {\n fieldName: backRelFieldName,\n typeName: childModelName,\n optional: isOneToOne,\n list: !isOneToOne,\n relationName,\n };\n\n addRelationField(relationsByTable, parentTableName, backRelField);\n parentUsed.add(backRelFieldName);\n }\n }\n\n return { relationsByTable };\n}\n\nfunction detectOneToOne(fk: SqlForeignKeyIR, table: SqlTableIR): boolean {\n const fkCols = [...fk.columns].sort();\n\n if (table.primaryKey) {\n const pkCols = [...table.primaryKey.columns].sort();\n if (pkCols.length === fkCols.length && pkCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n for (const unique of table.uniques) {\n const uniqueCols = [...unique.columns].sort();\n if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction deriveRelationName(\n fk: SqlForeignKeyIR,\n childRelationFieldName: string,\n parentModelName: string,\n isSelfRelation: boolean,\n): string {\n if (fk.name) {\n return fk.name;\n }\n if (isSelfRelation) {\n return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;\n }\n return fk.columns.join('_');\n}\n\nfunction buildChildRelationField(\n fieldName: string,\n parentModelName: string,\n fk: SqlForeignKeyIR,\n optional: boolean,\n relationName?: string,\n): RelationField {\n const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : undefined;\n const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : undefined;\n\n return {\n fieldName,\n typeName: parentModelName,\n referencedTableName: fk.referencedTable,\n optional,\n list: false,\n relationName,\n fkName: fk.name,\n fields: fk.columns,\n references: fk.referencedColumns,\n onDelete: onDelete ? REFERENTIAL_ACTION_PSL[onDelete] : undefined,\n onUpdate: onUpdate ? REFERENTIAL_ACTION_PSL[onUpdate] : undefined,\n };\n}\n\nfunction resolveUniqueFieldName(\n desired: string,\n usedNames: ReadonlySet<string>,\n fallbackSuffix: string,\n): string {\n if (!usedNames.has(desired)) {\n return desired;\n }\n\n const withSuffix = `${desired}${fallbackSuffix}`;\n if (!usedNames.has(withSuffix)) {\n return withSuffix;\n }\n\n let counter = 2;\n while (usedNames.has(`${desired}${counter}`)) {\n counter++;\n }\n return `${desired}${counter}`;\n}\n\nfunction addRelationField(\n map: Map<string, RelationField[]>,\n tableName: string,\n field: RelationField,\n): void {\n const existing = map.get(tableName);\n if (existing) {\n existing.push(field);\n } else {\n map.set(tableName, [field]);\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { ColumnDefault, Contract } from "@prisma-next/contract/types";
2
2
  import { OperationContext, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
3
3
  import { SqlStorage } from "@prisma-next/sql-contract/types";
4
- import { SqlSchemaIR } from "@prisma-next/sql-schema-ir/types";
4
+ import { SqlSchemaIR, SqlSchemaIRNode } from "@prisma-next/sql-schema-ir/types";
5
5
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
6
6
 
7
- //#region src/core/schema-verify/verify-sql-schema.d.ts
7
+ //#region src/core/diff/sql-schema-diff.d.ts
8
8
  /**
9
9
  * Function type for normalizing raw database default expressions into ColumnDefault.
10
10
  * Target-specific implementations handle database dialect differences.
@@ -49,6 +49,15 @@ interface VerifySqlSchemaOptions {
49
49
  * with contract native types (e.g., Postgres 'varchar' → 'character varying').
50
50
  */
51
51
  readonly normalizeNativeType?: NativeTypeNormalizer;
52
+ /**
53
+ * When set, only the contract tables in these namespace ids are checked
54
+ * against `schema` (the matching actual namespace node). The full contract is
55
+ * still consulted for cross-namespace value-set / control-policy resolution.
56
+ * Used by the multi-schema verify, which pairs each contract namespace to its
57
+ * own actual node. Absent ⇒ all contract namespaces are checked against the
58
+ * single (flat) `schema` — the single-schema / SQLite path.
59
+ */
60
+ readonly restrictToNamespaceIds?: ReadonlySet<string>;
52
61
  }
53
62
  /**
54
63
  * Verifies that a SqlSchemaIR matches a Contract.
@@ -61,6 +70,36 @@ interface VerifySqlSchemaOptions {
61
70
  * @returns VerifyDatabaseSchemaResult with verification tree and issues
62
71
  */
63
72
  declare function verifySqlSchema(options: VerifySqlSchemaOptions): VerifyDatabaseSchemaResult;
73
+ /**
74
+ * The single per-namespace-paired relational verify shared by the migration
75
+ * planner and the family schema verify — there is exactly one such operation.
76
+ *
77
+ * Each contract namespace is paired to the introspected namespace node holding
78
+ * the same DDL schema, then `verifySqlSchema` checks that namespace's tables
79
+ * against the matching actual node (a contract table under `auth` is only ever
80
+ * looked up in the `auth` actual node, so a multi-schema database no longer
81
+ * reports tables in other schemas as missing). The full contract is passed every
82
+ * time — `restrictToNamespaceIds` scopes only which tables are checked, so
83
+ * cross-namespace value-set / control-policy resolution is unaffected.
84
+ *
85
+ * The DDL schema of each contract namespace is read from a single-namespace
86
+ * expected projection (`buildExpectedSchema`), which both callers already build
87
+ * the same way. Empty contract namespaces verify nothing and are skipped.
88
+ * Single-schema (one namespace) and SQLite's flat schema are one pairing —
89
+ * byte-identical to the prior per-node verify.
90
+ */
91
+ declare function verifySqlSchemaTree(options: {
92
+ readonly contract: Contract<SqlStorage>;
93
+ readonly actualSchema: SqlSchemaIRNode;
94
+ readonly buildExpectedSchema: (contract: Contract<SqlStorage>) => SqlSchemaIRNode;
95
+ readonly strict: boolean;
96
+ readonly typeMetadataRegistry: ReadonlyMap<string, {
97
+ nativeType?: string;
98
+ }>;
99
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
100
+ readonly normalizeDefault?: DefaultNormalizer;
101
+ readonly normalizeNativeType?: NativeTypeNormalizer;
102
+ }): VerifyDatabaseSchemaResult;
64
103
  //#endregion
65
- export { verifySqlSchema as i, NativeTypeNormalizer as n, VerifySqlSchemaOptions as r, DefaultNormalizer as t };
66
- //# sourceMappingURL=verify-sql-schema-B8uEjw2s.d.mts.map
104
+ export { verifySqlSchemaTree as a, verifySqlSchema as i, NativeTypeNormalizer as n, VerifySqlSchemaOptions as r, DefaultNormalizer as t };
105
+ //# sourceMappingURL=sql-schema-diff-6z36dZt6.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-schema-diff-6z36dZt6.d.mts","names":[],"sources":["../src/core/diff/sql-schema-diff.ts"],"mappings":";;;;;;;;;;AA4EkB;KAHN,iBAAA,IACV,UAAA,UACA,UAAA,aACG,aAAa;;;;AAOoC;AAKtD;KALY,oBAAA,IAAwB,UAAkB;;;;UAKrC,sBAAA;EAQI;EAAA,SANV,QAAA,EAAU,QAAA,CAAS,UAAA;EAagB;EAAA,SAXnC,MAAA,EAAQ,WAAA;EAiBW;EAAA,SAfnB,MAAA;EA8ByB;EAAA,SA5BzB,OAAA,GAAU,gBAAA;EA4B0B;EAAA,SA1BpC,oBAAA,EAAsB,WAAA;IAAsB,UAAA;EAAA;EAN5C;;;;EAAA,SAWA,mBAAA,EAAqB,aAAA,CAAc,8BAAA;EALnC;;;;;EAAA,SAWA,gBAAA,GAAmB,iBAAA;EAAnB;;;;;EAAA,SAMA,mBAAA,GAAsB,oBAAA;EASc;AAAA;AAa/C;;;;;;EAb+C,SAApC,sBAAA,GAAyB,WAAA;AAAA;AAawD;AAkyC5F;;;;;;;;;AAlyC4F,iBAA5E,eAAA,CAAgB,OAAA,EAAS,sBAAA,GAAyB,0BAA0B;;;;;;;;;;;;;;;;;;;iBAkyC5E,mBAAA,CAAoB,OAAA;EAAA,SACzB,QAAA,EAAU,QAAA,CAAS,UAAA;EAAA,SACnB,YAAA,EAAc,eAAA;EAAA,SACd,mBAAA,GAAsB,QAAA,EAAU,QAAA,CAAS,UAAA,MAAgB,eAAA;EAAA,SACzD,MAAA;EAAA,SACA,oBAAA,EAAsB,WAAA;IAAsB,UAAA;EAAA;EAAA,SAC5C,mBAAA,EAAqB,aAAA,CAAc,8BAAA;EAAA,SACnC,gBAAA,GAAmB,iBAAA;EAAA,SACnB,mBAAA,GAAsB,oBAAA;AAAA,IAC7B,0BAAA"}
@@ -1,13 +1,13 @@
1
- import { r as SqlControlAdapter } from "./control-adapter-B2q9WN1V.mjs";
1
+ import { r as SqlControlAdapter } from "./control-adapter-DHYFuOBy.mjs";
2
2
  import { Contract, ControlPolicy } from "@prisma-next/contract/types";
3
- import { ContractSerializer, ContractSpace, ControlAdapterDescriptor, ControlExtensionDescriptor, ControlFamilyInstance, ControlStack, MigratableTargetDescriptor, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, MigrationPlannerFailureResult, MigrationPlannerSuccessResult, MigrationRunnerExecutionChecks, MigrationRunnerFailure, MigrationRunnerPerSpaceSuccessValue, MigrationRunnerResult, OpFactoryCall, OperationContext, OperationPreview, OperationPreviewCapable, PslContractInferCapable, SchemaDiffIssue, SchemaIssue, SchemaVerifier, SchemaViewCapable, SignDatabaseResult, VerifyDatabaseResult, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
3
+ import { ContractSerializer, ContractSpace, ControlAdapterDescriptor, ControlExtensionDescriptor, ControlFamilyInstance, ControlStack, DiffIssue, MigratableTargetDescriptor, MigrationOperationPolicy, MigrationPlan, MigrationPlanOperation, MigrationPlannerConflict, MigrationPlannerFailureResult, MigrationPlannerSuccessResult, MigrationRunnerExecutionChecks, MigrationRunnerFailure, MigrationRunnerPerSpaceSuccessValue, MigrationRunnerResult, OpFactoryCall, OperationContext, OperationPreview, OperationPreviewCapable, PslContractInferCapable, SchemaDiffer, SchemaIssue, SchemaVerifier, SchemaViewCapable, SignDatabaseResult, VerifyDatabaseResult, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
4
4
  import { SqlControlDriverInstance, SqlStorage, StorageColumn, StorageTable, StorageTypeInstance } from "@prisma-next/sql-contract/types";
5
- import { PslDocumentAst } from "@prisma-next/framework-components/psl-ast";
6
5
  import { Result } from "@prisma-next/utils/result";
7
6
  import { AnyQueryAst, DdlNode, LowererContext, SqlExecuteRequest } from "@prisma-next/sql-relational-core/ast";
8
- import { SqlSchemaIR } from "@prisma-next/sql-schema-ir/types";
7
+ import { SqlSchemaIR, SqlSchemaIRNode } from "@prisma-next/sql-schema-ir/types";
9
8
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
10
9
  import { TypesImportSpec } from "@prisma-next/framework-components/emission";
10
+ import { PslDocumentAst } from "@prisma-next/framework-components/psl-ast";
11
11
  import { AggregateMigrationEdgeRef } from "@prisma-next/migration-tools/aggregate";
12
12
  import { SqlOperationDescriptors } from "@prisma-next/sql-operations";
13
13
 
@@ -24,7 +24,7 @@ interface SqlFamilyInstanceState {
24
24
  readonly extensionIds: ReadonlyArray<string>;
25
25
  readonly typeMetadataRegistry: SqlTypeMetadataRegistry;
26
26
  }
27
- interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchemaIR>, SchemaViewCapable<SqlSchemaIR>, PslContractInferCapable<SqlSchemaIR>, OperationPreviewCapable, SqlFamilyInstanceState {
27
+ interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchemaIRNode>, SchemaViewCapable<SqlSchemaIRNode>, PslContractInferCapable<SqlSchemaIRNode>, OperationPreviewCapable, SqlFamilyInstanceState {
28
28
  /**
29
29
  * The family seam-of-record for on-disk contract reads. Structurally
30
30
  * validates the JSON envelope, then hydrates IR-class instances via
@@ -42,18 +42,17 @@ interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchem
42
42
  readonly configPath?: string;
43
43
  }): Promise<VerifyDatabaseResult>;
44
44
  /**
45
- * Verify a contract against an already-introspected schema slice.
45
+ * Verify a contract against an already-introspected schema.
46
46
  *
47
47
  * Callers that need to verify against the live database compose
48
48
  * `introspect({ driver })` + `verifySchema({ contract, schema, ... })`.
49
- * The aggregate verifier projects each member's claimed slice via
50
- * `projectSchemaToSpace` and hands the projected slice inthis
51
- * keeps per-member verification from surfacing sibling-space tables
52
- * as `extras`.
49
+ * The aggregate verifier hands in the full introspected schema and scopes
50
+ * the returned result to each member's contract space afterwards so
51
+ * sibling-space tables never survive as `extras`.
53
52
  */
54
53
  verifySchema(options: {
55
54
  readonly contract: unknown;
56
- readonly schema: SqlSchemaIR;
55
+ readonly schema: SqlSchemaIRNode;
57
56
  readonly strict: boolean;
58
57
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
59
58
  }): VerifyDatabaseSchemaResult;
@@ -66,8 +65,8 @@ interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchem
66
65
  introspect(options: {
67
66
  readonly driver: SqlControlDriverInstance<string>;
68
67
  readonly contract?: unknown;
69
- }): Promise<SqlSchemaIR>;
70
- inferPslContract(schemaIR: SqlSchemaIR): PslDocumentAst;
68
+ }): Promise<SqlSchemaIRNode>;
69
+ inferPslContract(schemaIR: SqlSchemaIRNode): PslDocumentAst;
71
70
  lowerAst(ast: AnyQueryAst | DdlNode, context: LowererContext<unknown>): Promise<SqlExecuteRequest>;
72
71
  /**
73
72
  * Inserts the initial marker row for `space` (upsert on `space`).
@@ -114,10 +113,40 @@ interface SqlControlFamilyInstance extends ControlFamilyInstance<'sql', SqlSchem
114
113
  };
115
114
  }): Promise<void>;
116
115
  bootstrapControlTableQueries(): readonly DdlNode[];
117
- bootstrapSignMarkerQueries(): readonly DdlNode[];
118
116
  toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview;
119
117
  }
120
118
  //#endregion
119
+ //#region src/core/migrations/schema-differ.d.ts
120
+ /**
121
+ * Inputs to a SQL target's schema-differ (`diffDatabaseSchema` /
122
+ * `verifyDatabaseSchema` on the descriptor): the contract (the expected side
123
+ * derives from it), the introspected actual schema node, and the resolution
124
+ * context the relational diff needs.
125
+ */
126
+ interface DiffDatabaseSchemaInput {
127
+ readonly contract: Contract<SqlStorage>;
128
+ readonly schema: SqlSchemaIRNode;
129
+ readonly strict: boolean;
130
+ readonly typeMetadataRegistry: ReadonlyMap<string, {
131
+ readonly nativeType?: string;
132
+ }>;
133
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
134
+ }
135
+ /**
136
+ * The `SchemaDiffer` a SQL target implements: the black-box comparison of the
137
+ * contract's expected schema against the introspected actual schema, projected
138
+ * to the two issue lists. How it computes them is private to the target.
139
+ */
140
+ type SqlDiffDatabaseSchema = SchemaDiffer<DiffDatabaseSchemaInput>['diff'];
141
+ /**
142
+ * The same combined comparison as {@link SqlDiffDatabaseSchema}, wrapped in the
143
+ * verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
144
+ * pass/warn/fail tree the CLI renders. Verify calls this instead of the diff so
145
+ * the relational walk that produces the tree runs once per verify, not once for
146
+ * the diff and again for the tree.
147
+ */
148
+ type SqlVerifyDatabaseSchema = (input: DiffDatabaseSchemaInput) => VerifyDatabaseSchemaResult;
149
+ //#endregion
121
150
  //#region src/core/migrations/types.d.ts
122
151
  type AnyRecord = Readonly<Record<string, unknown>>;
123
152
  interface StorageTypePlanResult<TTargetDetails> {
@@ -356,7 +385,12 @@ interface SqlPlannerFailureResult extends Omit<MigrationPlannerFailureResult, 'c
356
385
  type SqlPlannerResult<TTargetDetails> = SqlPlannerSuccessResult<TTargetDetails> | SqlPlannerFailureResult;
357
386
  interface SqlMigrationPlannerPlanOptions {
358
387
  readonly contract: Contract<SqlStorage>;
359
- readonly schema: SqlSchemaIR;
388
+ /**
389
+ * The "from"/live schema as the target's introspected node (SQLite a flat
390
+ * `SqlSchemaIR`, Postgres a `PostgresDatabaseSchemaNode` root). Structure-aware
391
+ * consumers narrow the concrete shape before walking it.
392
+ */
393
+ readonly schema: SqlSchemaIRNode;
360
394
  readonly policy: MigrationOperationPolicy;
361
395
  readonly schemaName?: string;
362
396
  /**
@@ -391,6 +425,16 @@ interface SqlMigrationPlannerPlanOptions {
391
425
  * All components must have matching familyId ('sql') and targetId.
392
426
  */
393
427
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
428
+ /**
429
+ * Caller-supplied keep-predicate the planner applies to its schema diff
430
+ * (via `SchemaDiff.filter`) before building operations. The orchestration
431
+ * constructs it so the diff findings reaching op-building are exactly the
432
+ * contract space's own — e.g. dropping the `extra` findings for elements a
433
+ * sibling contract space declares, so the planner never emits DROP ops
434
+ * against another space's tables. The planner applies it blindly and holds
435
+ * no ownership logic. Absent for single-space plans.
436
+ */
437
+ readonly keepDiffIssue?: (issue: DiffIssue) => boolean;
394
438
  }
395
439
  interface SqlMigrationPlanner<TTargetDetails> {
396
440
  plan(options: SqlMigrationPlannerPlanOptions): SqlPlannerResult<TTargetDetails>;
@@ -495,6 +539,29 @@ interface SqlControlTargetDescriptor<TTargetId extends string, TTargetDetails, T
495
539
  * the base, the target-specific dispatch on the subclass.
496
540
  */
497
541
  readonly schemaVerifier: SchemaVerifier<TContract, SqlSchemaIR>;
542
+ /**
543
+ * Database→PSL inference for `contract infer`. Target logic (owns the dialect
544
+ * maps), so it lives on the descriptor. Optional: targets without `contract
545
+ * infer` (Mongo) omit it, and the family instance throws when it is absent.
546
+ */
547
+ readonly inferPslContract?: (schema: SqlSchemaIRNode) => PslDocumentAst;
548
+ /**
549
+ * The single combined database-schema diff of two derived representations —
550
+ * the target's black-box comparison. Every SQL target provides it (Postgres
551
+ * returns relational + policy issues; SQLite returns relational only). It is
552
+ * schema logic on the target, not database I/O, so it lives here rather than
553
+ * on the control adapter. How it computes the two issue sets is private.
554
+ * See {@link SqlDiffDatabaseSchema} / {@link SqlVerifyDatabaseSchema}.
555
+ */
556
+ readonly diffDatabaseSchema: SqlDiffDatabaseSchema;
557
+ /**
558
+ * The same combined comparison as {@link diffDatabaseSchema}, wrapped in the
559
+ * verify envelope (`ok`/`summary`/`code`/`target`/`timings`) plus the
560
+ * pass/warn/fail tree the CLI renders. Verify calls this instead of
561
+ * `diffDatabaseSchema` so the relational walk that produces the tree runs
562
+ * once per verify, not once for the diff and again for the tree.
563
+ */
564
+ readonly verifyDatabaseSchema: SqlVerifyDatabaseSchema;
498
565
  createPlanner(adapter: SqlControlAdapter<TTargetId>): SqlMigrationPlanner<TTargetDetails>;
499
566
  createRunner(family: SqlControlFamilyInstance): SqlMigrationRunner<TTargetDetails>;
500
567
  }
@@ -517,4 +584,4 @@ interface CreateSqlMigrationPlanOptions<TTargetDetails> {
517
584
  }
518
585
  //#endregion
519
586
  export { SqlPlannerResult as A, SqlMigrationRunnerResult as C, SqlPlannerConflictKind as D, SqlPlannerConflict as E, StorageTypePlanResult as M, SqlControlFamilyInstance as N, SqlPlannerConflictLocation as O, SqlMigrationRunnerFailure as S, SqlPlanTargetDetails as T, SqlMigrationPlannerPlanOptions as _, FieldEvent as a, SqlMigrationRunnerExecuteCallbacks as b, SqlControlAdapterDescriptor as c, SqlMigrationPlan as d, SqlMigrationPlanContractInfo as f, SqlMigrationPlanner as g, SqlMigrationPlanOperationTarget as h, ExpandNativeTypeInput as i, SqlPlannerSuccessResult as j, SqlPlannerFailureResult as k, SqlControlExtensionDescriptor as l, SqlMigrationPlanOperationStep as m, CodecControlHooks as n, FieldEventContext as o, SqlMigrationPlanOperation as p, CreateSqlMigrationPlanOptions as r, ResolveIdentityValueInput as s, AnyRecord as t, SqlControlTargetDescriptor as u, SqlMigrationRunner as v, SqlMigrationRunnerSuccessValue as w, SqlMigrationRunnerExecuteOptions as x, SqlMigrationRunnerErrorCode as y };
520
- //# sourceMappingURL=types-BxsFkHYv.d.mts.map
587
+ //# sourceMappingURL=types-CkOIJXxU.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-CkOIJXxU.d.mts","names":[],"sources":["../src/core/control-instance.ts","../src/core/migrations/schema-differ.ts","../src/core/migrations/types.ts"],"mappings":"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"}