@prisma/orm-family-sql 8.0.0-rc.11-dev.16 → 8.0.0-rc.11-dev.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/{authoring-type-constructors-BD-XuavC-CJV-TxFh.mjs → authoring-type-constructors-BD-XuavC-CW5J4Z8r.mjs} +2 -2
  2. package/dist/{authoring-type-constructors-BD-XuavC-CJV-TxFh.mjs.map → authoring-type-constructors-BD-XuavC-CW5J4Z8r.mjs.map} +1 -1
  3. package/dist/{config-types-BNJgLUUQ.mjs → config-types-tDX8p7v3.mjs} +2 -2
  4. package/dist/{config-types-BNJgLUUQ.mjs.map → config-types-tDX8p7v3.mjs.map} +1 -1
  5. package/dist/{contract-builder-De_sioHE.d.mts → contract-builder-Bwe2diF2.d.mts} +14 -5
  6. package/dist/{contract-builder-De_sioHE.d.mts.map → contract-builder-Bwe2diF2.d.mts.map} +1 -1
  7. package/dist/{contract-builder-BOmEsrRi.mjs → contract-builder-D1f6k8r4.mjs} +2 -2
  8. package/dist/{contract-builder-BOmEsrRi.mjs.map → contract-builder-D1f6k8r4.mjs.map} +1 -1
  9. package/dist/contract-prisma7__provider.d.mts +85 -0
  10. package/dist/contract-prisma7__provider.d.mts.map +1 -0
  11. package/dist/contract-prisma7__provider.mjs +1648 -0
  12. package/dist/contract-prisma7__provider.mjs.map +1 -0
  13. package/dist/contract-psl.d.mts +4 -3
  14. package/dist/contract-psl.d.mts.map +1 -1
  15. package/dist/contract-psl.mjs +1 -1
  16. package/dist/contract-psl__attribute-specs.d.mts +3 -3
  17. package/dist/contract-psl__attribute-specs.d.mts.map +1 -1
  18. package/dist/contract-psl__attribute-specs.mjs +1 -1
  19. package/dist/contract-psl__provider.mjs +5 -5
  20. package/dist/contract-psl__provider.mjs.map +1 -1
  21. package/dist/contract-ts.d.mts +2 -2
  22. package/dist/contract-ts.mjs +3 -3
  23. package/dist/contract-ts__config-types.mjs +1 -1
  24. package/dist/contract-ts__contract-builder.d.mts +2 -2
  25. package/dist/contract-ts__contract-builder.mjs +2 -2
  26. package/dist/{control-CYQ2U777.d.mts → control-CvOB6L1w.d.mts} +12 -11
  27. package/dist/control-CvOB6L1w.d.mts.map +1 -0
  28. package/dist/{control-adapter-C99J7aEF-CUDc48SO.d.mts → control-adapter-C99J7aEF-BLc1Uog8.d.mts} +3 -3
  29. package/dist/{control-adapter-C99J7aEF-CUDc48SO.d.mts.map → control-adapter-C99J7aEF-BLc1Uog8.d.mts.map} +1 -1
  30. package/dist/control-adapter-DfLKiViv.d.mts +1 -0
  31. package/dist/{control-BNXN-KA4.mjs → control-xNkuCauS.mjs} +4 -4
  32. package/dist/control-xNkuCauS.mjs.map +1 -0
  33. package/dist/{derived-checks-DGjY5t7S-B3txNm7X.mjs → derived-checks-DGjY5t7S-CzJmkeZR.mjs} +2 -2
  34. package/dist/{derived-checks-DGjY5t7S-B3txNm7X.mjs.map → derived-checks-DGjY5t7S-CzJmkeZR.mjs.map} +1 -1
  35. package/dist/{diff-CFhK3Q3k.d.mts → diff-Dz5kQO4e.d.mts} +6 -6
  36. package/dist/{diff-CFhK3Q3k.d.mts.map → diff-Dz5kQO4e.d.mts.map} +1 -1
  37. package/dist/family.d.mts +9 -9
  38. package/dist/family.mjs +4 -4
  39. package/dist/family__control-adapter.d.mts +2 -2
  40. package/dist/family__control.d.mts +4 -4
  41. package/dist/family__control.mjs +3 -3
  42. package/dist/family__diff.d.mts +2 -2
  43. package/dist/family__migration.d.mts +1 -1
  44. package/dist/family__pack.d.mts +1 -1
  45. package/dist/family__pack.d.mts.map +1 -1
  46. package/dist/family__pack.mjs +2 -2
  47. package/dist/family__psl-infer.d.mts +2 -2
  48. package/dist/family__psl-infer.mjs +2 -2
  49. package/dist/{interpreter-C_i0NCiB-CptD-6Yu.mjs → interpreter-QDw8KJeP-Bc93B8xi.mjs} +52 -8
  50. package/dist/interpreter-QDw8KJeP-Bc93B8xi.mjs.map +1 -0
  51. package/dist/{migration-CkjRhB8h.d.mts → migration-D5C6JC3c.d.mts} +2 -2
  52. package/dist/{migration-CkjRhB8h.d.mts.map → migration-D5C6JC3c.d.mts.map} +1 -1
  53. package/dist/{psl-infer-TBwKfKgU.mjs → psl-infer-CPQSp4tG.mjs} +2 -84
  54. package/dist/psl-infer-CPQSp4tG.mjs.map +1 -0
  55. package/dist/{psl-infer-CCAD6FWA.d.mts → psl-infer-tLt9U1UP.d.mts} +4 -7
  56. package/dist/{psl-infer-CCAD6FWA.d.mts.map → psl-infer-tLt9U1UP.d.mts.map} +1 -1
  57. package/dist/{schema-differ-DpG_gnur-BICVtTHY.d.mts → schema-differ-DpG_gnur-CLds_Z0t.d.mts} +3 -3
  58. package/dist/{schema-differ-DpG_gnur-BICVtTHY.d.mts.map → schema-differ-DpG_gnur-CLds_Z0t.d.mts.map} +1 -1
  59. package/dist/schema-ir.d.mts +1 -1
  60. package/dist/schema-ir.mjs +1 -1
  61. package/dist/schema-ir__types.d.mts +2 -2
  62. package/dist/schema-ir__types.mjs +1 -1
  63. package/dist/{sql-attribute-specs-BCJ_CDJH-CfH1ddqf.mjs → sql-attribute-specs-BnUIuOy5-8t7OYHpi.mjs} +5 -5
  64. package/dist/sql-attribute-specs-BnUIuOy5-8t7OYHpi.mjs.map +1 -0
  65. package/dist/types-9RtQn3mX.d.mts +1 -0
  66. package/dist/{types-YStFFkKs-D9UAmnON.d.mts → types-C6k9x_Je-DkvHNHEX.d.mts} +18 -2
  67. package/dist/types-C6k9x_Je-DkvHNHEX.d.mts.map +1 -0
  68. package/dist/{types-BvupgHcG-c8QDupnu.mjs → types-CZn-8Rsg-Bv6arhpI.mjs} +73 -13
  69. package/dist/types-CZn-8Rsg-Bv6arhpI.mjs.map +1 -0
  70. package/dist/{types-IqZMLrFC-BQmtKloA.d.mts → types-IqZMLrFC-BAUPBjE5.d.mts} +4 -4
  71. package/dist/{types-IqZMLrFC-BQmtKloA.d.mts.map → types-IqZMLrFC-BAUPBjE5.d.mts.map} +1 -1
  72. package/package.json +19 -17
  73. package/dist/control-BNXN-KA4.mjs.map +0 -1
  74. package/dist/control-CYQ2U777.d.mts.map +0 -1
  75. package/dist/control-adapter-BPttH3He.d.mts +0 -1
  76. package/dist/interpreter-C_i0NCiB-CptD-6Yu.mjs.map +0 -1
  77. package/dist/psl-infer-TBwKfKgU.mjs.map +0 -1
  78. package/dist/sql-attribute-specs-BCJ_CDJH-CfH1ddqf.mjs.map +0 -1
  79. package/dist/types-BvupgHcG-c8QDupnu.mjs.map +0 -1
  80. package/dist/types-Dwcw0F8X.d.mts +0 -1
  81. package/dist/types-YStFFkKs-D9UAmnON.d.mts.map +0 -1
@@ -0,0 +1,1648 @@
1
+ import { l as validateSqlStorageConsistency, s as validateModelStorageReferences } from "./validators-DD98VrpC.mjs";
2
+ import { t as deriveValueSetFromEntity } from "./value-set-derivation-hook-Di9JZ0X7.mjs";
3
+ import { n as buildSqlContractFromDefinition, t as applySqlSpecifierControlPolicy } from "./derived-checks-DGjY5t7S-CzJmkeZR.mjs";
4
+ import { a as normalizeReferentialAction, n as buildEntityTypesByDiscriminator, o as numberLiteralDefault, r as indexFkRelations, s as resolveFieldTypeDescriptor, t as applyBackrelationCandidates } from "./interpreter-QDw8KJeP-Bc93B8xi.mjs";
5
+ import { isStructuredError } from "@prisma/orm-framework/utils/structured-error";
6
+ import { collectScalarTypeConstructors, instantiateAuthoringEntityType } from "@prisma/orm-framework/components/authoring";
7
+ import { InternalError } from "@prisma/orm-framework/utils/internal-error";
8
+ import { ifDefined } from "@prisma/orm-framework/utils/defined";
9
+ import { blindCast } from "@prisma/orm-framework/utils/casts";
10
+ import { validateContractDomain } from "@prisma/orm-framework/contract/validate-domain";
11
+ import { readFile, readdir, stat } from "node:fs/promises";
12
+ import { buildSymbolTable, keywordPslSpan, nodePslSpan, rangeToPslSpan, readResolvedAttribute, readResolvedAttributes } from "@prisma/orm-framework/psl-parser";
13
+ import { ArrayLiteralAst, BooleanLiteralExprAst, FunctionCallAst, IdentifierAst, NumberLiteralExprAst, StringLiteralExprAst, parse, printSyntax } from "@prisma/orm-framework/psl-parser/syntax";
14
+ import { notOk, ok } from "@prisma/orm-framework/utils/result";
15
+ import { basename, dirname, extname, join, normalize } from "pathe";
16
+ import { fkRelationPairKey } from "@prisma/orm-framework/psl-parser/interpret";
17
+ //#region ../../../2-sql/2-authoring/contract-prisma7/dist/provider.mjs
18
+ function prisma7Diagnostic(code, message, sourceId, span) {
19
+ return {
20
+ code,
21
+ message,
22
+ sourceId,
23
+ ...span !== void 0 ? { span } : {}
24
+ };
25
+ }
26
+ function andList(items) {
27
+ const leading = items.slice(0, -1);
28
+ const last = items[items.length - 1] ?? "";
29
+ return leading.length === 0 ? last : `${leading.join(", ")} and ${last}`;
30
+ }
31
+ function fieldList(modelName, fieldNames) {
32
+ return andList(fieldNames.map((name) => `"${modelName}.${name}"`));
33
+ }
34
+ function ignoredFieldReferenced(input) {
35
+ const fields = fieldList(input.modelName, input.fieldNames);
36
+ const one = input.fieldNames.length === 1;
37
+ return prisma7Diagnostic("PSL.PRISMA7_IGNORED_FIELD_REFERENCED", `${one ? "Field" : "Fields"} ${fields} ${one ? "is" : "are"} marked @ignore, but ${input.usedBy} uses ${one ? "it" : "them"}, and Prisma 7 still creates the ${input.constraint} that includes ${one ? "its column" : "their columns"}. Remove @ignore from ${fields}; Prisma 7's next migration is then empty, and ${one ? "the field appears" : "the fields appear"} in the Prisma 7 client again.`, input.sourceId, input.span);
38
+ }
39
+ const CLIENT_SIDE_GENERATORS = /* @__PURE__ */ new Set([
40
+ "uuid",
41
+ "cuid",
42
+ "ulid",
43
+ "nanoid"
44
+ ]);
45
+ function givesColumnDefault(attribute) {
46
+ const expression = attribute?.args.find((arg) => arg.kind === "positional")?.expression;
47
+ if (expression === void 0) return false;
48
+ const call = FunctionCallAst.cast(expression.syntax);
49
+ if (call === void 0) return true;
50
+ const fn = call.path().join(".");
51
+ if (CLIENT_SIDE_GENERATORS.has(fn)) return false;
52
+ return fn !== "dbgenerated" || [...call.args()].length > 0;
53
+ }
54
+ /** Positional argument keys per Prisma 7 default function, matching the target registry's signatures. */
55
+ const FUNCTION_ARGUMENT_KEYS = {
56
+ uuid: ["version"],
57
+ cuid: ["version"],
58
+ nanoid: ["size"],
59
+ dbgenerated: ["expression"],
60
+ now: [],
61
+ autoincrement: [],
62
+ ulid: []
63
+ };
64
+ function literalArgument(expression) {
65
+ const text = StringLiteralExprAst.cast(expression.syntax)?.value();
66
+ if (text !== void 0) return text;
67
+ const number = NumberLiteralExprAst.cast(expression.syntax)?.value();
68
+ if (number !== void 0) return number;
69
+ return BooleanLiteralExprAst.cast(expression.syntax)?.value();
70
+ }
71
+ function lowerPrisma7Default(input) {
72
+ const { attribute, field, sourceId, diagnostics } = input;
73
+ const label = `Field "${input.modelName}.${field.name}"`;
74
+ const unknown = (reason, span) => {
75
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_DEFAULT", `${label}: @default ${reason}`, sourceId, span));
76
+ };
77
+ const argument = attribute.args.find((arg) => arg.kind === "positional");
78
+ const expression = argument?.expression;
79
+ if (argument === void 0 || expression === void 0) return unknown("needs one value.", attribute.span);
80
+ const call = FunctionCallAst.cast(expression.syntax);
81
+ if (call !== void 0) return lowerFunction(call, input, label, unknown);
82
+ const rawLiteral = input.literalForm?.kind === "sqlExpression" ? sqlExpressionDefault(expression, input.literalForm, input.field.list) : void 0;
83
+ if (rawLiteral === "unreadable") return unknown("holds a value this contract source does not read.", attribute.span);
84
+ if (rawLiteral !== void 0) return {
85
+ storage: {
86
+ kind: "function",
87
+ expression: rawLiteral.expression
88
+ },
89
+ onCreate: void 0
90
+ };
91
+ const scalar = scalarValue$1(expression, input, unknown);
92
+ if (scalar === void 0) return void 0;
93
+ return {
94
+ storage: {
95
+ kind: "literal",
96
+ value: scalar
97
+ },
98
+ onCreate: void 0
99
+ };
100
+ }
101
+ function scalarValue$1(expression, input, unknown) {
102
+ const span = input.attribute.span;
103
+ const isJson = input.literalForm?.kind === "json";
104
+ const jsonNull = (holds) => {
105
+ input.diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_JSON_NULL_DEFAULT_UNSUPPORTED", `Field "${input.modelName}.${input.field.name}": @default(${printSyntax(expression.syntax).trim()}) ${holds} the JSON value null, which the contract cannot tell apart from SQL NULL. Remove the @default or give it another JSON value; either changes the column default on Prisma 7's next migration.`, input.sourceId, span));
106
+ };
107
+ const array = ArrayLiteralAst.cast(expression.syntax);
108
+ if (array !== void 0) {
109
+ const values = [];
110
+ for (const element of array.elements()) {
111
+ const value = elementValue(element, input);
112
+ if (value === void 0) return unknown(rejectedNumberReason(element, input) ?? "lists may only hold literals or enum members.", span);
113
+ values.push(value);
114
+ }
115
+ if (isJson && values.includes(null)) return jsonNull("holds");
116
+ return values;
117
+ }
118
+ const value = elementValue(expression, input);
119
+ if (isJson && value === null) return jsonNull("is");
120
+ if (value !== void 0) return value;
121
+ const numberReason = rejectedNumberReason(expression, input);
122
+ if (numberReason !== void 0) return unknown(numberReason, span);
123
+ const identifier = IdentifierAst.cast(expression.syntax)?.name();
124
+ if (identifier !== void 0) return unknown(input.enumMembers === void 0 ? `refers to "${identifier}", but the field is not an enum.` : `refers to "${identifier}", which is not a member of the field's enum.`, span);
125
+ return unknown("holds a value this contract source does not read.", span);
126
+ }
127
+ function sqlExpressionDefault(expression, form, isList) {
128
+ const array = isList ? ArrayLiteralAst.cast(expression.syntax) : void 0;
129
+ if (array === void 0) {
130
+ const text = StringLiteralExprAst.cast(expression.syntax)?.value();
131
+ if (text === void 0) return void 0;
132
+ const literal = form.literal(text);
133
+ return literal === void 0 ? "unreadable" : { expression: literal };
134
+ }
135
+ const literals = [];
136
+ for (const element of array.elements()) {
137
+ const text = StringLiteralExprAst.cast(element.syntax)?.value();
138
+ const literal = text === void 0 ? void 0 : form.literal(text);
139
+ if (literal === void 0) return "unreadable";
140
+ literals.push(literal);
141
+ }
142
+ return { expression: form.list(literals) };
143
+ }
144
+ /** The Prisma 7 scalars whose number defaults must be whole numbers, as each is named in a message. */
145
+ const WHOLE_NUMBER_SCALARS = {
146
+ Int: "an Int",
147
+ BigInt: "a BigInt"
148
+ };
149
+ const WHOLE_NUMBER_TEXT = /^-?\d+$/;
150
+ /** The number literal the column codec reads neither as a number nor as text, such as `1.5` for a `BigInt`, which Prisma 7 rejects too. */
151
+ function rejectedNumberReason(expression, input) {
152
+ const text = NumberLiteralExprAst.cast(expression.syntax)?.token()?.text;
153
+ if (text === void 0 || numberValue(text, input) !== void 0) return void 0;
154
+ const { typeName } = input.field;
155
+ const wholeNumberScalar = Object.hasOwn(WHOLE_NUMBER_SCALARS, typeName) ? WHOLE_NUMBER_SCALARS[typeName] : void 0;
156
+ return wholeNumberScalar === void 0 ? `holds ${text}, which is not a valid ${typeName} value.` : `holds ${text}, which is not an integer; ${wholeNumberScalar} default must be a whole number.`;
157
+ }
158
+ /** A number default for the field: Prisma 7 accepts only whole numbers for `Int` and `BigInt`. */
159
+ function numberValue(text, input) {
160
+ if (Object.hasOwn(WHOLE_NUMBER_SCALARS, input.field.typeName) && !WHOLE_NUMBER_TEXT.test(text)) return;
161
+ return numberLiteralDefault(text, input.codecId, input.codecLookup);
162
+ }
163
+ function elementValue(expression, input) {
164
+ const member = IdentifierAst.cast(expression.syntax)?.name();
165
+ if (member !== void 0) return input.enumMembers?.get(member);
166
+ const number = NumberLiteralExprAst.cast(expression.syntax)?.token()?.text;
167
+ if (number !== void 0) return numberValue(number, input);
168
+ const text = StringLiteralExprAst.cast(expression.syntax)?.value();
169
+ if (text !== void 0) {
170
+ if (input.literalForm?.kind === "json") try {
171
+ return blindCast(JSON.parse(text));
172
+ } catch {
173
+ return;
174
+ }
175
+ return text;
176
+ }
177
+ return BooleanLiteralExprAst.cast(expression.syntax)?.value();
178
+ }
179
+ function lowerFunction(call, input, label, unknown) {
180
+ const fn = call.path().join(".");
181
+ const span = input.attribute.span;
182
+ const callArgs = [...call.args()];
183
+ if (fn === "dbgenerated" && callArgs.length === 0) {
184
+ if (input.field.optional || input.field.list) return {
185
+ storage: void 0,
186
+ onCreate: void 0
187
+ };
188
+ input.diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_DEFAULT", `${label}: @default(dbgenerated()) with no expression is not supported yet on a required field, because without a column default Prisma 8 requires the value on create. Either remove the @default, which makes Prisma 7's next migration drop the column default (ALTER COLUMN ... DROP DEFAULT) and both clients require the value on create, or write the column's database default as @default(dbgenerated("<expression>")), which Prisma 7's next migration sets on the column.`, input.sourceId, span));
189
+ return;
190
+ }
191
+ const keys = FUNCTION_ARGUMENT_KEYS[fn];
192
+ const entry = input.controlMutationDefaults.defaultFunctionRegistry.get(fn);
193
+ if (keys === void 0 || entry === void 0) return unknown(`function "${fn}()" is not a Prisma 7 default function this target supports.`, span);
194
+ const args = {};
195
+ let index = 0;
196
+ for (const arg of callArgs) {
197
+ const key = arg.name()?.name() ?? keys[index];
198
+ const value = arg.value();
199
+ const literal = value === void 0 ? void 0 : literalArgument(value);
200
+ if (key === void 0 || literal === void 0) return unknown(`function "${fn}()" has an argument this contract source does not read.`, span);
201
+ args[key] = literal;
202
+ index += 1;
203
+ }
204
+ if (fn === "cuid") args["version"] = 2;
205
+ const lowered = entry.lower({
206
+ call: {
207
+ fn,
208
+ span,
209
+ args
210
+ },
211
+ context: {
212
+ sourceId: input.sourceId,
213
+ modelName: input.modelName,
214
+ fieldName: input.field.name,
215
+ columnCodecId: input.codecId
216
+ }
217
+ });
218
+ if (!lowered.ok) {
219
+ input.diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_DEFAULT", `${label}: ${lowered.diagnostic.message}`, input.sourceId, span));
220
+ return;
221
+ }
222
+ return lowered.value.kind === "storage" ? {
223
+ storage: lowered.value.defaultValue,
224
+ onCreate: void 0
225
+ } : {
226
+ storage: void 0,
227
+ onCreate: lowered.value.generated
228
+ };
229
+ }
230
+ function parseIndexAttribute(attribute, owner, sourceId, indexTypes, diagnostics) {
231
+ const unsupported = (what, span) => {
232
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_INDEX_ARGUMENT_UNSUPPORTED", `"${owner}": @${attribute.name} ${what}`, sourceId, span));
233
+ };
234
+ let fields;
235
+ let map;
236
+ let type;
237
+ for (const arg of attribute.args) {
238
+ const key = arg.kind === "positional" ? "fields" : arg.name;
239
+ const expression = arg.expression;
240
+ switch (key) {
241
+ case "fields": {
242
+ const array = expression === void 0 ? void 0 : ArrayLiteralAst.cast(expression.syntax);
243
+ if (array === void 0) return unsupported("expects a list of field names.", arg.span);
244
+ const names = [];
245
+ for (const element of array.elements()) {
246
+ const name = IdentifierAst.cast(element.syntax)?.name();
247
+ if (name === void 0) return unsupported("field arguments such as sort or length are not supported; Prisma 8 indexes carry none.", arg.span);
248
+ names.push(name);
249
+ }
250
+ fields = names;
251
+ break;
252
+ }
253
+ case "map":
254
+ map = expression === void 0 ? void 0 : StringLiteralExprAst.cast(expression.syntax)?.value();
255
+ if (map === void 0) return unsupported("map must be a string.", arg.span);
256
+ break;
257
+ case "name": break;
258
+ case "type": {
259
+ const token = expression === void 0 ? void 0 : IdentifierAst.cast(expression.syntax)?.name();
260
+ type = token !== void 0 && Object.hasOwn(indexTypes, token) ? indexTypes[token] : void 0;
261
+ if (type === void 0) return unsupported(`type "${token ?? ""}" is not an index type Prisma 8 supports.`, arg.span);
262
+ break;
263
+ }
264
+ default: return unsupported(`argument "${key ?? ""}" is not supported.`, arg.span);
265
+ }
266
+ }
267
+ return {
268
+ fields,
269
+ map,
270
+ type,
271
+ span: attribute.span
272
+ };
273
+ }
274
+ const utf8 = new TextEncoder();
275
+ /**
276
+ * A generated constraint name as Prisma 7 spells it: `base` cut so that
277
+ * `base + suffix` is at most `maxBytes` bytes, cut on a character boundary,
278
+ * with the suffix kept whole. Prisma 7.10.0 emits `..._aVeryLongCo_idx` for a
279
+ * long `@@index`, `..._AB_pkey` and `..._B_index` for a long implicit junction,
280
+ * and cuts a multi-byte name before the character that would cross the budget.
281
+ */
282
+ function prisma7ConstraintName(base, suffix, maxBytes) {
283
+ const budget = maxBytes - utf8.encode(suffix).length;
284
+ let bytes = 0;
285
+ let kept = "";
286
+ for (const character of base) {
287
+ bytes += utf8.encode(character).length;
288
+ if (bytes > budget) break;
289
+ kept += character;
290
+ }
291
+ return `${kept}${suffix}`;
292
+ }
293
+ /** Prisma 7's default index name: `{table}_{columns}_idx`, or `_key` for a unique index, cut to `maxBytes`. */
294
+ function defaultIndexName(tableName, columns, unique, maxBytes) {
295
+ return prisma7ConstraintName(`${tableName}_${columns.join("_")}`, unique ? "_key" : "_idx", maxBytes);
296
+ }
297
+ function indexNode(tableName, columns, attribute, unique, maxBytes) {
298
+ return {
299
+ columns,
300
+ ...attribute.type === void 0 ? {
301
+ type: void 0,
302
+ options: void 0
303
+ } : {
304
+ type: attribute.type,
305
+ options: {}
306
+ },
307
+ where: void 0,
308
+ unique: unique ? true : void 0,
309
+ map: attribute.map ?? defaultIndexName(tableName, columns, unique, maxBytes),
310
+ name: void 0
311
+ };
312
+ }
313
+ function prisma7ScalarMapping(typeMap, scalar) {
314
+ return Object.hasOwn(typeMap.scalars, scalar) ? typeMap.scalars[scalar] : void 0;
315
+ }
316
+ function prisma7NativeTypeMapping(typeMap, nativeType, args) {
317
+ const mapping = Object.hasOwn(typeMap.nativeTypes, nativeType) ? typeMap.nativeTypes[nativeType] : void 0;
318
+ if (mapping === void 0) return void 0;
319
+ return args.length === 0 ? mapping : {
320
+ constructorName: mapping.constructorName,
321
+ args
322
+ };
323
+ }
324
+ /** The codes `applyBackrelationCandidates` reports, each shown as `PSL.PRISMA7_RELATION_UNRESOLVED`. */
325
+ const RELATION_PAIRING_CODES = /* @__PURE__ */ new Set([
326
+ "PSL_ORPHANED_BACKRELATION",
327
+ "PSL_AMBIGUOUS_BACKRELATION",
328
+ "PSL_NON_UNIQUE_BACKRELATION",
329
+ "PSL_REQUIRED_ONE_TO_ONE_BACKRELATION",
330
+ "PSL_JUNCTION_ID_NOT_FK_COVERING",
331
+ "PSL_JUNCTION_TARGET_FK_NOT_ID"
332
+ ]);
333
+ function identifierNames(expression) {
334
+ if (expression === void 0) return void 0;
335
+ const array = ArrayLiteralAst.cast(expression.syntax);
336
+ if (array === void 0) return void 0;
337
+ const names = [];
338
+ for (const element of array.elements()) {
339
+ const name = IdentifierAst.cast(element.syntax)?.name();
340
+ if (name === void 0) return void 0;
341
+ names.push(name);
342
+ }
343
+ return names;
344
+ }
345
+ function stringValue(expression) {
346
+ return expression === void 0 ? void 0 : StringLiteralExprAst.cast(expression.syntax)?.value();
347
+ }
348
+ const PRISMA7_REFERENTIAL_ACTIONS = /* @__PURE__ */ new Set([
349
+ "Cascade",
350
+ "Restrict",
351
+ "NoAction",
352
+ "SetNull",
353
+ "SetDefault"
354
+ ]);
355
+ function actionValue(expression) {
356
+ const token = expression === void 0 ? void 0 : IdentifierAst.cast(expression.syntax)?.name();
357
+ return token !== void 0 && PRISMA7_REFERENTIAL_ACTIONS.has(token) ? normalizeReferentialAction(token) : void 0;
358
+ }
359
+ function parseRelationAttribute(attribute, label, sourceId, diagnostics) {
360
+ let name;
361
+ let fields;
362
+ let references;
363
+ let onDelete;
364
+ let onUpdate;
365
+ const invalid = (what, span) => {
366
+ diagnostics.push({
367
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
368
+ message: `${label}: @relation ${what}.`,
369
+ sourceId,
370
+ span
371
+ });
372
+ };
373
+ for (const arg of attribute.args) {
374
+ const key = arg.kind === "positional" ? "name" : arg.name;
375
+ switch (key) {
376
+ case "name":
377
+ name = stringValue(arg.expression);
378
+ if (name === void 0) return invalid("name must be a string", arg.span);
379
+ break;
380
+ case "fields":
381
+ fields = identifierNames(arg.expression);
382
+ if (fields === void 0) return invalid("fields must be a list of field names", arg.span);
383
+ break;
384
+ case "references":
385
+ references = identifierNames(arg.expression);
386
+ if (references === void 0) return invalid("references must be a list of field names", arg.span);
387
+ break;
388
+ case "onDelete":
389
+ onDelete = actionValue(arg.expression);
390
+ if (onDelete === void 0) return invalid("onDelete must be a referential action", arg.span);
391
+ break;
392
+ case "onUpdate":
393
+ onUpdate = actionValue(arg.expression);
394
+ if (onUpdate === void 0) return invalid("onUpdate must be a referential action", arg.span);
395
+ break;
396
+ case "map": break;
397
+ default: return invalid(`argument "${key ?? ""}" is not supported`, arg.span);
398
+ }
399
+ }
400
+ return {
401
+ name,
402
+ fields,
403
+ references,
404
+ onDelete,
405
+ onUpdate,
406
+ span: attribute.span
407
+ };
408
+ }
409
+ function columnNames(model, fieldNames) {
410
+ const columns = [];
411
+ for (const fieldName of fieldNames) {
412
+ const column = model.columns.get(fieldName);
413
+ if (column === void 0) return void 0;
414
+ columns.push(column.columnName);
415
+ }
416
+ return columns;
417
+ }
418
+ function unresolved(label, reason, sourceId, span) {
419
+ return prisma7Diagnostic("PSL.PRISMA7_RELATION_UNRESOLVED", `${label} ${reason}`, sourceId, span);
420
+ }
421
+ function groupBy(items, keyOf) {
422
+ const groups = /* @__PURE__ */ new Map();
423
+ for (const item of items) {
424
+ const group = groups.get(keyOf(item)) ?? [];
425
+ groups.set(keyOf(item), group);
426
+ group.push(item);
427
+ }
428
+ return groups;
429
+ }
430
+ function orderJunctionSides(requester, partner) {
431
+ return (requester.model === partner.model ? requester.field.field.name < partner.field.field.name : requester.model.modelName < partner.model.modelName) ? [requester, partner] : [partner, requester];
432
+ }
433
+ function junctionKey(namespaceId, name) {
434
+ return JSON.stringify([namespaceId, name]);
435
+ }
436
+ /**
437
+ * Prisma 7's default relation name: the two model names in alphabetical
438
+ * order joined by `To`. Giving every unnamed relation that name lets the
439
+ * shared pairing helper match Prisma 7's rule that an unnamed side pairs only
440
+ * with the unnamed side of the same model pair.
441
+ */
442
+ function effectiveRelationName(attribute, modelName, targetModelName) {
443
+ if (attribute?.name !== void 0) return attribute.name;
444
+ const [first, second] = modelName < targetModelName ? [modelName, targetModelName] : [targetModelName, modelName];
445
+ return `${first}To${second}`;
446
+ }
447
+ /**
448
+ * Prisma 7 accepts `SetNull` over a required field and `SetDefault` over a
449
+ * required field with no default, and writes them into the foreign key; the
450
+ * contract rejects both, because the action would fail the first time it runs.
451
+ */
452
+ function referentialActionRejections(input) {
453
+ const { model, relationField, label, fieldNames, span } = input;
454
+ const anotherAction = "choose another action, which replaces the foreign key on Prisma 7's next migration and leaves the Prisma 7 client unchanged.";
455
+ const fieldsWhere = (predicate) => fieldNames.filter((name) => {
456
+ const column = model.columns.get(name);
457
+ return column !== void 0 && predicate(column);
458
+ });
459
+ const rejections = [];
460
+ for (const [key, action] of Object.entries(input.actions)) {
461
+ if (action === "setNull") {
462
+ const required = fieldsWhere((column) => !column.nullable);
463
+ if (required.length === 0) continue;
464
+ const fields = fieldList(model.modelName, required);
465
+ rejections.push(prisma7Diagnostic("PSL.PRISMA7_REFERENTIAL_ACTION_UNSUPPORTED", `${label}: ${key}: SetNull sets the foreign key fields to null, but ${fields} ${required.length === 1 ? "is" : "are"} required, so Prisma 8 cannot describe this foreign key. Make ${fields}${relationField.optional ? "" : ` and "${model.modelName}.${relationField.name}"`} optional, which drops NOT NULL on Prisma 7's next migration and makes ${required.length === 1 && relationField.optional ? "it" : "them"} nullable in the Prisma 7 client, or ${anotherAction}`, model.sourceId, span));
466
+ }
467
+ if (action === "setDefault") {
468
+ const withoutDefault = fieldsWhere((column) => !column.nullable && column.default === void 0);
469
+ if (withoutDefault.length === 0) continue;
470
+ const fields = fieldList(model.modelName, withoutDefault);
471
+ const one = withoutDefault.length === 1;
472
+ const generated = withoutDefault.filter((name) => model.columns.get(name)?.executionDefaults?.onCreate !== void 0);
473
+ const plain = withoutDefault.filter((name) => !generated.includes(name));
474
+ const generatorNote = generated.length > 0 ? " (a client-side generator such as uuid() does not give the column one)" : "";
475
+ const example = "a column default, such as a literal or @default(dbgenerated(\"<expression>\"))";
476
+ const plainFields = fieldList(model.modelName, plain);
477
+ const generatedFields = fieldList(model.modelName, generated);
478
+ const edit = generated.length === 0 ? `Give ${plainFields} ${example}` : plain.length === 0 ? `Replace the @default on ${generatedFields} with ${example}, because a field takes only one @default` : `Give ${plainFields} ${example}, and replace the @default on ${generatedFields} with one, because a field takes only one @default`;
479
+ const effects = [
480
+ `Prisma 7's next migration sets ${one ? "it" : "them"}`,
481
+ ...plain.length > 0 ? [`${plainFields} ${plain.length === 1 ? "becomes" : "become"} optional when creating records with the Prisma 7 client`] : [],
482
+ ...generated.length > 0 ? [`the Prisma 7 client stops generating ${generated.length === 1 ? "a value" : "values"} for ${generatedFields}`] : []
483
+ ];
484
+ rejections.push(prisma7Diagnostic("PSL.PRISMA7_REFERENTIAL_ACTION_UNSUPPORTED", `${label}: ${key}: SetDefault sets the foreign key fields to their column defaults, but ${fields} ${one ? "is" : "are"} required and ${one ? "has" : "have"} no column default${generatorNote}, so Prisma 8 cannot describe this foreign key. ${edit}: ${andList(effects)}. Or ${anotherAction}`, model.sourceId, span));
485
+ }
486
+ }
487
+ return rejections;
488
+ }
489
+ function lowerRelations(models, naming, diagnostics) {
490
+ const fkRelationMetadata = [];
491
+ const candidates = [];
492
+ const invalidFkPairings = [];
493
+ const foreignKeys = /* @__PURE__ */ new Map();
494
+ const junctions = /* @__PURE__ */ new Map();
495
+ const reportedJunctionNames = /* @__PURE__ */ new Set();
496
+ const junctionRequests = [];
497
+ const addForeignKey = (modelName, node) => {
498
+ const existing = foreignKeys.get(modelName) ?? [];
499
+ foreignKeys.set(modelName, existing);
500
+ existing.push(node);
501
+ };
502
+ const isFkSide = (relationField) => relationField.attribute?.fields !== void 0;
503
+ const sameName = (left, right) => left.attribute?.name === right.attribute?.name;
504
+ const rejectFkSide = (model, relationField, ...rejections) => {
505
+ diagnostics.push(...rejections);
506
+ invalidFkPairings.push({
507
+ pairKey: fkRelationPairKey(model.modelName, relationField.targetModelName),
508
+ relationName: effectiveRelationName(relationField.attribute, model.modelName, relationField.targetModelName)
509
+ });
510
+ };
511
+ for (const model of models.values()) for (const relationField of model.relationFields) {
512
+ const { field, targetModelName } = relationField;
513
+ const label = `Relation field "${model.modelName}.${field.name}"`;
514
+ const target = models.get(targetModelName);
515
+ if (target === void 0) continue;
516
+ if (isFkSide(relationField)) {
517
+ const attribute = relationField.attribute;
518
+ if (attribute === void 0 || attribute.fields === void 0) continue;
519
+ const ignoredScalars = attribute.fields.filter((name) => model.ignoredFields.has(name));
520
+ if (ignoredScalars.length > 0) {
521
+ rejectFkSide(model, relationField, ignoredFieldReferenced({
522
+ modelName: model.modelName,
523
+ fieldNames: ignoredScalars,
524
+ usedBy: `relation field "${model.modelName}.${field.name}"`,
525
+ constraint: "foreign key",
526
+ sourceId: model.sourceId,
527
+ span: attribute.span
528
+ }));
529
+ continue;
530
+ }
531
+ if (attribute.references === void 0) {
532
+ rejectFkSide(model, relationField, unresolved(label, "declares fields without references.", model.sourceId, attribute.span));
533
+ continue;
534
+ }
535
+ if (attribute.fields.some((name) => model.rejectedFields.has(name)) || attribute.references.some((name) => target.ignoredFields.has(name) || target.rejectedFields.has(name))) {
536
+ rejectFkSide(model, relationField);
537
+ continue;
538
+ }
539
+ const localColumns = columnNames(model, attribute.fields);
540
+ const referencedColumns = columnNames(target, attribute.references);
541
+ if (localColumns === void 0 || referencedColumns === void 0) {
542
+ rejectFkSide(model, relationField, unresolved(label, "names a field that is not a scalar column of the model or its target.", model.sourceId, attribute.span));
543
+ continue;
544
+ }
545
+ if (localColumns.length !== referencedColumns.length) {
546
+ rejectFkSide(model, relationField, unresolved(label, "must list as many fields as references.", model.sourceId, attribute.span));
547
+ continue;
548
+ }
549
+ const nullability = attribute.fields.map((name) => model.columns.get(name)?.nullable === true);
550
+ const anyNullable = nullability.includes(true);
551
+ if (anyNullable && !field.optional) {
552
+ rejectFkSide(model, relationField, unresolved(label, "must be optional because one of its fields is optional.", model.sourceId, field.span));
553
+ continue;
554
+ }
555
+ const onDelete = attribute.onDelete ?? (nullability.includes(false) ? "restrict" : "setNull");
556
+ const onUpdate = attribute.onUpdate ?? "cascade";
557
+ const actionRejections = referentialActionRejections({
558
+ model,
559
+ relationField: field,
560
+ label,
561
+ fieldNames: attribute.fields,
562
+ actions: {
563
+ onDelete,
564
+ onUpdate
565
+ },
566
+ span: attribute.span
567
+ });
568
+ if (actionRejections.length > 0) {
569
+ rejectFkSide(model, relationField, ...actionRejections);
570
+ continue;
571
+ }
572
+ addForeignKey(model.modelName, {
573
+ columns: localColumns,
574
+ references: {
575
+ model: target.modelName,
576
+ table: target.tableName,
577
+ columns: referencedColumns,
578
+ namespaceId: target.namespaceId
579
+ },
580
+ onDelete,
581
+ onUpdate,
582
+ index: false
583
+ });
584
+ fkRelationMetadata.push({
585
+ declaringModelName: model.modelName,
586
+ declaringFieldName: field.name,
587
+ declaringTableName: model.tableName,
588
+ declaringNamespaceId: model.namespaceId,
589
+ targetModelName: target.modelName,
590
+ targetTableName: target.tableName,
591
+ targetNamespaceId: target.namespaceId,
592
+ relationName: effectiveRelationName(attribute, model.modelName, target.modelName),
593
+ nullable: anyNullable,
594
+ localColumns,
595
+ referencedColumns
596
+ });
597
+ continue;
598
+ }
599
+ if (target.ignoredRelationFields.some((other) => other.targetModelName === model.modelName && sameName(other, relationField))) continue;
600
+ if (target.relationFields.filter((other) => other.targetModelName === model.modelName && isFkSide(other) && sameName(other, relationField)).length > 0 || !field.list) {
601
+ candidates.push({
602
+ modelName: model.modelName,
603
+ tableName: model.tableName,
604
+ field,
605
+ targetModelName: target.modelName,
606
+ isList: field.list,
607
+ relationName: effectiveRelationName(relationField.attribute, model.modelName, target.modelName)
608
+ });
609
+ continue;
610
+ }
611
+ const partners = target.relationFields.filter((other) => other !== relationField && other.targetModelName === model.modelName && other.field.list && !isFkSide(other) && sameName(other, relationField));
612
+ const [partner] = partners;
613
+ if (partner === void 0) {
614
+ diagnostics.push(unresolved(label, `has no matching relation field on "${target.modelName}".`, model.sourceId, field.span));
615
+ continue;
616
+ }
617
+ if (partners.length > 1 || target === model && relationField.attribute?.name === void 0) {
618
+ diagnostics.push(unresolved(label, `is ambiguous: more than one list field on "${target.modelName}" could pair with it. Name both sides with @relation("name").`, model.sourceId, field.span));
619
+ continue;
620
+ }
621
+ const junctionName = effectiveRelationName(relationField.attribute, model.modelName, target.modelName);
622
+ const requester = {
623
+ model,
624
+ field: relationField
625
+ };
626
+ const partnerSide = {
627
+ model: target,
628
+ field: partner
629
+ };
630
+ const junctionNamespaceId = orderJunctionSides(requester, partnerSide)[0].model.namespaceId;
631
+ const namesake = models.get(junctionName);
632
+ if (namesake !== void 0 && namesake.namespaceId === junctionNamespaceId) {
633
+ const reportedKey = junctionKey(junctionNamespaceId, junctionName);
634
+ if (!reportedJunctionNames.has(reportedKey)) {
635
+ reportedJunctionNames.add(reportedKey);
636
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_JUNCTION_NAME_COLLISION", `${label} is an implicit many-to-many relation whose junction model would be named "${junctionName}", but model "${junctionName}" already has that name. Rename model "${junctionName}" and keep its table with @@map("${namesake.tableName}"); Prisma 7's next migration is then empty.`, model.sourceId, field.span));
637
+ }
638
+ continue;
639
+ }
640
+ junctionRequests.push({
641
+ requester,
642
+ partner: partnerSide,
643
+ name: junctionName
644
+ });
645
+ }
646
+ const requestsByJunction = groupBy(junctionRequests, (request) => junctionKey(orderJunctionSides(request.requester, request.partner)[0].model.namespaceId, request.name));
647
+ for (const requests of requestsByJunction.values()) {
648
+ const [first] = requests;
649
+ if (first === void 0) continue;
650
+ const name = first.name;
651
+ const [sideA] = orderJunctionSides(first.requester, first.partner);
652
+ const tableName = prisma7ConstraintName(`_${name}`, "", naming.identifierMaxBytes);
653
+ const sideLabel = (side) => `${side.model.modelName}.${side.field.field.name}`;
654
+ const pairs = /* @__PURE__ */ new Map();
655
+ for (const request of requests) {
656
+ const key = [sideLabel(request.requester), sideLabel(request.partner)].sort().join("|");
657
+ if (!pairs.has(key)) pairs.set(key, request);
658
+ }
659
+ if (pairs.size > 1) {
660
+ const pairRequests = [...pairs.values()];
661
+ for (const request of pairRequests) {
662
+ const others = pairRequests.filter((other) => other !== request).map((other) => `"${sideLabel(other.requester)}"`);
663
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_RELATION_NAME_SHARED", `Relation field "${sideLabel(request.requester)}" is an implicit many-to-many relation named "${name}", and so ${others.length === 1 ? "is relation field" : "are relation fields"} ${andList(others)}; Prisma 7 creates one table "${tableName}" for them, wired to only one of the relations (its foreign keys show which). Give each relation its own name with @relation("<name>") on both fields: renaming a relation that "${tableName}" does not reference makes Prisma 7's next migration create its own table, while renaming the one it references moves "${tableName}"'s foreign keys to another relation, which fails on rows whose ids that relation's models lack and attaches the rest to the wrong records.`, request.requester.model.sourceId, request.requester.field.field.span));
664
+ }
665
+ continue;
666
+ }
667
+ const tableOwner = [...models.values()].find((other) => other.tableName === tableName && other.namespaceId === sideA.model.namespaceId);
668
+ if (tableOwner !== void 0) {
669
+ const relationField = `${first.requester.model.modelName}.${first.requester.field.field.name}`;
670
+ const message = `Model "${tableOwner.modelName}" and the implicit many-to-many relation "${relationField}" both use table "${tableOwner.namespaceId}"."${tableName}"; Prisma 7 creates the relation's table there and never creates the model's. Rename the model's table with @@map, which makes Prisma 7's next migration create it, or give the relation its own name with @relation("<name>") on both fields, which makes Prisma 7's next migration rebuild "${tableName}" as the model's table and create an empty table for the relation, losing the relation's rows.`;
671
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_TABLE_COLLISION", message, tableOwner.sourceId, tableOwner.tableSpan), prisma7Diagnostic("PSL.PRISMA7_TABLE_COLLISION", message, first.requester.model.sourceId, first.requester.field.field.span));
672
+ continue;
673
+ }
674
+ for (const { requester, partner } of requests) {
675
+ const junction = synthesizeJunction(requester, partner, naming, diagnostics);
676
+ if (junction === void 0) continue;
677
+ if (!junctions.has(junction.key)) {
678
+ junctions.set(junction.key, junction.node);
679
+ fkRelationMetadata.push(...junction.foreignKeys);
680
+ }
681
+ candidates.push({
682
+ modelName: requester.model.modelName,
683
+ tableName: requester.model.tableName,
684
+ field: requester.field.field,
685
+ targetModelName: partner.model.modelName,
686
+ isList: true,
687
+ relationName: junction.candidateRelationName
688
+ });
689
+ }
690
+ }
691
+ const { modelRelations, fkRelationsByPair, fkRelationsByDeclaringModel } = indexFkRelations({ fkRelationMetadata });
692
+ const modelIdColumns = /* @__PURE__ */ new Map();
693
+ const modelUniqueColumnSets = /* @__PURE__ */ new Map();
694
+ for (const model of models.values()) {
695
+ const id = columnNames(model, model.idFields);
696
+ if (id !== void 0 && id.length > 0) modelIdColumns.set(model.modelName, id);
697
+ const sets = [];
698
+ if (id !== void 0 && id.length > 0) sets.push(id);
699
+ for (const unique of model.uniqueFieldSets) {
700
+ const columns = columnNames(model, unique);
701
+ if (columns !== void 0) sets.push(columns);
702
+ }
703
+ modelUniqueColumnSets.set(model.modelName, sets);
704
+ }
705
+ for (const key of junctions.keys()) {
706
+ modelIdColumns.set(key, ["A", "B"]);
707
+ modelUniqueColumnSets.set(key, [["A", "B"]]);
708
+ }
709
+ const pairingDiagnostics = [];
710
+ const candidatesBySourceId = /* @__PURE__ */ new Map();
711
+ for (const candidate of candidates) {
712
+ const sourceId = models.get(candidate.modelName)?.sourceId ?? "schema.prisma";
713
+ const group = candidatesBySourceId.get(sourceId) ?? [];
714
+ candidatesBySourceId.set(sourceId, group);
715
+ group.push(candidate);
716
+ }
717
+ for (const [sourceId, backrelationCandidates] of candidatesBySourceId) applyBackrelationCandidates({
718
+ backrelationCandidates,
719
+ fkRelationsByPair,
720
+ invalidFkPairings,
721
+ fkRelationsByDeclaringModel,
722
+ modelIdColumns,
723
+ modelUniqueColumnSets,
724
+ modelRelations,
725
+ diagnostics: pairingDiagnostics,
726
+ sourceId
727
+ });
728
+ for (const diagnostic of pairingDiagnostics) diagnostics.push(RELATION_PAIRING_CODES.has(diagnostic.code) ? {
729
+ ...diagnostic,
730
+ code: "PSL.PRISMA7_RELATION_UNRESOLVED"
731
+ } : diagnostic);
732
+ const relations = /* @__PURE__ */ new Map();
733
+ for (const [modelName, nodes] of modelRelations) relations.set(modelName, [...nodes].sort((left, right) => left.fieldName.localeCompare(right.fieldName)));
734
+ return {
735
+ junctions,
736
+ foreignKeys,
737
+ relations
738
+ };
739
+ }
740
+ /**
741
+ * The id column a junction side contributes. The diagnostic names the
742
+ * requesting relation field, so it is located at that field, whichever side's
743
+ * id is at fault.
744
+ */
745
+ function singleIdColumn(side, requester, diagnostics) {
746
+ if (side.model.idFields.some((name) => side.model.ignoredFields.has(name) || side.model.rejectedFields.has(name))) return;
747
+ const [idField, ...rest] = side.model.idFields;
748
+ const column = idField === void 0 ? void 0 : side.model.columns.get(idField);
749
+ if (column === void 0 || rest.length > 0) {
750
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_JUNCTION_ID_UNSUPPORTED", `Relation field "${requester.model.modelName}.${requester.field.field.name}" is an implicit many-to-many relation, but "${side.model.modelName}" ${column === void 0 ? "has no single-field @id" : "has a composite id"}; Prisma 7 requires a single-field @id on both models of an implicit many-to-many relation.`, requester.model.sourceId, requester.field.field.span));
751
+ return;
752
+ }
753
+ return column;
754
+ }
755
+ /**
756
+ * Prisma 7's implicit junction: table `_AToB` (or `_Name`), columns `A` and `B`
757
+ * typed like the two ids, primary key `(A, B)`, index `_AToB_B_index`, and two
758
+ * cascading foreign keys, with relation fields named as `contract infer` names
759
+ * them. `A` is the model whose name is smaller in plain
760
+ * string order; for a self-relation, the field whose name is smaller. This is
761
+ * prisma-engines' rule (`psl/parser-database/src/relations.rs`,
762
+ * `ingest_relation`: the side with the greater model name, or field name for a
763
+ * self relation, is skipped so the smaller one owns `field_a`).
764
+ */
765
+ function synthesizeJunction(requester, partner, naming, diagnostics) {
766
+ const [sideA, sideB] = orderJunctionSides(requester, partner);
767
+ const requesterFirst = sideA === requester;
768
+ const name = requester.field.attribute?.name ?? `${sideA.model.modelName}To${sideB.model.modelName}`;
769
+ const idA = singleIdColumn(sideA, requester, diagnostics);
770
+ const idB = singleIdColumn(sideB, requester, diagnostics);
771
+ if (idA === void 0 || idB === void 0) return void 0;
772
+ const tableName = prisma7ConstraintName(`_${name}`, "", naming.identifierMaxBytes);
773
+ const namespaceId = sideA.model.namespaceId;
774
+ const key = junctionKey(namespaceId, name);
775
+ const [relationFieldA, relationFieldB] = naming.junctionRelationFieldNames(sideA.model.tableName, sideB.model.tableName);
776
+ const foreignKey = (column, side, id) => ({
777
+ columns: [column],
778
+ references: {
779
+ model: side.model.modelName,
780
+ table: side.model.tableName,
781
+ columns: [id.columnName],
782
+ namespaceId: side.model.namespaceId
783
+ },
784
+ onDelete: "cascade",
785
+ onUpdate: "cascade",
786
+ index: false
787
+ });
788
+ const metadata = (column, side, id) => ({
789
+ declaringModelName: key,
790
+ declaringFieldName: column === "A" ? relationFieldA : relationFieldB,
791
+ declaringTableName: tableName,
792
+ declaringNamespaceId: namespaceId,
793
+ targetModelName: side.model.modelName,
794
+ targetTableName: side.model.tableName,
795
+ targetNamespaceId: side.model.namespaceId,
796
+ relationName: `${name}:${column}`,
797
+ nullable: false,
798
+ localColumns: [column],
799
+ referencedColumns: [id.columnName]
800
+ });
801
+ const index = {
802
+ columns: ["B"],
803
+ type: void 0,
804
+ options: void 0,
805
+ where: void 0,
806
+ unique: void 0,
807
+ map: prisma7ConstraintName(`_${name}`, "_B_index", naming.identifierMaxBytes),
808
+ name: void 0
809
+ };
810
+ return {
811
+ key,
812
+ node: {
813
+ modelName: name,
814
+ tableName,
815
+ namespaceId,
816
+ fields: [{
817
+ fieldName: "A",
818
+ columnName: "A",
819
+ descriptor: idA.descriptor,
820
+ nullable: false
821
+ }, {
822
+ fieldName: "B",
823
+ columnName: "B",
824
+ descriptor: idB.descriptor,
825
+ nullable: false
826
+ }],
827
+ id: { columns: ["A", "B"] },
828
+ indexes: [index],
829
+ foreignKeys: [foreignKey("A", sideA, idA), foreignKey("B", sideB, idB)]
830
+ },
831
+ foreignKeys: [metadata("A", sideA, idA), metadata("B", sideB, idB)],
832
+ candidateRelationName: requesterFirst ? `${name}:A` : `${name}:B`
833
+ };
834
+ }
835
+ const SUMMARY = "Prisma 7 schema interpretation failed";
836
+ const EMPTY_DESCRIPTORS = /* @__PURE__ */ new Map();
837
+ function attributeText(attribute) {
838
+ const args = attribute.args.map((arg) => arg.kind === "named" ? `${arg.name}: ${arg.value}` : arg.value);
839
+ return args.length === 0 ? `@${attribute.name}` : `@${attribute.name}(${args.join(", ")})`;
840
+ }
841
+ function stringArgument(attribute) {
842
+ const expression = (attribute.args.find((arg) => arg.kind === "positional") ?? attribute.args.find((arg) => arg.name === "name"))?.expression;
843
+ if (expression === void 0) return void 0;
844
+ return StringLiteralExprAst.cast(expression.syntax)?.value();
845
+ }
846
+ function scalarValue(block, key) {
847
+ const parameter = block.parameters[key];
848
+ if (parameter?.kind !== "value") return void 0;
849
+ try {
850
+ const parsed = JSON.parse(parameter.raw);
851
+ return typeof parsed === "string" ? parsed : void 0;
852
+ } catch {
853
+ return;
854
+ }
855
+ }
856
+ function parameterSpan(block, key) {
857
+ const parameter = block.parameters[key];
858
+ return parameter === void 0 ? block.span : parameter.span;
859
+ }
860
+ function interpretPrisma7Documents(input) {
861
+ const { binding } = input;
862
+ const diagnostics = [...input.seedDiagnostics];
863
+ const defaultNamespaceId = binding.target.defaultNamespaceId;
864
+ const datasources = [];
865
+ const enumBlocks = [];
866
+ const models = [];
867
+ const ignoredModels = /* @__PURE__ */ new Set();
868
+ const declaredNames = /* @__PURE__ */ new Map();
869
+ const claimName = (kind, name, sourceId, span) => {
870
+ const previous = declaredNames.get(name);
871
+ if (previous === void 0) {
872
+ declaredNames.set(name, sourceId);
873
+ return true;
874
+ }
875
+ diagnostics.push({
876
+ code: "PSL_DUPLICATE_DECLARATION",
877
+ message: `Duplicate declaration of ${kind} "${name}"; first declared in ${basename(previous)}.`,
878
+ sourceId,
879
+ span
880
+ });
881
+ return false;
882
+ };
883
+ for (const { document, sourceFile, sourceId } of input.documents) {
884
+ const { table, diagnostics: tableDiagnostics } = buildSymbolTable({
885
+ document,
886
+ sourceFile,
887
+ pslBlockDescriptors: {}
888
+ });
889
+ for (const diagnostic of tableDiagnostics) diagnostics.push({
890
+ code: diagnostic.code,
891
+ message: diagnostic.message,
892
+ sourceId,
893
+ span: rangeToPslSpan(diagnostic.range, sourceFile)
894
+ });
895
+ const unsupported = (keyword, span) => {
896
+ diagnostics.push({
897
+ code: "PSL_UNSUPPORTED_TOP_LEVEL_BLOCK",
898
+ message: `Unsupported top-level block "${keyword}"`,
899
+ sourceId,
900
+ span
901
+ });
902
+ };
903
+ for (const block of Object.values(table.topLevel.blocks)) switch (block.keyword) {
904
+ case "datasource":
905
+ datasources.push({
906
+ block,
907
+ sourceId,
908
+ sourceFile
909
+ });
910
+ break;
911
+ case "generator": break;
912
+ case "enum":
913
+ if (claimName("enum", block.name, sourceId, block.span)) enumBlocks.push({
914
+ block,
915
+ sourceId,
916
+ sourceFile
917
+ });
918
+ break;
919
+ case "view":
920
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_VIEW_UNSUPPORTED", `View "${block.name}" is not supported; Prisma 8 has no views. Remove the view or replace it with a model over the underlying table.`, sourceId, keywordPslSpan(block.node.syntax, block.keyword, sourceFile)));
921
+ break;
922
+ default: unsupported(block.keyword, keywordPslSpan(block.node.syntax, block.keyword, sourceFile));
923
+ }
924
+ for (const namespace of Object.values(table.topLevel.namespaces)) unsupported("namespace", namespace.span);
925
+ for (const compositeType of Object.values(table.topLevel.compositeTypes)) unsupported("type", compositeType.span);
926
+ for (const namedType of Object.values(table.topLevel.namedTypes)) unsupported("types", namedType.span);
927
+ for (const symbol of Object.values(table.topLevel.models)) {
928
+ if (!claimName("model", symbol.name, sourceId, symbol.span)) continue;
929
+ const declaration = readModelDeclaration(symbol, sourceId, defaultNamespaceId, binding.indexTypes, diagnostics);
930
+ if (declaration === void 0) ignoredModels.add(symbol.name);
931
+ else models.push(declaration);
932
+ }
933
+ }
934
+ checkDatasource(datasources, input.documents[0]?.sourceId ?? "schema.prisma", binding, diagnostics);
935
+ reportTableCollisions(models, diagnostics);
936
+ const enums = /* @__PURE__ */ new Map();
937
+ for (const source of enumBlocks) {
938
+ const declaration = readEnumDeclaration(source, defaultNamespaceId, diagnostics);
939
+ if (declaration !== void 0) enums.set(declaration.name, declaration);
940
+ }
941
+ const namespaceEntities = lowerNativeEnums(enums, input, diagnostics);
942
+ const modelNames = /* @__PURE__ */ new Set([...models.map((model) => model.symbol.name), ...ignoredModels]);
943
+ const scalarColumnDescriptors = collectScalarTypeConstructors(input.authoringContributions.type);
944
+ const composedExtensions = new Set(input.composedExtensions);
945
+ const builds = /* @__PURE__ */ new Map();
946
+ for (const declaration of models) {
947
+ const build = {
948
+ declaration,
949
+ columns: /* @__PURE__ */ new Map(),
950
+ ignoredFields: /* @__PURE__ */ new Set(),
951
+ ignoredRelationFields: [],
952
+ rejectedFields: /* @__PURE__ */ new Set(),
953
+ idFields: declaration.id?.fields ?? [],
954
+ uniqueIndexes: [...declaration.uniqueIndexes],
955
+ relationFields: []
956
+ };
957
+ for (const field of Object.values(declaration.symbol.fields)) {
958
+ const reported = diagnostics.length;
959
+ readField({
960
+ field,
961
+ build,
962
+ modelNames,
963
+ ignoredModels,
964
+ enums,
965
+ namespaceEntities,
966
+ scalarColumnDescriptors,
967
+ composedExtensions,
968
+ input,
969
+ diagnostics
970
+ });
971
+ if (diagnostics.length > reported && !build.columns.has(field.name) && !build.ignoredFields.has(field.name)) build.rejectedFields.add(field.name);
972
+ }
973
+ builds.set(declaration.symbol.name, build);
974
+ }
975
+ const relationModels = /* @__PURE__ */ new Map();
976
+ for (const [modelName, build] of builds) relationModels.set(modelName, {
977
+ modelName,
978
+ tableName: build.declaration.tableName,
979
+ tableSpan: build.declaration.symbol.attributes.find((attribute) => attribute.name === "map")?.span ?? build.declaration.symbol.span,
980
+ namespaceId: build.declaration.namespaceId,
981
+ sourceId: build.declaration.sourceId,
982
+ columns: build.columns,
983
+ ignoredFields: build.ignoredFields,
984
+ ignoredRelationFields: build.ignoredRelationFields,
985
+ rejectedFields: build.rejectedFields,
986
+ idFields: build.idFields,
987
+ uniqueFieldSets: build.uniqueIndexes.flatMap((index) => index.fields === void 0 ? [] : [index.fields]),
988
+ relationFields: build.relationFields
989
+ });
990
+ const lowered = lowerRelations(relationModels, binding, diagnostics);
991
+ const modelNodes = [];
992
+ for (const [modelName, build] of builds) {
993
+ const model = relationModels.get(modelName);
994
+ if (model === void 0) continue;
995
+ const ignoredAmong = (fieldNames) => fieldNames?.filter((name) => build.ignoredFields.has(name)) ?? [];
996
+ const idAttribute = build.declaration.id;
997
+ const ignoredIdFields = ignoredAmong(idAttribute?.fields);
998
+ if (idAttribute !== void 0 && ignoredIdFields.length > 0) diagnostics.push(ignoredFieldReferenced({
999
+ modelName,
1000
+ fieldNames: ignoredIdFields,
1001
+ usedBy: `@@id on model "${modelName}"`,
1002
+ constraint: "primary key",
1003
+ sourceId: model.sourceId,
1004
+ span: idAttribute.span
1005
+ }));
1006
+ const id = keyColumns(model, model.idFields);
1007
+ const indexes = [...build.uniqueIndexes.map((attribute) => ({
1008
+ attribute,
1009
+ unique: true
1010
+ })), ...build.declaration.indexes.map((attribute) => ({
1011
+ attribute,
1012
+ unique: false
1013
+ }))].flatMap(({ attribute, unique }) => {
1014
+ const ignoredIndexFields = ignoredAmong(attribute.fields);
1015
+ if (ignoredIndexFields.length > 0) {
1016
+ diagnostics.push(ignoredFieldReferenced({
1017
+ modelName,
1018
+ fieldNames: ignoredIndexFields,
1019
+ usedBy: `${unique ? "@@unique" : "@@index"} on model "${modelName}"`,
1020
+ constraint: unique ? "unique index" : "index",
1021
+ sourceId: model.sourceId,
1022
+ span: attribute.span
1023
+ }));
1024
+ return [];
1025
+ }
1026
+ if (attribute.fields?.some((name) => build.rejectedFields.has(name))) return [];
1027
+ const columns = attribute.fields === void 0 ? void 0 : keyColumns(model, attribute.fields);
1028
+ if (columns === void 0) {
1029
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_INDEX_ARGUMENT_UNSUPPORTED", `Model "${modelName}": an index names a field that is not a scalar column of the model.`, model.sourceId, attribute.span));
1030
+ return [];
1031
+ }
1032
+ return [indexNode(model.tableName, columns, attribute, unique, binding.identifierMaxBytes)];
1033
+ });
1034
+ const foreignKeys = lowered.foreignKeys.get(modelName);
1035
+ const relations = lowered.relations.get(modelName);
1036
+ modelNodes.push({
1037
+ modelName,
1038
+ tableName: model.tableName,
1039
+ namespaceId: model.namespaceId,
1040
+ fields: [...build.columns.values()],
1041
+ ...id !== void 0 && id.length > 0 ? { id: { columns: id } } : {},
1042
+ ...indexes.length > 0 ? { indexes } : {},
1043
+ ...foreignKeys !== void 0 ? { foreignKeys } : {},
1044
+ ...relations !== void 0 ? { relations } : {}
1045
+ });
1046
+ }
1047
+ for (const [key, junction] of lowered.junctions) {
1048
+ const relations = lowered.relations.get(key);
1049
+ modelNodes.push(relations === void 0 ? junction : {
1050
+ ...junction,
1051
+ relations
1052
+ });
1053
+ }
1054
+ if (diagnostics.length > 0) return notOk({
1055
+ summary: SUMMARY,
1056
+ diagnostics
1057
+ });
1058
+ const createNamespace = (namespace) => {
1059
+ const entities = namespaceEntities.get(namespace.id);
1060
+ if (entities === void 0) return binding.createNamespace(namespace);
1061
+ const valueSet = {
1062
+ ...namespace.entries["valueSet"],
1063
+ ...entities["valueSet"]
1064
+ };
1065
+ return binding.createNamespace({
1066
+ ...namespace,
1067
+ entries: {
1068
+ ...namespace.entries,
1069
+ ...entities,
1070
+ ...Object.keys(valueSet).length > 0 ? { valueSet } : {}
1071
+ }
1072
+ });
1073
+ };
1074
+ return ok(buildSqlContractFromDefinition({
1075
+ target: binding.target,
1076
+ warnings: void 0,
1077
+ createNamespace,
1078
+ ...namespaceEntities.size > 0 ? { namespaces: [...namespaceEntities.keys()] } : {},
1079
+ models: modelNodes
1080
+ }, input.codecLookup));
1081
+ }
1082
+ function checkDatasource(datasources, fallbackSourceId, binding, diagnostics) {
1083
+ const [datasource] = datasources;
1084
+ const [namedProvider] = binding.providers;
1085
+ if (datasource === void 0) {
1086
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_PROVIDER_MISMATCH", `No datasource block found; add \`datasource db { provider = "${namedProvider}" }\`.`, fallbackSourceId, void 0));
1087
+ return;
1088
+ }
1089
+ const block = datasource.block.block;
1090
+ const provider = scalarValue(block, "provider");
1091
+ if (provider === void 0 || !binding.providers.includes(provider)) diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_PROVIDER_MISMATCH", provider === void 0 ? `The datasource block declares no string \`provider\`; this contract source reads Prisma 7 schemas for provider "${namedProvider}".` : `The datasource provider is "${provider}"; this contract source reads Prisma 7 schemas for provider "${namedProvider}".`, datasource.sourceId, parameterSpan(block, "provider")));
1092
+ for (const [property, edit] of Object.entries({
1093
+ relationMode: "Removing relationMode, or setting it to \"foreignKeys\"",
1094
+ referentialIntegrity: "Removing referentialIntegrity, or replacing it with relationMode = \"foreignKeys\""
1095
+ })) {
1096
+ if (scalarValue(block, property) !== "prisma") continue;
1097
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_RELATION_MODE_UNSUPPORTED", `${property} = "prisma" is not supported: the contract declares the foreign keys its relations need, and in this mode Prisma 7 creates none. ${edit}, makes Prisma 7's next migration add those foreign keys, and that migration fails if any existing row breaks one.`, datasource.sourceId, parameterSpan(block, property)));
1098
+ }
1099
+ }
1100
+ function reportTableCollisions(models, diagnostics) {
1101
+ const byTable = /* @__PURE__ */ new Map();
1102
+ for (const model of models) {
1103
+ const key = `${model.namespaceId}.${model.tableName}`;
1104
+ const group = byTable.get(key) ?? [];
1105
+ byTable.set(key, group);
1106
+ group.push(model);
1107
+ }
1108
+ for (const group of byTable.values()) {
1109
+ if (group.length < 2) continue;
1110
+ const names = group.map((model) => `"${model.symbol.name}"`).join(", ");
1111
+ for (const model of group) {
1112
+ const mapAttribute = model.symbol.attributes.find((attribute) => attribute.name === "map");
1113
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_TABLE_COLLISION", `Models ${names} all map to table "${model.namespaceId}"."${model.tableName}"; each model needs its own table.`, model.sourceId, mapAttribute?.span ?? model.symbol.span));
1114
+ }
1115
+ }
1116
+ }
1117
+ function keyColumns(model, fieldNames) {
1118
+ const columns = [];
1119
+ for (const fieldName of fieldNames) {
1120
+ const column = model.columns.get(fieldName);
1121
+ if (column === void 0) return void 0;
1122
+ columns.push(column.columnName);
1123
+ }
1124
+ return columns;
1125
+ }
1126
+ function readModelDeclaration(symbol, sourceId, defaultNamespaceId, indexTypes, diagnostics) {
1127
+ if (symbol.attributes.some((attribute) => attribute.name === "ignore")) return void 0;
1128
+ let tableName = symbol.name;
1129
+ let namespaceId = defaultNamespaceId;
1130
+ let id;
1131
+ const uniqueIndexes = [];
1132
+ const indexes = [];
1133
+ for (const attribute of symbol.attributes) switch (attribute.name) {
1134
+ case "map":
1135
+ tableName = requireStringArgument(attribute, symbol.name, sourceId, diagnostics) ?? tableName;
1136
+ break;
1137
+ case "schema":
1138
+ namespaceId = requireStringArgument(attribute, symbol.name, sourceId, diagnostics) ?? namespaceId;
1139
+ break;
1140
+ case "id": {
1141
+ const parsed = parseIndexAttribute(attribute, symbol.name, sourceId, indexTypes, diagnostics);
1142
+ if (parsed?.fields !== void 0) id = parsed;
1143
+ break;
1144
+ }
1145
+ case "unique": {
1146
+ const parsed = parseIndexAttribute(attribute, symbol.name, sourceId, indexTypes, diagnostics);
1147
+ if (parsed?.fields !== void 0) uniqueIndexes.push(parsed);
1148
+ break;
1149
+ }
1150
+ case "index": {
1151
+ const parsed = parseIndexAttribute(attribute, symbol.name, sourceId, indexTypes, diagnostics);
1152
+ if (parsed?.fields !== void 0) indexes.push(parsed);
1153
+ break;
1154
+ }
1155
+ default: diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_ATTRIBUTE", `Model "${symbol.name}": attribute "@@${attribute.name}" is not supported yet by the Prisma 7 contract source.`, sourceId, attribute.span));
1156
+ }
1157
+ return {
1158
+ symbol,
1159
+ sourceId,
1160
+ namespaceId,
1161
+ tableName,
1162
+ id,
1163
+ uniqueIndexes,
1164
+ indexes
1165
+ };
1166
+ }
1167
+ function requireStringArgument(attribute, owner, sourceId, diagnostics) {
1168
+ const value = stringArgument(attribute);
1169
+ if (value === void 0) diagnostics.push({
1170
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
1171
+ message: `"${owner}": attribute "${attribute.name}" expects one string argument.`,
1172
+ sourceId,
1173
+ span: attribute.span
1174
+ });
1175
+ return value;
1176
+ }
1177
+ function readEnumDeclaration(source, defaultNamespaceId, diagnostics) {
1178
+ const { block, sourceId, sourceFile } = source;
1179
+ let typeName = block.name;
1180
+ let namespaceId = defaultNamespaceId;
1181
+ for (const attribute of readResolvedAttributes(block.node.attributes(), sourceFile)) switch (attribute.name) {
1182
+ case "map":
1183
+ typeName = requireStringArgument(attribute, block.name, sourceId, diagnostics) ?? typeName;
1184
+ break;
1185
+ case "schema":
1186
+ namespaceId = requireStringArgument(attribute, block.name, sourceId, diagnostics) ?? namespaceId;
1187
+ break;
1188
+ default: diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_ATTRIBUTE", `Enum "${block.name}": attribute "@@${attribute.name}" is not supported by the Prisma 7 contract source.`, sourceId, attribute.span));
1189
+ }
1190
+ const members = [];
1191
+ for (const entry of block.node.entries()) {
1192
+ const name = entry.key()?.name();
1193
+ if (name === void 0) continue;
1194
+ let value = name;
1195
+ const span = nodePslSpan(entry.syntax, sourceFile);
1196
+ for (const attributeNode of entry.attributes()) {
1197
+ const attribute = readResolvedAttribute(attributeNode, sourceFile);
1198
+ if (attribute.name === "map") value = requireStringArgument(attribute, `${block.name}.${name}`, sourceId, diagnostics) ?? value;
1199
+ else diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_ATTRIBUTE", `Enum member "${block.name}.${name}": attribute "@${attribute.name}" is not supported by the Prisma 7 contract source.`, sourceId, attribute.span));
1200
+ }
1201
+ members.push({
1202
+ name,
1203
+ value,
1204
+ span
1205
+ });
1206
+ }
1207
+ return {
1208
+ name: block.name,
1209
+ typeName,
1210
+ namespaceId,
1211
+ members,
1212
+ span: block.span,
1213
+ sourceId
1214
+ };
1215
+ }
1216
+ function lowerNativeEnums(enums, input, diagnostics) {
1217
+ const result = /* @__PURE__ */ new Map();
1218
+ if (enums.size === 0) return result;
1219
+ const { entityKind } = input.binding.nativeEnum;
1220
+ const descriptor = buildEntityTypesByDiscriminator(input.authoringContributions).get(entityKind);
1221
+ for (const declaration of enums.values()) {
1222
+ if (descriptor === void 0) {
1223
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNSUPPORTED_TYPE", `Enum "${declaration.name}" cannot be lowered: target "${input.binding.target.targetId}" registers no "${entityKind}" entity kind.`, declaration.sourceId, declaration.span));
1224
+ continue;
1225
+ }
1226
+ const context = {
1227
+ family: input.binding.target.familyId,
1228
+ target: input.binding.target.targetId,
1229
+ codecLookup: input.codecLookup,
1230
+ sourceId: declaration.sourceId,
1231
+ diagnostics: { push: (diagnostic) => {
1232
+ diagnostics.push(blindCast(diagnostic));
1233
+ } }
1234
+ };
1235
+ const entity = instantiateAuthoringEntityType(entityKind, descriptor, [{
1236
+ kind: entityKind,
1237
+ keyword: entityKind,
1238
+ name: declaration.name,
1239
+ parameters: Object.fromEntries(declaration.members.map((member) => [member.name, {
1240
+ kind: "value",
1241
+ raw: JSON.stringify(member.value),
1242
+ span: member.span
1243
+ }])),
1244
+ blockAttributes: [],
1245
+ attributes: { map: {
1246
+ args: { name: declaration.typeName },
1247
+ span: declaration.span
1248
+ } },
1249
+ span: declaration.span,
1250
+ namespaceId: declaration.namespaceId
1251
+ }], context);
1252
+ if (entity === void 0) continue;
1253
+ const entities = result.get(declaration.namespaceId) ?? {};
1254
+ result.set(declaration.namespaceId, entities);
1255
+ entities[entityKind] = {
1256
+ ...entities[entityKind],
1257
+ [declaration.name]: entity
1258
+ };
1259
+ const valueSet = deriveValueSetFromEntity(descriptor.output, entity);
1260
+ if (valueSet !== void 0) entities["valueSet"] = {
1261
+ ...entities["valueSet"],
1262
+ [declaration.name]: valueSet
1263
+ };
1264
+ }
1265
+ return result;
1266
+ }
1267
+ function keysUsingField(field, model) {
1268
+ const modelName = model.symbol.name;
1269
+ const uses = [];
1270
+ for (const attribute of field.attributes) {
1271
+ if (attribute.name === "id") uses.push({
1272
+ usedBy: "its @id",
1273
+ constraint: "primary key"
1274
+ });
1275
+ if (attribute.name === "unique") uses.push({
1276
+ usedBy: "its @unique",
1277
+ constraint: "unique index"
1278
+ });
1279
+ }
1280
+ if (model.id?.fields?.includes(field.name)) uses.push({
1281
+ usedBy: `@@id on model "${modelName}"`,
1282
+ constraint: "primary key"
1283
+ });
1284
+ for (const unique of model.uniqueIndexes) if (unique.fields?.includes(field.name)) uses.push({
1285
+ usedBy: `@@unique on model "${modelName}"`,
1286
+ constraint: "unique index"
1287
+ });
1288
+ for (const index of model.indexes) if (index.fields?.includes(field.name)) uses.push({
1289
+ usedBy: `@@index on model "${modelName}"`,
1290
+ constraint: "index"
1291
+ });
1292
+ for (const other of Object.values(model.symbol.fields)) {
1293
+ if (other.attributes.some((attribute) => attribute.name === "ignore")) continue;
1294
+ const relation = other.attributes.find((attribute) => attribute.name === "relation");
1295
+ if ((relation === void 0 ? void 0 : parseRelationAttribute(relation, other.name, model.sourceId, []))?.fields?.includes(field.name)) uses.push({
1296
+ usedBy: `relation field "${modelName}.${other.name}"`,
1297
+ constraint: "foreign key"
1298
+ });
1299
+ }
1300
+ return uses;
1301
+ }
1302
+ function nativeTypeMessage(input) {
1303
+ const { label, nativeType, field, model } = input;
1304
+ const uses = keysUsingField(field, model);
1305
+ if (uses.length > 0) {
1306
+ const constraints = [...new Set(uses.map((use) => `the ${use.constraint}`))];
1307
+ return `${label}: native type "@db.${nativeType}" has no Prisma 8 codec, and ${andList(uses.map((use) => use.usedBy))} ${uses.length === 1 ? "uses" : "use"} the field, so @ignore on the field does not help: Prisma 7 still creates ${andList(constraints)} over the column. Add @@ignore to model "${model.symbol.name}" to keep the model out of the contract: Prisma 7's next migration is empty, but the model disappears from the Prisma 7 client too, and every relation field in another model that points to it needs @ignore, which removes that field from the Prisma 7 client as well. Changing the field's type instead changes the column type on Prisma 7's next migration.`;
1308
+ }
1309
+ return `${label}: native type "@db.${nativeType}" has no Prisma 8 codec. Add @ignore to the field to keep its column out of the contract: Prisma 7's next migration is empty, and the field disappears from the Prisma 7 client too${!field.optional && !field.list && !givesColumnDefault(input.defaultAttribute) ? "; because the field is required and its column has no default, neither client can then insert rows" : ""}. Changing the field's type instead changes the column type on Prisma 7's next migration.`;
1310
+ }
1311
+ function readIgnoredField(field, isRelationField, args) {
1312
+ const { build, diagnostics } = args;
1313
+ const model = build.declaration;
1314
+ if (isRelationField) {
1315
+ if (args.ignoredModels.has(field.typeName)) return;
1316
+ const relation = field.attributes.find((attribute) => attribute.name === "relation");
1317
+ build.ignoredRelationFields.push({
1318
+ field,
1319
+ targetModelName: field.typeName,
1320
+ attribute: relation === void 0 ? void 0 : parseRelationAttribute(relation, field.name, model.sourceId, [])
1321
+ });
1322
+ return;
1323
+ }
1324
+ for (const attribute of field.attributes) {
1325
+ if (attribute.name !== "id" && attribute.name !== "unique") continue;
1326
+ if (attribute.name === "id") build.idFields = [field.name];
1327
+ diagnostics.push(ignoredFieldReferenced({
1328
+ modelName: model.symbol.name,
1329
+ fieldNames: [field.name],
1330
+ usedBy: `its @${attribute.name}`,
1331
+ constraint: attribute.name === "id" ? "primary key" : "unique index",
1332
+ sourceId: model.sourceId,
1333
+ span: attribute.span
1334
+ }));
1335
+ }
1336
+ }
1337
+ function readField(args) {
1338
+ const { field, build, diagnostics, input } = args;
1339
+ const { binding } = input;
1340
+ const model = build.declaration;
1341
+ const sourceId = model.sourceId;
1342
+ const label = `Field "${model.symbol.name}.${field.name}"`;
1343
+ const isRelationField = args.modelNames.has(field.typeName) && field.typeConstructor === void 0;
1344
+ if (field.attributes.some((attribute) => attribute.name === "ignore")) {
1345
+ build.ignoredFields.add(field.name);
1346
+ readIgnoredField(field, isRelationField, args);
1347
+ return;
1348
+ }
1349
+ let columnName = field.name;
1350
+ let nativeType;
1351
+ let relation;
1352
+ let defaultAttribute;
1353
+ let updatedAt;
1354
+ for (const attribute of field.attributes) if (attribute.name === "map" && !isRelationField) columnName = requireStringArgument(attribute, label, sourceId, diagnostics) ?? columnName;
1355
+ else if (attribute.name.startsWith("db.") && !isRelationField) nativeType = {
1356
+ name: attribute.name.slice(3),
1357
+ attribute
1358
+ };
1359
+ else if (attribute.name === "id" && !isRelationField) {
1360
+ if (parseIndexAttribute(attribute, label, sourceId, binding.indexTypes, diagnostics) !== void 0) build.idFields = [field.name];
1361
+ } else if (attribute.name === "unique" && !isRelationField) {
1362
+ const parsed = parseIndexAttribute(attribute, label, sourceId, binding.indexTypes, diagnostics);
1363
+ if (parsed !== void 0) build.uniqueIndexes.push({
1364
+ ...parsed,
1365
+ fields: [field.name]
1366
+ });
1367
+ } else if (attribute.name === "default" && !isRelationField) defaultAttribute = attribute;
1368
+ else if (attribute.name === "updatedAt" && !isRelationField) updatedAt = attribute;
1369
+ else if (attribute.name === "relation" && isRelationField) relation = attribute;
1370
+ else diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNKNOWN_ATTRIBUTE", `${label}: attribute "@${attribute.name}" is not supported yet by the Prisma 7 contract source.`, sourceId, attribute.span));
1371
+ if (field.malformedType) return;
1372
+ if (field.typeConstructor !== void 0) {
1373
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNSUPPORTED_TYPE", `${label} has type "${field.typeConstructor.path.join(".")}(...)", which has no Prisma 8 codec, so model "${model.symbol.name}" cannot use this contract source while it has the field. Prisma 7 rejects @ignore on an Unsupported field, and removing the field drops its column on Prisma 7's next migration. Adding @@ignore to model "${model.symbol.name}" keeps the model out of the contract: Prisma 7's next migration is empty, but the model disappears from the Prisma 7 client too, and every relation field in another model that points to it needs @ignore, which removes that field from the Prisma 7 client as well.`, sourceId, field.typeConstructor.span));
1374
+ return;
1375
+ }
1376
+ if (args.ignoredModels.has(field.typeName)) return;
1377
+ if (isRelationField) {
1378
+ const attribute = relation === void 0 ? void 0 : parseRelationAttribute(relation, label, sourceId, diagnostics);
1379
+ if (relation !== void 0 && attribute === void 0) return;
1380
+ build.relationFields.push({
1381
+ field,
1382
+ targetModelName: field.typeName,
1383
+ attribute
1384
+ });
1385
+ return;
1386
+ }
1387
+ const enumDeclaration = args.enums.get(field.typeName);
1388
+ let call;
1389
+ if (enumDeclaration !== void 0) {
1390
+ if (enumDeclaration.namespaceId !== model.namespaceId) {
1391
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_ENUM_NAMESPACE_MISMATCH", `${label} uses enum "${enumDeclaration.name}" from schema "${enumDeclaration.namespaceId}", but the model is in schema "${model.namespaceId}". Prisma 8 columns reference the enum type of their own schema; declare the enum in "${model.namespaceId}" or move the model.`, sourceId, field.span));
1392
+ return;
1393
+ }
1394
+ call = {
1395
+ path: binding.nativeEnum.typeConstructor,
1396
+ args: [{
1397
+ kind: "positional",
1398
+ value: enumDeclaration.name,
1399
+ span: field.span
1400
+ }],
1401
+ span: field.span
1402
+ };
1403
+ } else {
1404
+ const scalar = prisma7ScalarMapping(binding.typeMap, field.typeName);
1405
+ if (scalar === void 0) {
1406
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNSUPPORTED_TYPE", `${label} has unknown type "${field.typeName}".`, sourceId, field.span));
1407
+ return;
1408
+ }
1409
+ let mapping = scalar;
1410
+ let span = field.span;
1411
+ if (nativeType !== void 0) {
1412
+ const native = prisma7NativeTypeMapping(binding.typeMap, nativeType.name, nativeType.attribute.args.map((arg) => arg.value));
1413
+ if (native === void 0) {
1414
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_NATIVE_TYPE_UNSUPPORTED", nativeTypeMessage({
1415
+ label,
1416
+ nativeType: nativeType.name,
1417
+ field,
1418
+ model,
1419
+ defaultAttribute
1420
+ }), sourceId, nativeType.attribute.span));
1421
+ return;
1422
+ }
1423
+ mapping = native;
1424
+ span = nativeType.attribute.span;
1425
+ }
1426
+ call = {
1427
+ path: [mapping.constructorName],
1428
+ args: mapping.args.map((value) => ({
1429
+ kind: "positional",
1430
+ value,
1431
+ span
1432
+ })),
1433
+ span
1434
+ };
1435
+ }
1436
+ const namespaceExtensionEntities = args.namespaceEntities.get(model.namespaceId);
1437
+ const resolved = resolveFieldTypeDescriptor({
1438
+ field: {
1439
+ ...field,
1440
+ typeConstructor: call
1441
+ },
1442
+ enumTypeDescriptors: EMPTY_DESCRIPTORS,
1443
+ namedTypeDescriptors: EMPTY_DESCRIPTORS,
1444
+ scalarColumnDescriptors: args.scalarColumnDescriptors,
1445
+ authoringContributions: input.authoringContributions,
1446
+ composedExtensions: args.composedExtensions,
1447
+ familyId: binding.target.familyId,
1448
+ targetId: binding.target.targetId,
1449
+ diagnostics,
1450
+ sourceId,
1451
+ entityLabel: label,
1452
+ namespaceId: model.namespaceId,
1453
+ ...ifDefined("namespaceExtensionEntities", namespaceExtensionEntities),
1454
+ codecLookup: input.codecLookup
1455
+ });
1456
+ if (!resolved.ok) {
1457
+ if (!resolved.alreadyReported) diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UNSUPPORTED_TYPE", `${label} type "${field.typeName}" could not be resolved against target "${binding.target.targetId}".`, sourceId, field.span));
1458
+ return;
1459
+ }
1460
+ const updatedAtGeneratorId = updatedAt === void 0 ? void 0 : binding.updatedAtGeneratorId(resolved.descriptor.codecId);
1461
+ if (updatedAt !== void 0 && updatedAtGeneratorId === void 0) {
1462
+ const withoutUpdatedAt = defaultAttribute !== void 0 && givesColumnDefault(defaultAttribute) ? `. Its ${attributeText(defaultAttribute)} still sets the value on create, and neither client changes it on update.` : field.optional ? ", but neither client then fills the value, so it stays empty unless a client writes it, and updates leave it unchanged." : ", but neither client then fills the value, so both require it on create and leave it unchanged on update.";
1463
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UPDATED_AT_TYPE_UNSUPPORTED", `${label}: @updatedAt is not supported on this column, because Prisma 8 has no generator for column type "${resolved.descriptor.nativeType}" yet. Remove @updatedAt: Prisma 7's next migration is empty${withoutUpdatedAt}`, sourceId, updatedAt.span));
1464
+ return;
1465
+ }
1466
+ if (updatedAt !== void 0 && defaultAttribute !== void 0) {
1467
+ const written = attributeText(defaultAttribute);
1468
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_UPDATED_AT_WITH_DEFAULT_UNSUPPORTED", `${label} combines @updatedAt with ${written}, which Prisma 8 cannot express yet. Remove ${written}: @updatedAt still sets the value on create and on update, and Prisma 7's next migration removes the column default.`, sourceId, defaultAttribute.span));
1469
+ return;
1470
+ }
1471
+ const lowered = defaultAttribute === void 0 ? void 0 : lowerPrisma7Default({
1472
+ attribute: defaultAttribute,
1473
+ field,
1474
+ modelName: model.symbol.name,
1475
+ codecId: resolved.descriptor.codecId,
1476
+ codecLookup: input.codecLookup,
1477
+ literalForm: binding.literalDefaultForm(resolved.descriptor),
1478
+ enumMembers: enumDeclaration === void 0 ? void 0 : new Map(enumDeclaration.members.map((member) => [member.name, member.value])),
1479
+ controlMutationDefaults: input.controlMutationDefaults,
1480
+ sourceId,
1481
+ diagnostics
1482
+ });
1483
+ if (defaultAttribute !== void 0 && lowered === void 0) return;
1484
+ const updatedAtGenerator = updatedAtGeneratorId === void 0 ? void 0 : {
1485
+ kind: "generator",
1486
+ id: updatedAtGeneratorId
1487
+ };
1488
+ const generator = updatedAtGenerator ?? lowered?.onCreate;
1489
+ const generatingAttribute = updatedAt ?? defaultAttribute;
1490
+ if (generator !== void 0 && generatingAttribute !== void 0 && field.optional) {
1491
+ const written = attributeText(generatingAttribute);
1492
+ diagnostics.push(prisma7Diagnostic("PSL.PRISMA7_OPTIONAL_GENERATED_FIELD_UNSUPPORTED", `${label} is optional and its value comes from ${written}, which Prisma 8 cannot express on an optional field yet. Remove ${written} and keep the "?": the database does not change, and both clients then stop filling the value.`, sourceId, generatingAttribute.span));
1493
+ return;
1494
+ }
1495
+ const executionDefaults = updatedAtGenerator !== void 0 ? {
1496
+ onCreate: updatedAtGenerator,
1497
+ onUpdate: updatedAtGenerator
1498
+ } : generator !== void 0 ? { onCreate: generator } : void 0;
1499
+ build.columns.set(field.name, {
1500
+ fieldName: field.name,
1501
+ columnName,
1502
+ descriptor: resolved.descriptor,
1503
+ nullable: field.optional || field.list,
1504
+ ...field.list ? {
1505
+ many: true,
1506
+ noCheck: ["elementNotNull"]
1507
+ } : {},
1508
+ ...ifDefined("default", lowered?.storage),
1509
+ ...ifDefined("executionDefaults", executionDefaults)
1510
+ });
1511
+ }
1512
+ function defaultOutputFromSchemaPath(schemaPath) {
1513
+ return join(dirname(schemaPath), "contract.json");
1514
+ }
1515
+ function mapParseDiagnostics(diagnostics, sourceFile, sourceId) {
1516
+ return diagnostics.map((diagnostic) => ({
1517
+ code: diagnostic.code,
1518
+ message: diagnostic.message,
1519
+ sourceId,
1520
+ span: rangeToPslSpan(diagnostic.range, sourceFile)
1521
+ }));
1522
+ }
1523
+ /**
1524
+ * The files a Prisma 7 schema input names: the file itself, or every regular
1525
+ * `.prisma` file under the directory, nested directories and symbolic links
1526
+ * included, as Prisma 7 reads a schema directory. Sorted by path so duplicate
1527
+ * detection blames the later file deterministically.
1528
+ */
1529
+ async function listSchemaFiles(absolutePath, displayPath) {
1530
+ if (!(await stat(absolutePath)).isDirectory()) return [{
1531
+ sourceId: displayPath,
1532
+ absolutePath
1533
+ }];
1534
+ const entries = await readdir(absolutePath, { recursive: true });
1535
+ const files = [];
1536
+ for (const entry of entries.filter((name) => extname(name) === ".prisma").map((name) => normalize(name)).sort()) {
1537
+ const entryPath = join(absolutePath, entry);
1538
+ if ((await stat(entryPath)).isFile()) files.push({
1539
+ sourceId: join(displayPath, entry),
1540
+ absolutePath: entryPath
1541
+ });
1542
+ }
1543
+ return files;
1544
+ }
1545
+ /**
1546
+ * The checks `contract emit` runs on the contract after `load` that the
1547
+ * contract builder does not: domain roots and relations, column defaults
1548
+ * against nullability, and model storage references. The structural check also
1549
+ * needs the target's entity kinds, which `load` does not receive.
1550
+ */
1551
+ function validateInterpretedContract(contract) {
1552
+ validateContractDomain(contract);
1553
+ const sqlContract = blindCast(contract);
1554
+ validateSqlStorageConsistency(sqlContract);
1555
+ validateModelStorageReferences(sqlContract);
1556
+ }
1557
+ function prisma7Contract(schemaPath, options) {
1558
+ return {
1559
+ source: {
1560
+ format: "prisma7",
1561
+ inputs: [schemaPath],
1562
+ async load(context) {
1563
+ const [absolutePath] = context.resolvedInputs;
1564
+ if (absolutePath === void 0) throw new InternalError("prisma7Contract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.");
1565
+ let files;
1566
+ try {
1567
+ files = await listSchemaFiles(absolutePath, schemaPath);
1568
+ } catch (error) {
1569
+ const message = String(error);
1570
+ return notOk({
1571
+ summary: `Failed to read Prisma 7 schema at "${schemaPath}"`,
1572
+ diagnostics: [prisma7Diagnostic("PSL.PRISMA7_SCHEMA_READ_FAILED", message, schemaPath, void 0)],
1573
+ meta: {
1574
+ schemaPath,
1575
+ absolutePath,
1576
+ cause: message
1577
+ }
1578
+ });
1579
+ }
1580
+ if (files.length === 0) return notOk({
1581
+ summary: `Failed to read Prisma 7 schema at "${schemaPath}"`,
1582
+ diagnostics: [prisma7Diagnostic("PSL.PRISMA7_SCHEMA_READ_FAILED", `The schema directory "${schemaPath}" contains no .prisma file.`, schemaPath, void 0)],
1583
+ meta: {
1584
+ schemaPath,
1585
+ absolutePath
1586
+ }
1587
+ });
1588
+ const documents = [];
1589
+ const seedDiagnostics = [];
1590
+ for (const file of files) {
1591
+ let schema;
1592
+ try {
1593
+ schema = await readFile(file.absolutePath, "utf-8");
1594
+ } catch (error) {
1595
+ const message = String(error);
1596
+ return notOk({
1597
+ summary: `Failed to read Prisma 7 schema at "${file.sourceId}"`,
1598
+ diagnostics: [prisma7Diagnostic("PSL.PRISMA7_SCHEMA_READ_FAILED", message, file.sourceId, void 0)],
1599
+ meta: {
1600
+ schemaPath: file.sourceId,
1601
+ absoluteSchemaPath: file.absolutePath,
1602
+ cause: message
1603
+ }
1604
+ });
1605
+ }
1606
+ const { document, sourceFile, diagnostics } = parse(schema, { grammar: "prisma7" });
1607
+ seedDiagnostics.push(...mapParseDiagnostics(diagnostics, sourceFile, file.sourceId));
1608
+ documents.push({
1609
+ document,
1610
+ sourceFile,
1611
+ sourceId: file.sourceId
1612
+ });
1613
+ }
1614
+ let contract;
1615
+ try {
1616
+ const interpreted = interpretPrisma7Documents({
1617
+ documents,
1618
+ seedDiagnostics,
1619
+ binding: options.binding,
1620
+ controlMutationDefaults: context.controlMutationDefaults,
1621
+ authoringContributions: context.authoringContributions,
1622
+ codecLookup: context.codecLookup,
1623
+ composedExtensions: context.composedExtensions
1624
+ });
1625
+ if (!interpreted.ok) return interpreted;
1626
+ contract = applySqlSpecifierControlPolicy(interpreted.value, options.defaultControlPolicy, options.binding.createNamespace);
1627
+ validateInterpretedContract(contract);
1628
+ } catch (error) {
1629
+ if (!isStructuredError(error)) throw error;
1630
+ return notOk({
1631
+ summary: "Prisma 7 schema interpretation failed",
1632
+ diagnostics: [prisma7Diagnostic("PSL.PRISMA7_CONTRACT_INVALID", `This schema gives a contract that Prisma 8 rejects, and the Prisma 7 contract source has no specific diagnostic for the cause: ${error.message.replace(/\.$/, "")}. This is a bug in Prisma ORM; please report it with this schema.`, schemaPath, void 0)],
1633
+ meta: {
1634
+ schemaPath,
1635
+ code: error.code
1636
+ }
1637
+ });
1638
+ }
1639
+ return ok(contract);
1640
+ }
1641
+ },
1642
+ output: options.output ?? defaultOutputFromSchemaPath(schemaPath)
1643
+ };
1644
+ }
1645
+ //#endregion
1646
+ export { prisma7Contract };
1647
+
1648
+ //# sourceMappingURL=contract-prisma7__provider.mjs.map