@prisma/orm-family-mongo 8.0.0-rc.2-dev.3 → 8.0.0-rc.20-dev.1

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 (207) hide show
  1. package/README.md +1 -5
  2. package/dist/authoring-entity-types-UA5sY_Xm-DeYf_cYq.mjs +87 -0
  3. package/dist/authoring-entity-types-UA5sY_Xm-DeYf_cYq.mjs.map +1 -0
  4. package/dist/{canonicalization-hooks-DF3Z6sjO.mjs → canonicalization-hooks-CRVM-Kqh-Qi-VmEVg.mjs} +4 -3
  5. package/dist/canonicalization-hooks-CRVM-Kqh-Qi-VmEVg.mjs.map +1 -0
  6. package/dist/codec.d.mts +1 -1
  7. package/dist/codec.mjs +1 -1
  8. package/dist/{config-types-CFDf9ivE.mjs → config-types-DYTCUpAs.mjs} +5 -5
  9. package/dist/config-types-DYTCUpAs.mjs.map +1 -0
  10. package/dist/contract-builder-BHzQQk70.mjs +965 -0
  11. package/dist/contract-builder-BHzQQk70.mjs.map +1 -0
  12. package/dist/{contract-builder-DB8nguDE.d.mts → contract-builder-ClL-xMK2.d.mts} +271 -89
  13. package/dist/contract-builder-ClL-xMK2.d.mts.map +1 -0
  14. package/dist/contract-prisma6__provider.d.mts +35 -0
  15. package/dist/contract-prisma6__provider.d.mts.map +1 -0
  16. package/dist/contract-prisma6__provider.mjs +1202 -0
  17. package/dist/contract-prisma6__provider.mjs.map +1 -0
  18. package/dist/contract-psl.d.mts +152 -28
  19. package/dist/contract-psl.d.mts.map +1 -1
  20. package/dist/contract-psl.mjs +3 -2
  21. package/dist/contract-psl__provider.mjs +74 -44
  22. package/dist/contract-psl__provider.mjs.map +1 -1
  23. package/dist/contract-ts.d.mts +2 -2
  24. package/dist/contract-ts.mjs +2 -2
  25. package/dist/contract-ts__config-types.mjs +1 -1
  26. package/dist/contract-ts__contract-builder.d.mts +2 -2
  27. package/dist/contract-ts__contract-builder.mjs +1 -1
  28. package/dist/contract.d.mts +3 -3
  29. package/dist/contract.mjs +3 -3
  30. package/dist/contract__canonicalization-hooks.mjs +1 -1
  31. package/dist/contract__data-type.d.mts +37 -0
  32. package/dist/contract__data-type.d.mts.map +1 -0
  33. package/dist/contract__data-type.mjs +2 -0
  34. package/dist/contract__entity-kinds.d.mts +1 -1
  35. package/dist/contract__entity-kinds.mjs +1 -1
  36. package/dist/{control-C7-kthr1.d.mts → control-4pC8N2Rb.d.mts} +32 -19
  37. package/dist/control-4pC8N2Rb.d.mts.map +1 -0
  38. package/dist/{control-CClR5JMr.mjs → control-BQMBG11d.mjs} +19 -2
  39. package/dist/control-BQMBG11d.mjs.map +1 -0
  40. package/dist/{control-BbZQqmxo.mjs → control-B_pPN58L.mjs} +195 -87
  41. package/dist/control-B_pPN58L.mjs.map +1 -0
  42. package/dist/{control-Cj81sPbj.d.mts → control-CvQSMuxa.d.mts} +29 -6
  43. package/dist/control-CvQSMuxa.d.mts.map +1 -0
  44. package/dist/{control-adapter-Db5pT77b.d.mts → control-adapter-Bh_ZraGM--5JDb99k.d.mts} +48 -4
  45. package/dist/control-adapter-Bh_ZraGM--5JDb99k.d.mts.map +1 -0
  46. package/dist/control-adapter-CndDiTXW.d.mts +1 -0
  47. package/dist/dist-B8f-pfcT.mjs +1031 -0
  48. package/dist/dist-B8f-pfcT.mjs.map +1 -0
  49. package/dist/dist-Bgk36iLI.mjs +53 -0
  50. package/dist/dist-Bgk36iLI.mjs.map +1 -0
  51. package/dist/{dist-C7Ykq48Q.mjs → dist-CO2arS1K.mjs} +3 -1
  52. package/dist/dist-CO2arS1K.mjs.map +1 -0
  53. package/dist/{dist-Dyp05u64.mjs → dist-gmGbjhmk.mjs} +56 -32
  54. package/dist/dist-gmGbjhmk.mjs.map +1 -0
  55. package/dist/dist-xk_0xOR-.mjs +28 -0
  56. package/dist/dist-xk_0xOR-.mjs.map +1 -0
  57. package/dist/emitter.d.mts +2 -4
  58. package/dist/emitter.d.mts.map +1 -1
  59. package/dist/emitter.mjs +1 -1
  60. package/dist/{entity-kinds-B4KNTF8z-DPIuUuuB.mjs → entity-kinds-BQBtfVet-B-Px7NHp.mjs} +35 -18
  61. package/dist/entity-kinds-BQBtfVet-B-Px7NHp.mjs.map +1 -0
  62. package/dist/{execution-D5XyZ5XS.mjs → execution-CgP1Sdbr.mjs} +6 -3
  63. package/dist/execution-CgP1Sdbr.mjs.map +1 -0
  64. package/dist/{execution-CKnUiOfm.d.mts → execution-tPmN5pge.d.mts} +6 -2
  65. package/dist/execution-tPmN5pge.d.mts.map +1 -0
  66. package/dist/{exports-Bx-hlnZ3.mjs → exports-BAimNKOs.mjs} +31 -21
  67. package/dist/exports-BAimNKOs.mjs.map +1 -0
  68. package/dist/exports-BHQVApAg.mjs +86 -0
  69. package/dist/exports-BHQVApAg.mjs.map +1 -0
  70. package/dist/family.d.mts +11 -10
  71. package/dist/family.mjs +10 -9
  72. package/dist/family__control-adapter.d.mts +3 -2
  73. package/dist/family__control.d.mts +2 -2
  74. package/dist/family__control.mjs +3 -3
  75. package/dist/family__ir.d.mts +2 -2
  76. package/dist/family__ir.mjs +3 -3
  77. package/dist/family__migration.d.mts +1 -1
  78. package/dist/family__migration.mjs +1 -1
  79. package/dist/family__pack.d.mts +1 -1
  80. package/dist/family__pack.mjs +4 -2
  81. package/dist/family__pack.mjs.map +1 -1
  82. package/dist/family__runtime.d.mts +3 -3
  83. package/dist/family__runtime.mjs +3 -2
  84. package/dist/family__schema-verify.d.mts +1 -1
  85. package/dist/family__schema-verify.mjs +1 -1
  86. package/dist/{field-accessor-0oUt6RZC-B_Z30uAA.mjs → field-accessor-0oUt6RZC-CrJVzQiS.mjs} +2 -2
  87. package/dist/{field-accessor-0oUt6RZC-B_Z30uAA.mjs.map → field-accessor-0oUt6RZC-CrJVzQiS.mjs.map} +1 -1
  88. package/dist/{field-accessor-DHsAPiW3-BdYCspQC.d.mts → field-accessor-CmxCw9xP-C6jMngbK.d.mts} +35 -24
  89. package/dist/field-accessor-CmxCw9xP-C6jMngbK.d.mts.map +1 -0
  90. package/dist/index-9DDQlC5U.d.mts +87 -0
  91. package/dist/index-9DDQlC5U.d.mts.map +1 -0
  92. package/dist/{index-BR0ue13b.d.mts → index-BdXzdXGE.d.mts} +14 -8
  93. package/dist/index-BdXzdXGE.d.mts.map +1 -0
  94. package/dist/index-BhIiYIXu.d.mts +845 -0
  95. package/dist/index-BhIiYIXu.d.mts.map +1 -0
  96. package/dist/index-CQG5l2o9.d.mts +67 -0
  97. package/dist/index-CQG5l2o9.d.mts.map +1 -0
  98. package/dist/{index-DAOkcTCK.d.mts → index-FeVOOdZ0.d.mts} +9 -8
  99. package/dist/index-FeVOOdZ0.d.mts.map +1 -0
  100. package/dist/index-YY1SU_7o.d.mts +366 -0
  101. package/dist/index-YY1SU_7o.d.mts.map +1 -0
  102. package/dist/{index-DxoO-ywI.d.mts → index-rANtsIZG.d.mts} +9 -5
  103. package/dist/{index-DxoO-ywI.d.mts.map → index-rANtsIZG.d.mts.map} +1 -1
  104. package/dist/interpreter-BfHdPd7T-DGqi2_Um.mjs +2186 -0
  105. package/dist/interpreter-BfHdPd7T-DGqi2_Um.mjs.map +1 -0
  106. package/dist/{ir-CQrenTYt.d.mts → ir-BLC0t6_x.d.mts} +5 -27
  107. package/dist/ir-BLC0t6_x.d.mts.map +1 -0
  108. package/dist/{ir-Ch2aPr7a.mjs → ir-DGm0HXbP.mjs} +3 -8
  109. package/dist/ir-DGm0HXbP.mjs.map +1 -0
  110. package/dist/lowering.d.mts +1 -1
  111. package/dist/{migration-dcM7u4HG.mjs → migration-DnQ7_A_B.mjs} +4 -4
  112. package/dist/migration-DnQ7_A_B.mjs.map +1 -0
  113. package/dist/{migration-CNDQv5yB.d.mts → migration-YQVmgFU8.d.mts} +7 -7
  114. package/dist/{migration-CNDQv5yB.d.mts.map → migration-YQVmgFU8.d.mts.map} +1 -1
  115. package/dist/{mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs → mongo-contract-serializer-Zx1rvil3-BywiKCpn.mjs} +27 -8
  116. package/dist/mongo-contract-serializer-Zx1rvil3-BywiKCpn.mjs.map +1 -0
  117. package/dist/{mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts → mongo-contract-view-AnejqfrQ-Wj_ulq2L.d.mts} +3 -3
  118. package/dist/{mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts.map → mongo-contract-view-AnejqfrQ-Wj_ulq2L.d.mts.map} +1 -1
  119. package/dist/{mongo-contract-view-rcWzby6f-wRBCUnBt.mjs → mongo-contract-view-D5yu2LrY-DCAZYJ4q.mjs} +4 -4
  120. package/dist/{mongo-contract-view-rcWzby6f-wRBCUnBt.mjs.map → mongo-contract-view-D5yu2LrY-DCAZYJ4q.mjs.map} +1 -1
  121. package/dist/mongo-data-type-DzyzU4LF-C1ydFXgE.mjs +53 -0
  122. package/dist/mongo-data-type-DzyzU4LF-C1ydFXgE.mjs.map +1 -0
  123. package/dist/{mongo-value-set-tNn9-pun-dJYx_rVD.d.mts → mongo-value-set-DEd7WLCT-B2Ar2GkJ.d.mts} +20 -4
  124. package/dist/mongo-value-set-DEd7WLCT-B2Ar2GkJ.d.mts.map +1 -0
  125. package/dist/orm.d.mts +154 -96
  126. package/dist/orm.d.mts.map +1 -1
  127. package/dist/orm.mjs +670 -148
  128. package/dist/orm.mjs.map +1 -1
  129. package/dist/pack-qw77Jt2G.d.mts +58 -0
  130. package/dist/pack-qw77Jt2G.d.mts.map +1 -0
  131. package/dist/query-ast.d.mts +5 -5
  132. package/dist/query-ast.mjs +3 -3
  133. package/dist/query-ast__control.d.mts +4 -4
  134. package/dist/query-ast__control.mjs +2 -2
  135. package/dist/query-ast__execution.d.mts +2 -2
  136. package/dist/query-ast__execution.mjs +1 -1
  137. package/dist/query-builder.d.mts +4 -836
  138. package/dist/query-builder.mjs +2 -2
  139. package/dist/query-builder__contract-free.d.mts +6 -6
  140. package/dist/query-builder__contract-free.mjs +3 -3
  141. package/dist/{query-plan-C0-Yu8hf-DdilEdW6.d.mts → query-plan-3fs1HokF-CrNsr-Wx.d.mts} +10 -4
  142. package/dist/{query-plan-C0-Yu8hf-DdilEdW6.d.mts.map → query-plan-3fs1HokF-CrNsr-Wx.d.mts.map} +1 -1
  143. package/dist/runtime-B5fNQHQZ.mjs +16 -0
  144. package/dist/runtime-B5fNQHQZ.mjs.map +1 -0
  145. package/dist/runtime-yZA30qM2.d.mts +11 -0
  146. package/dist/runtime-yZA30qM2.d.mts.map +1 -0
  147. package/dist/runtime.d.mts +74 -87
  148. package/dist/runtime.d.mts.map +1 -1
  149. package/dist/runtime.mjs +133 -67
  150. package/dist/runtime.mjs.map +1 -1
  151. package/dist/schema-ir.d.mts +2 -2
  152. package/dist/schema-ir.mjs +2 -2
  153. package/dist/{schema-verify-DJGr28XW.d.mts → schema-verify-CVOG6EZx.d.mts} +5 -5
  154. package/dist/{schema-verify-DJGr28XW.d.mts.map → schema-verify-CVOG6EZx.d.mts.map} +1 -1
  155. package/dist/value.d.mts +2 -2
  156. package/dist/value.mjs +1 -1
  157. package/dist/{verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs → verify-mongo-schema-CeQP5N4k-CNOctppM.mjs} +9 -26
  158. package/dist/verify-mongo-schema-CeQP5N4k-CNOctppM.mjs.map +1 -0
  159. package/dist/wire.d.mts +3 -3
  160. package/dist/wire.mjs +14 -2
  161. package/dist/wire.mjs.map +1 -1
  162. package/package.json +24 -21
  163. package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs +0 -176
  164. package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs.map +0 -1
  165. package/dist/canonicalization-hooks-DF3Z6sjO.mjs.map +0 -1
  166. package/dist/config-types-CFDf9ivE.mjs.map +0 -1
  167. package/dist/contract-builder-BFq0gOMV.mjs +0 -634
  168. package/dist/contract-builder-BFq0gOMV.mjs.map +0 -1
  169. package/dist/contract-builder-DB8nguDE.d.mts.map +0 -1
  170. package/dist/control-BbZQqmxo.mjs.map +0 -1
  171. package/dist/control-C7-kthr1.d.mts.map +0 -1
  172. package/dist/control-CClR5JMr.mjs.map +0 -1
  173. package/dist/control-Cj81sPbj.d.mts.map +0 -1
  174. package/dist/control-adapter-Db5pT77b.d.mts.map +0 -1
  175. package/dist/dist-C7Ykq48Q.mjs.map +0 -1
  176. package/dist/dist-Czwqx_i3.mjs +0 -58
  177. package/dist/dist-Czwqx_i3.mjs.map +0 -1
  178. package/dist/dist-DHrEJnhK.mjs +0 -236
  179. package/dist/dist-DHrEJnhK.mjs.map +0 -1
  180. package/dist/dist-Dyp05u64.mjs.map +0 -1
  181. package/dist/entity-kinds-B4KNTF8z-DPIuUuuB.mjs.map +0 -1
  182. package/dist/execution-CKnUiOfm.d.mts.map +0 -1
  183. package/dist/execution-D5XyZ5XS.mjs.map +0 -1
  184. package/dist/exports-Bx-hlnZ3.mjs.map +0 -1
  185. package/dist/exports-C4RGBGzZ.mjs +0 -156
  186. package/dist/exports-C4RGBGzZ.mjs.map +0 -1
  187. package/dist/field-accessor-DHsAPiW3-BdYCspQC.d.mts.map +0 -1
  188. package/dist/index-BR0ue13b.d.mts.map +0 -1
  189. package/dist/index-Cd2zLiU6.d.mts +0 -128
  190. package/dist/index-Cd2zLiU6.d.mts.map +0 -1
  191. package/dist/index-DAOkcTCK.d.mts.map +0 -1
  192. package/dist/index-Dv2PNMiG.d.mts +0 -53
  193. package/dist/index-Dv2PNMiG.d.mts.map +0 -1
  194. package/dist/index-wKMm41HC.d.mts +0 -30
  195. package/dist/index-wKMm41HC.d.mts.map +0 -1
  196. package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs +0 -1091
  197. package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs.map +0 -1
  198. package/dist/ir-CQrenTYt.d.mts.map +0 -1
  199. package/dist/ir-Ch2aPr7a.mjs.map +0 -1
  200. package/dist/migration-dcM7u4HG.mjs.map +0 -1
  201. package/dist/mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs.map +0 -1
  202. package/dist/mongo-value-set-tNn9-pun-dJYx_rVD.d.mts.map +0 -1
  203. package/dist/pack-D9aLY50F.d.mts +0 -44
  204. package/dist/pack-D9aLY50F.d.mts.map +0 -1
  205. package/dist/query-builder.d.mts.map +0 -1
  206. package/dist/runtime-DPkRW4iu.d.mts +0 -1
  207. package/dist/verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs.map +0 -1
@@ -0,0 +1,1202 @@
1
+ import { o as MongoIndex } from "./entity-kinds-BQBtfVet-B-Px7NHp.mjs";
2
+ import { N as validateMongoStorage, u as buildMongoStorage, w as mongoValueSetsOf } from "./dist-B8f-pfcT.mjs";
3
+ import { i as pairMongoBackRelations } from "./interpreter-BfHdPd7T-DGqi2_Um.mjs";
4
+ import { isStructuredError } from "@prisma/orm-framework/utils/structured-error";
5
+ import { blindCast } from "@prisma/orm-framework/utils/casts";
6
+ import { crossRef } from "@prisma/orm-framework/contract/types";
7
+ import { buildExecutionSection, computeProfileHash } from "@prisma/orm-framework/contract/hashing";
8
+ import { InternalError } from "@prisma/orm-framework/utils/internal-error";
9
+ import { readFile, readdir, stat } from "node:fs/promises";
10
+ import { applySpecifierDefaultControlPolicy } from "@prisma/orm-framework/contract/apply-specifier-default-control-policy";
11
+ import { validateContractDomain } from "@prisma/orm-framework/contract/validate-domain";
12
+ import { ArrayLiteralAst, FunctionCallAst, IdentifierAst, PathExprAst, StringLiteralExprAst, dottedPathsIn, parse, printSyntax } from "@prisma/orm-framework/psl-parser/syntax";
13
+ import { notOk, ok } from "@prisma/orm-framework/utils/result";
14
+ import { basename, dirname, extname, join, normalize } from "pathe";
15
+ import { resolveToOneRelationNullable } from "@prisma/orm-framework/contract-authoring";
16
+ import { encodeEnumMembers, enumMemberProblemDiagnostic, instantiateAuthoringEntityType, isAuthoringEntityTypeDescriptor } from "@prisma/orm-framework/components/authoring";
17
+ import { buildSymbolTable, keywordPslSpan, mapPslDiagnostics, nodePslSpan, readResolvedAttribute } from "@prisma/orm-framework/psl-parser";
18
+ import { fkRelationPairKey } from "@prisma/orm-framework/psl-parser/interpret";
19
+ import { ifDefined } from "@prisma/orm-framework/utils/defined";
20
+ //#region ../../../2-mongo-family/2-authoring/contract-prisma6/dist/provider.mjs
21
+ function prisma6Diagnostic(code, message, sourceId, span) {
22
+ return {
23
+ code,
24
+ message,
25
+ sourceId,
26
+ ...span !== void 0 ? { span } : {}
27
+ };
28
+ }
29
+ function unsupported(attribute, what, span, ctx) {
30
+ ctx.diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_INDEX_ARGUMENT_UNSUPPORTED", `${ctx.owner}: ${ctx.prefix}${attribute.name} ${what}`, ctx.sourceId, span));
31
+ }
32
+ function sortDirection(expression) {
33
+ if (expression === void 0) return void 0;
34
+ const token = IdentifierAst.cast(expression.syntax)?.name();
35
+ return token === "Asc" ? 1 : token === "Desc" ? -1 : void 0;
36
+ }
37
+ /**
38
+ * Reads `sort:` from one index element's or `@unique`'s arguments. `length:` and every other argument are refused: a MongoDB index has no prefix length, and Prisma 6 accepts no other argument there on MongoDB.
39
+ */
40
+ function readSort(attribute, args, ctx) {
41
+ let direction;
42
+ for (const arg of args) {
43
+ const key = arg.name()?.name();
44
+ const span = nodePslSpan(arg.syntax, ctx.sources);
45
+ if (key !== "sort") return unsupported(attribute, key === "length" ? "argument \"length\" is not supported: a MongoDB index has no prefix length. Remove it; Prisma 6 ignores it on MongoDB." : `argument "${key ?? ""}" is not supported.`, span, ctx);
46
+ direction = sortDirection(arg.value());
47
+ if (direction === void 0) return unsupported(attribute, "sort must be Asc or Desc.", span, ctx);
48
+ }
49
+ return { direction };
50
+ }
51
+ function readFields(attribute, expression, span, ctx) {
52
+ const array = expression === void 0 ? void 0 : ArrayLiteralAst.cast(expression.syntax);
53
+ if (array === void 0) return unsupported(attribute, "expects a list of field names.", span, ctx);
54
+ const fields = [];
55
+ for (const element of array.elements()) {
56
+ const name = IdentifierAst.cast(element.syntax)?.name();
57
+ if (name !== void 0) {
58
+ fields.push({
59
+ name,
60
+ direction: void 0
61
+ });
62
+ continue;
63
+ }
64
+ const call = FunctionCallAst.cast(element.syntax);
65
+ const path = PathExprAst.cast(element.syntax)?.path() ?? call?.path() ?? [];
66
+ const [callee] = path;
67
+ if (path.length > 1 && (callee === void 0 || !ctx.compositeFields.has(callee))) return unsupported(attribute, `lists the dotted path "${path.join(".")}", but "${callee ?? ""}" is not a composite-type field of the model, and Prisma 6 refuses the path as an unknown field. List fields of the model by name.`, nodePslSpan(element.syntax, ctx.sources), ctx);
68
+ if (path.length > 1) {
69
+ ctx.diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_COMPOSITE_INDEX_PATH_UNSUPPORTED", `Index path "${path.join(".")}" reaches into a composite type; indexes on composite-type fields are not supported yet. Index a top-level field or remove the index. Either change also reaches the Prisma 6 app, whose \`db push\` builds its indexes from this schema.`, ctx.sourceId, nodePslSpan(element.syntax, ctx.sources)));
70
+ return;
71
+ }
72
+ if (call === void 0 || callee === void 0) return unsupported(attribute, "expects a list of field names.", nodePslSpan(element.syntax, ctx.sources), ctx);
73
+ const sort = readSort(attribute, call.args(), ctx);
74
+ if (sort === void 0) return void 0;
75
+ fields.push({
76
+ name: callee,
77
+ direction: sort.direction
78
+ });
79
+ }
80
+ return fields;
81
+ }
82
+ /** Reads `@@index`, `@@unique` or `@@fulltext`. `map:` and `name:` are dropped: MongoDB verify never compares index names. */
83
+ function parseIndexAttribute(attribute, ctx) {
84
+ let fields;
85
+ for (const arg of attribute.args) {
86
+ const key = arg.kind === "positional" ? "fields" : arg.name;
87
+ if (key === "map" || key === "name") continue;
88
+ if (key !== "fields") return unsupported(attribute, `argument "${key ?? ""}" is not supported.`, arg.span, ctx);
89
+ fields = readFields(attribute, arg.expression, arg.span, ctx);
90
+ if (fields === void 0) return void 0;
91
+ }
92
+ if (fields === void 0 || fields.length === 0) return unsupported(attribute, "expects a list of field names.", attribute.span, ctx);
93
+ return {
94
+ kind: attribute.name,
95
+ fields,
96
+ span: attribute.span
97
+ };
98
+ }
99
+ /** Reads a field's `@unique`: `sort:` sets the key direction; `map:` and `name:` are dropped. */
100
+ function parseFieldUnique(attribute, fieldName, ctx) {
101
+ let direction;
102
+ for (const arg of attribute.args) {
103
+ const key = arg.kind === "positional" ? void 0 : arg.name;
104
+ if (key === "map" || key === "name") continue;
105
+ if (key === "sort") {
106
+ direction = sortDirection(arg.expression);
107
+ if (direction === void 0) return unsupported(attribute, "sort must be Asc or Desc.", arg.span, ctx);
108
+ continue;
109
+ }
110
+ return unsupported(attribute, key === "length" ? "argument \"length\" is not supported: a MongoDB index has no prefix length. Remove it; Prisma 6 ignores it on MongoDB." : `argument "${key ?? ""}" is not supported.`, arg.span, ctx);
111
+ }
112
+ return {
113
+ kind: "unique",
114
+ fields: [{
115
+ name: fieldName,
116
+ direction
117
+ }],
118
+ span: attribute.span
119
+ };
120
+ }
121
+ const SUMMARY = "Prisma 6 MongoDB schema interpretation failed";
122
+ function stringArgument(attribute) {
123
+ const expression = (attribute.args.find((arg) => arg.kind === "positional") ?? attribute.args.find((arg) => arg.name === "name"))?.expression;
124
+ return expression === void 0 ? void 0 : StringLiteralExprAst.cast(expression.syntax)?.value();
125
+ }
126
+ function requireString(attribute, owner, sourceId, diagnostics) {
127
+ const value = stringArgument(attribute);
128
+ if (value === void 0) diagnostics.push({
129
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
130
+ message: `${owner}: attribute "@${attribute.name}" expects one string argument.`,
131
+ sourceId,
132
+ span: attribute.span
133
+ });
134
+ return value;
135
+ }
136
+ function attributeText(attribute) {
137
+ const args = attribute.args.map((arg) => arg.kind === "named" ? `${arg.name}: ${arg.value}` : arg.value);
138
+ return args.length === 0 ? `@${attribute.name}` : `@${attribute.name}(${args.join(", ")})`;
139
+ }
140
+ /** `auto()` and `now()` with no arguments; any other `@default` value is `other`. */
141
+ function defaultKind(attribute) {
142
+ const expression = attribute.args.find((arg) => arg.kind === "positional")?.expression;
143
+ const call = expression === void 0 ? void 0 : FunctionCallAst.cast(expression.syntax);
144
+ if (call === void 0 || [...call.args()].length > 0) return "other";
145
+ const path = call.path().join(".");
146
+ return path === "auto" ? "auto" : path === "now" ? "now" : "other";
147
+ }
148
+ function unknownAttribute(owner, attribute, prefix, sourceId) {
149
+ return prisma6Diagnostic("PSL.PRISMA6_MONGO_UNKNOWN_ATTRIBUTE", `${owner}: attribute "${prefix}${attribute.name}" is not supported by the Prisma 6 MongoDB contract source.`, sourceId, attribute.span);
150
+ }
151
+ function interpretPrisma6Documents(input) {
152
+ const { binding } = input;
153
+ const diagnostics = [...input.seedDiagnostics];
154
+ const datasources = [];
155
+ const enumBlocks = [];
156
+ const compositeTypes = [];
157
+ const models = [];
158
+ const ignoredModels = /* @__PURE__ */ new Set();
159
+ const declaredNames = /* @__PURE__ */ new Map();
160
+ const claimName = (kind, name, sourceId, span) => {
161
+ const previous = declaredNames.get(name);
162
+ if (previous === void 0) {
163
+ declaredNames.set(name, sourceId);
164
+ return true;
165
+ }
166
+ diagnostics.push({
167
+ code: "PSL_DUPLICATE_DECLARATION",
168
+ message: `Duplicate declaration of ${kind} "${name}"; first declared in ${basename(previous)}.`,
169
+ sourceId,
170
+ span
171
+ });
172
+ return false;
173
+ };
174
+ for (const { document, sources, sourceFile, sourceId } of input.documents) {
175
+ const { symbolTable, diagnostics: tableDiagnostics } = buildSymbolTable({
176
+ documents: [document],
177
+ sources,
178
+ defaultNamespaceId: input.defaultNamespaceId
179
+ });
180
+ for (const diagnostic of tableDiagnostics) diagnostics.push({
181
+ code: diagnostic.code,
182
+ message: diagnostic.message,
183
+ sourceId,
184
+ span: sourceFile.rangeToPslSpan(diagnostic.range)
185
+ });
186
+ const unsupported = (keyword, span) => {
187
+ diagnostics.push({
188
+ code: "PSL_UNSUPPORTED_TOP_LEVEL_BLOCK",
189
+ message: `Unsupported top-level block "${keyword}"`,
190
+ sourceId,
191
+ span
192
+ });
193
+ };
194
+ const unsupportedInclusions = (code, holders) => {
195
+ for (const holder of Object.values(holders)) for (const inclusion of holder.node.inclusions()) diagnostics.push({
196
+ code,
197
+ message: `Unsupported mixin inclusion "${printSyntax(inclusion.syntax).trim()}"`,
198
+ sourceId,
199
+ span: nodePslSpan(inclusion.syntax, sources)
200
+ });
201
+ };
202
+ for (const block of Object.values(symbolTable.defaultNamespace.blocks)) switch (block.keyword) {
203
+ case "datasource":
204
+ datasources.push({
205
+ symbol: block,
206
+ sourceId,
207
+ sources
208
+ });
209
+ reportDottedBlockValues(block, sourceId, sources, diagnostics);
210
+ break;
211
+ case "generator":
212
+ reportDottedBlockValues(block, sourceId, sources, diagnostics);
213
+ break;
214
+ case "enum":
215
+ if (claimName("enum", block.name, sourceId, block.span)) enumBlocks.push({
216
+ symbol: block,
217
+ sourceId,
218
+ sources
219
+ });
220
+ break;
221
+ case "view":
222
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_VIEW_UNSUPPORTED", `View "${block.name}" is not supported; Prisma 8 has no views on MongoDB. Remove the view from the schema this contract source reads. The Prisma 6 client then loses the view's model too.`, sourceId, keywordPslSpan(block.node.syntax, block.keyword, sources)));
223
+ break;
224
+ default: unsupported(block.keyword, keywordPslSpan(block.node.syntax, block.keyword, sources));
225
+ }
226
+ for (const namespace of Object.values(symbolTable.namespaces)) for (const { span } of namespace.declarations) unsupported("namespace", span);
227
+ for (const namedType of Object.values(symbolTable.namedTypes)) unsupported("types", namedType.span);
228
+ for (const mixin of Object.values(symbolTable.defaultNamespace.mixins)) unsupported(`${mixin.keyword} mixin`, mixin.span);
229
+ unsupportedInclusions("PSL_INVALID_MODEL_MEMBER", symbolTable.defaultNamespace.models);
230
+ unsupportedInclusions("PSL_INVALID_MODEL_MEMBER", symbolTable.defaultNamespace.compositeTypes);
231
+ unsupportedInclusions("PSL_INVALID_EXTENSION_BLOCK_MEMBER", symbolTable.defaultNamespace.blocks);
232
+ for (const symbol of Object.values(symbolTable.defaultNamespace.compositeTypes)) if (claimName("type", symbol.name, sourceId, symbol.span)) compositeTypes.push({
233
+ symbol,
234
+ sourceId,
235
+ sources
236
+ });
237
+ for (const symbol of Object.values(symbolTable.defaultNamespace.models)) {
238
+ if (!claimName("model", symbol.name, sourceId, symbol.span)) continue;
239
+ if (symbol.attributes.some((attribute) => attribute.name === "ignore")) ignoredModels.add(symbol.name);
240
+ else models.push({
241
+ symbol,
242
+ sourceId,
243
+ sources
244
+ });
245
+ }
246
+ }
247
+ const providerMismatch = checkDatasource(datasources, input.documents[0]?.sourceId ?? "schema.prisma", binding);
248
+ if (providerMismatch !== void 0) return notOk({
249
+ summary: SUMMARY,
250
+ diagnostics: inSourceOrder([...input.seedDiagnostics, providerMismatch], input.documents)
251
+ });
252
+ const enums = /* @__PURE__ */ new Map();
253
+ for (const located of enumBlocks) {
254
+ const built = buildEnum(located, input, diagnostics);
255
+ if (built !== void 0) enums.set(located.symbol.name, built);
256
+ }
257
+ const modelNames = /* @__PURE__ */ new Set([...models.map((m) => m.symbol.name), ...ignoredModels]);
258
+ const compositeTypeNames = new Set(compositeTypes.map((c) => c.symbol.name));
259
+ const enumNames = new Set(enumBlocks.map((located) => located.symbol.name));
260
+ const typeContext = {
261
+ binding,
262
+ generatorFunctions: input.generatorFunctions,
263
+ enums,
264
+ enumNames,
265
+ compositeTypeNames,
266
+ diagnostics,
267
+ namespaceId: input.defaultNamespaceId
268
+ };
269
+ const valueObjects = {};
270
+ for (const located of compositeTypes) valueObjects[located.symbol.name] = { fields: readCompositeFields(located, typeContext) };
271
+ const builds = /* @__PURE__ */ new Map();
272
+ for (const located of models) builds.set(located.symbol.name, readModel(located, modelNames, ignoredModels, typeContext));
273
+ const foreignKeys = [];
274
+ const invalidFkPairings = [];
275
+ const backRelations = [];
276
+ for (const build of builds.values()) readRelationFields(build, builds, {
277
+ foreignKeys,
278
+ invalidFkPairings,
279
+ backRelations
280
+ }, diagnostics, input.defaultNamespaceId);
281
+ const paired = pairMongoBackRelations({
282
+ foreignKeys,
283
+ candidates: backRelations,
284
+ invalidFkPairings,
285
+ namespaceId: input.defaultNamespaceId
286
+ });
287
+ diagnostics.push(...mapPslDiagnostics(paired.diagnostics, mergedSources(input.documents)));
288
+ for (const { modelName, fieldName, relation } of paired.relations) {
289
+ const build = builds.get(modelName);
290
+ if (build !== void 0) build.relations[fieldName] = relation;
291
+ }
292
+ const collections = {};
293
+ const roots = {};
294
+ const executionDefaults = [];
295
+ for (const [modelName, build] of builds) {
296
+ const indexes = buildIndexes(build, diagnostics);
297
+ const existing = collections[build.collection];
298
+ collections[build.collection] = { indexes: [...existing?.indexes ?? [], ...indexes] };
299
+ roots[build.collection] = crossRef(modelName, input.defaultNamespaceId);
300
+ for (const { field, phases } of build.executionDefaults) executionDefaults.push({
301
+ ref: {
302
+ namespace: input.defaultNamespaceId,
303
+ entry: build.collection,
304
+ field
305
+ },
306
+ ...phases
307
+ });
308
+ if (!build.hasId) diagnostics.push({
309
+ code: "PSL_MISSING_ID_FIELD",
310
+ message: `Model "${modelName}" has no field with @id attribute. Every model must have exactly one @id field.`,
311
+ sourceId: build.located.sourceId,
312
+ span: build.located.symbol.span
313
+ });
314
+ }
315
+ if (diagnostics.length > 0) return notOk({
316
+ summary: SUMMARY,
317
+ diagnostics: inSourceOrder(diagnostics, input.documents)
318
+ });
319
+ return ok(assembleContract({
320
+ binding,
321
+ builds,
322
+ collections,
323
+ roots,
324
+ valueObjects,
325
+ enums,
326
+ executionDefaults,
327
+ namespaceId: input.defaultNamespaceId
328
+ }));
329
+ }
330
+ /**
331
+ * Diagnostics by file, in the order the schema files were read, then by position; one with no position comes first in its file.
332
+ */
333
+ function inSourceOrder(diagnostics, documents) {
334
+ const fileOrder = new Map(documents.map((document, index) => [document.sourceId, index]));
335
+ const fileRank = (diagnostic) => fileOrder.get(diagnostic.sourceId) ?? documents.length;
336
+ const offset = (diagnostic) => diagnostic.span?.start.offset ?? -1;
337
+ return [...diagnostics].sort((a, b) => fileRank(a) - fileRank(b) || offset(a) - offset(b));
338
+ }
339
+ /** Prisma 6 accepts no dotted path in a datasource or generator block, though the parser reads one as a value. */
340
+ function reportDottedBlockValues(block, sourceId, sources, diagnostics) {
341
+ for (const entry of block.entries) {
342
+ const value = entry.value();
343
+ if (value === void 0) continue;
344
+ for (const path of dottedPathsIn(value)) diagnostics.push({
345
+ code: "PSL_INVALID_EXTENSION_BLOCK_MEMBER",
346
+ message: `${block.keyword} "${block.name}": the value of "${entry.key()?.name() ?? ""}" holds the dotted path ${path.path().join(".")}, which Prisma 6 does not accept in a ${block.keyword} block.`,
347
+ sourceId,
348
+ span: nodePslSpan(path.syntax, sources)
349
+ });
350
+ }
351
+ }
352
+ /** The provider-mismatch diagnostic, or `undefined` when the schema names a provider the target reads. */
353
+ function checkDatasource(datasources, fallbackSourceId, binding) {
354
+ const [datasource] = datasources;
355
+ const [namedProvider] = binding.providers;
356
+ if (datasource === void 0) return prisma6Diagnostic("PSL.PRISMA6_MONGO_PROVIDER_MISMATCH", `No datasource block found; add \`datasource db { provider = "${namedProvider}" }\`.`, fallbackSourceId, void 0);
357
+ const block = datasource.symbol;
358
+ let parameter;
359
+ for (const entry of block.entries) if (entry.key()?.name() === "provider") {
360
+ parameter = entry;
361
+ break;
362
+ }
363
+ const expression = parameter?.value();
364
+ const provider = expression instanceof StringLiteralExprAst ? expression.value() : void 0;
365
+ if (provider !== void 0 && binding.providers.includes(provider)) return void 0;
366
+ return prisma6Diagnostic("PSL.PRISMA6_MONGO_PROVIDER_MISMATCH", provider === void 0 ? `The datasource block declares no string \`provider\`; this contract source reads Prisma 6 schemas for provider "${namedProvider}".` : `The datasource provider is "${provider}"; this contract source reads Prisma 6 schemas for provider "${namedProvider}".`, datasource.sourceId, parameter === void 0 ? block.span : nodePslSpan(parameter.syntax, datasource.sources));
367
+ }
368
+ function buildEnum(located, input, diagnostics) {
369
+ const { symbol: block, sourceId, sources } = located;
370
+ for (const attribute of block.attributes) {
371
+ if (attribute.name === "map") continue;
372
+ if (attribute.name === "schema") {
373
+ diagnostics.push(schemaUnsupported(`Enum "${block.name}"`, attribute, sourceId));
374
+ continue;
375
+ }
376
+ diagnostics.push(unknownAttribute(`Enum "${block.name}"`, attribute, "@@", sourceId));
377
+ }
378
+ const values = Object.create(null);
379
+ const writtenValues = Object.create(null);
380
+ const parameterSpans = Object.create(null);
381
+ for (const entry of block.entries) {
382
+ const name = entry.key()?.name();
383
+ if (name === void 0) continue;
384
+ let value = name;
385
+ for (const attributeNode of entry.attributes()) {
386
+ const attribute = readResolvedAttribute(attributeNode, sources);
387
+ if (attribute.name === "map") value = requireString(attribute, `Enum member "${block.name}.${name}"`, sourceId, diagnostics) ?? value;
388
+ else diagnostics.push(unknownAttribute(`Enum member "${block.name}.${name}"`, attribute, "@", sourceId));
389
+ }
390
+ values[name] = value;
391
+ writtenValues[name] = {
392
+ kind: "string",
393
+ text: value
394
+ };
395
+ parameterSpans[name] = nodePslSpan(entry.syntax, sources);
396
+ }
397
+ const descriptor = input.authoringContributions.entityTypes["enum"];
398
+ if (descriptor === void 0 || !isAuthoringEntityTypeDescriptor(descriptor)) {
399
+ diagnostics.push({
400
+ code: "PSL_ENUM_MISSING_FACTORY",
401
+ message: `enum "${block.name}" requires an "enum" entityType factory in the active authoring contributions`,
402
+ sourceId,
403
+ span: block.span
404
+ });
405
+ return;
406
+ }
407
+ const context = {
408
+ family: input.binding.target.familyId,
409
+ target: input.binding.target.targetId,
410
+ codecLookup: input.codecLookup,
411
+ dataTypes: input.dataTypes,
412
+ sourceId,
413
+ enumInferenceCodecs: {
414
+ text: input.binding.scalarCodecIds.String,
415
+ int: input.binding.scalarCodecIds.Int
416
+ },
417
+ diagnostics: { push: (diagnostic) => {
418
+ diagnostics.push(blindCast(diagnostic));
419
+ } }
420
+ };
421
+ const handle = instantiateAuthoringEntityType("enum", descriptor, [{
422
+ kind: "enum",
423
+ keyword: "enum",
424
+ name: block.name,
425
+ values,
426
+ writtenValues,
427
+ parameterSpans,
428
+ attributes: {},
429
+ span: block.span
430
+ }], context);
431
+ if (handle === void 0 || handle === null) return void 0;
432
+ const encoded = encodeEnumMembers(handle, input.codecLookup);
433
+ if (!encoded.ok) {
434
+ const site = {
435
+ enumName: block.name,
436
+ codecId: handle.codecId,
437
+ sourceId,
438
+ span: block.span,
439
+ memberSpans: parameterSpans
440
+ };
441
+ diagnostics.push(...encoded.failure.map((problem) => enumMemberProblemDiagnostic(problem, site)));
442
+ return;
443
+ }
444
+ return {
445
+ codecId: handle.codecId,
446
+ members: encoded.value
447
+ };
448
+ }
449
+ function schemaUnsupported(owner, attribute, sourceId) {
450
+ return prisma6Diagnostic("PSL.PRISMA6_MONGO_SCHEMA_UNSUPPORTED", `${owner}: "@@schema" is not supported; a MongoDB contract has one database, bound by the connection string. Remove @@schema.`, sourceId, attribute.span);
451
+ }
452
+ function unsupportedTypeMessage(label, typeName, owner) {
453
+ const base = `${label} has type "${typeName}(...)", which has no Prisma 8 codec, so ${`${owner.kind} "${owner.name}"`} cannot use this contract source while it has the field. Prisma 6 rejects @ignore on an Unsupported field. Removing the field from the schema leaves its stored values in the documents, but the Prisma 6 client no longer reads or writes them.`;
454
+ if (owner.kind === "type") return base;
455
+ return `${base} Adding @@ignore to model "${owner.name}" keeps the model out of the contract, but the model disappears from the Prisma 6 client too, and every relation field in another model that points to it needs @ignore, which removes that field from the Prisma 6 client as well.`;
456
+ }
457
+ /** The native types Prisma 6 accepts on each MongoDB scalar, checked with Prisma 6.19. */
458
+ const PRISMA6_NATIVE_TYPES = {
459
+ String: ["db.String", "db.ObjectId"],
460
+ Boolean: ["db.Bool"],
461
+ Int: ["db.Int", "db.Long"],
462
+ BigInt: ["db.Long"],
463
+ Float: ["db.Double"],
464
+ DateTime: ["db.Date", "db.Timestamp"],
465
+ Bytes: ["db.BinData", "db.ObjectId"],
466
+ Json: ["db.Json"]
467
+ };
468
+ /** The BSON type Prisma 6 stores for each native type. */
469
+ const PRISMA6_NATIVE_TYPE_BSON = {
470
+ "db.String": "string",
471
+ "db.ObjectId": "objectId",
472
+ "db.Bool": "bool",
473
+ "db.Int": "int",
474
+ "db.Long": "long",
475
+ "db.Double": "double",
476
+ "db.Date": "date",
477
+ "db.Timestamp": "timestamp",
478
+ "db.BinData": "binData",
479
+ "db.Json": "object"
480
+ };
481
+ /** The BSON type Prisma 6 stores for each MongoDB scalar that has no native type. `Int` is a long. */
482
+ const PRISMA6_SCALAR_BSON = {
483
+ String: "string",
484
+ Boolean: "bool",
485
+ Int: "long",
486
+ BigInt: "long",
487
+ Float: "double",
488
+ DateTime: "date",
489
+ Bytes: "binData",
490
+ Json: "object"
491
+ };
492
+ function withArticle(typeName) {
493
+ return `${/^[AEIOU]/.test(typeName) ? "an" : "a"} ${typeName}`;
494
+ }
495
+ function acceptedByPrisma6(nativeType, typeName) {
496
+ return (Object.hasOwn(PRISMA6_NATIVE_TYPES, typeName) ? PRISMA6_NATIVE_TYPES[typeName] : void 0)?.includes(nativeType) === true;
497
+ }
498
+ /** Why the reader refuses a native type, and what removing it does to the Prisma 6 app. */
499
+ function nativeTypeRefusal(label, nativeType, typeName) {
500
+ const refused = `${label}: native type "@${nativeType}" is not supported`;
501
+ if (!acceptedByPrisma6(nativeType, typeName)) return `${refused}, and Prisma 6 does not accept it on ${withArticle(typeName)} field either. Remove it.`;
502
+ const declared = PRISMA6_NATIVE_TYPE_BSON[nativeType];
503
+ const plain = PRISMA6_SCALAR_BSON[typeName];
504
+ return `${refused}: Prisma 6 stores it as a BSON ${declared}, and Prisma 8 has no codec for that BSON type. Remove it; this also changes the Prisma 6 app: its client then stores new ${typeName} values as BSON ${plain} instead of ${declared}. Documents already stored keep their ${declared} values, so rewrite them as ${plain}s before Prisma 8 reads them.`;
505
+ }
506
+ function nativeTypeCodecId(binding, typeName, nativeType) {
507
+ const forType = Object.hasOwn(binding.nativeTypeCodecIds, typeName) ? binding.nativeTypeCodecIds[typeName] : void 0;
508
+ return forType !== void 0 && Object.hasOwn(forType, nativeType) ? forType[nativeType] : void 0;
509
+ }
510
+ /** The field's contract type, or `undefined` after reporting why it has none. */
511
+ function resolveFieldType(field, owner, nativeType, sourceId, ctx) {
512
+ const { binding, diagnostics } = ctx;
513
+ const label = `Field "${owner.name}.${field.name}"`;
514
+ if (field.typeConstructor !== void 0) {
515
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_UNSUPPORTED_TYPE", unsupportedTypeMessage(label, field.typeConstructor.path.join("."), owner), sourceId, field.typeConstructor.span));
516
+ return;
517
+ }
518
+ const nativeTypeUnsupported = (attribute) => {
519
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_NATIVE_TYPE_UNSUPPORTED", nativeTypeRefusal(label, attribute.name, field.typeName), sourceId, attribute.span));
520
+ };
521
+ const many = { many: field.list ? { elementNullable: false } : false };
522
+ if (ctx.compositeTypeNames.has(field.typeName)) {
523
+ if (nativeType !== void 0) return nativeTypeUnsupported(nativeType);
524
+ return {
525
+ type: {
526
+ kind: "valueObject",
527
+ name: field.typeName
528
+ },
529
+ nullable: field.optional,
530
+ ...many
531
+ };
532
+ }
533
+ const enumBuild = ctx.enums.get(field.typeName);
534
+ if (enumBuild !== void 0) {
535
+ if (nativeType !== void 0) return nativeTypeUnsupported(nativeType);
536
+ const valueSet = {
537
+ plane: "domain",
538
+ entityKind: "enum",
539
+ namespaceId: ctx.namespaceId,
540
+ entityName: field.typeName
541
+ };
542
+ return {
543
+ type: {
544
+ kind: "scalar",
545
+ codecId: enumBuild.codecId
546
+ },
547
+ nullable: field.optional,
548
+ valueSet,
549
+ ...many
550
+ };
551
+ }
552
+ if (ctx.enumNames.has(field.typeName)) return nativeType === void 0 ? void 0 : nativeTypeUnsupported(nativeType);
553
+ const scalarCodecId = Object.hasOwn(binding.scalarCodecIds, field.typeName) ? binding.scalarCodecIds[field.typeName] : void 0;
554
+ if (scalarCodecId === void 0) {
555
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_UNSUPPORTED_TYPE", `${label} has unknown type "${field.typeName}": it is not a scalar type, an enum, a composite type, or a model. Correct the type name.`, sourceId, field.span));
556
+ return;
557
+ }
558
+ let codecId = scalarCodecId;
559
+ if (nativeType !== void 0) {
560
+ const nativeCodecId = nativeTypeCodecId(binding, field.typeName, nativeType.name);
561
+ if (nativeCodecId === void 0) return nativeTypeUnsupported(nativeType);
562
+ codecId = nativeCodecId;
563
+ }
564
+ return {
565
+ type: {
566
+ kind: "scalar",
567
+ codecId
568
+ },
569
+ nullable: field.optional,
570
+ ...many
571
+ };
572
+ }
573
+ function readCompositeFields(located, ctx) {
574
+ const { symbol, sourceId } = located;
575
+ for (const attribute of symbol.attributes) ctx.diagnostics.push(unknownAttribute(`Type "${symbol.name}"`, attribute, "@@", sourceId));
576
+ const fields = {};
577
+ for (const field of Object.values(symbol.fields)) {
578
+ if (field.malformedType) continue;
579
+ const label = `Field "${symbol.name}.${field.name}"`;
580
+ let nativeType;
581
+ let rejected = false;
582
+ for (const attribute of field.attributes) if (attribute.name.startsWith("db.")) nativeType = attribute;
583
+ else if (attribute.name === "map") {
584
+ ctx.diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_COMPOSITE_MAP_UNSUPPORTED", `${label}: @map on a field of a composite type is not supported yet. The stored field keeps the name "${stringArgument(attribute) ?? field.name}", so removing @map renames it in storage; keep the schema as it is until Prisma 8 supports it.`, sourceId, attribute.span));
585
+ rejected = true;
586
+ } else if (attribute.name === "default") {
587
+ ctx.diagnostics.push(defaultUnsupported(label, attribute, {
588
+ kind: "type",
589
+ name: symbol.name
590
+ }, field, sourceId));
591
+ rejected = true;
592
+ } else {
593
+ ctx.diagnostics.push(unknownAttribute(label, attribute, "@", sourceId));
594
+ rejected = true;
595
+ }
596
+ if (rejected) continue;
597
+ const resolved = resolveFieldType(field, {
598
+ kind: "type",
599
+ name: symbol.name
600
+ }, nativeType, sourceId, ctx);
601
+ if (resolved !== void 0) fields[field.name] = resolved;
602
+ }
603
+ return fields;
604
+ }
605
+ /** What the Prisma 6 app loses when the Prisma 6 client stops filling a default. */
606
+ function defaultRemovalConsequence(owner, field) {
607
+ if (field.optional || field.list) return owner.kind === "model" ? `a Prisma 6 create call that leaves "${field.name}" out no longer gets the default value` : `a "${owner.name}" value written without "${field.name}" no longer gets the default value`;
608
+ return owner.kind === "model" ? `every Prisma 6 create call must then pass "${field.name}"` : `every "${owner.name}" value the Prisma 6 app writes must then include "${field.name}"`;
609
+ }
610
+ function defaultUnsupported(label, attribute, owner, field, sourceId) {
611
+ return prisma6Diagnostic("PSL.PRISMA6_MONGO_DEFAULT_UNSUPPORTED", `${label}: ${attributeText(attribute)} is not supported. MongoDB has no stored defaults, and Prisma 8 fills only \`now()\` on DateTime fields. The Prisma 6 client fills this default today, so removing it also changes the Prisma 6 app: ${defaultRemovalConsequence(owner, field)}. Set the value in the application code that creates documents, then remove the default.`, sourceId, attribute.span);
612
+ }
613
+ function readModel(located, modelNames, ignoredModels, ctx) {
614
+ const { symbol, sourceId, sources } = located;
615
+ const { diagnostics } = ctx;
616
+ const modelLabel = `Model "${symbol.name}"`;
617
+ let collection = symbol.name;
618
+ const build = {
619
+ located,
620
+ collection: symbol.name,
621
+ storedNames: /* @__PURE__ */ new Map(),
622
+ ignoredFields: /* @__PURE__ */ new Set(),
623
+ rejectedFields: /* @__PURE__ */ new Set(),
624
+ fields: {},
625
+ relations: {},
626
+ executionDefaults: [],
627
+ uniqueFields: [],
628
+ modelIndexes: [],
629
+ relationFields: [],
630
+ hasId: false
631
+ };
632
+ const indexContext = {
633
+ owner: modelLabel,
634
+ prefix: "@@",
635
+ sourceId,
636
+ sources,
637
+ diagnostics,
638
+ compositeFields: new Set(Object.values(symbol.fields).filter((field) => ctx.compositeTypeNames.has(field.typeName)).map((field) => field.name))
639
+ };
640
+ for (const attribute of symbol.attributes) switch (attribute.name) {
641
+ case "map":
642
+ collection = requireString(attribute, modelLabel, sourceId, diagnostics) ?? collection;
643
+ break;
644
+ case "index":
645
+ case "unique":
646
+ case "fulltext": {
647
+ const parsed = parseIndexAttribute({
648
+ ...attribute,
649
+ name: attribute.name
650
+ }, indexContext);
651
+ if (parsed !== void 0) build.modelIndexes.push(parsed);
652
+ break;
653
+ }
654
+ case "id":
655
+ build.hasId = true;
656
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_COMPOSITE_ID_UNSUPPORTED", `${modelLabel}: @@id is not supported; a MongoDB document is identified by its "_id" field. Declare the id as \`id String @id @default(auto()) @map("_id") @db.ObjectId\`.`, sourceId, attribute.span));
657
+ break;
658
+ case "schema":
659
+ diagnostics.push(schemaUnsupported(modelLabel, attribute, sourceId));
660
+ break;
661
+ case "ignore": break;
662
+ default: diagnostics.push(unknownAttribute(modelLabel, attribute, "@@", sourceId));
663
+ }
664
+ for (const field of Object.values(symbol.fields)) {
665
+ const reported = diagnostics.length;
666
+ readModelField(field, build, modelNames, ignoredModels, ctx);
667
+ if (diagnostics.length > reported) build.rejectedFields.add(field.name);
668
+ }
669
+ return {
670
+ ...build,
671
+ collection
672
+ };
673
+ }
674
+ function readModelField(field, build, modelNames, ignoredModels, ctx) {
675
+ const { symbol, sourceId, sources } = build.located;
676
+ const { diagnostics, binding } = ctx;
677
+ const label = `Field "${symbol.name}.${field.name}"`;
678
+ const isRelationField = modelNames.has(field.typeName) && field.typeConstructor === void 0;
679
+ if (field.attributes.some((attribute) => attribute.name === "ignore")) {
680
+ build.ignoredFields.add(field.name);
681
+ const unique = field.attributes.find((attribute) => attribute.name === "unique");
682
+ if (unique !== void 0) diagnostics.push(ignoredFieldReferenced(symbol.name, [field.name], {
683
+ kind: "index",
684
+ text: `@unique on field "${symbol.name}.${field.name}"`
685
+ }, sourceId, unique.span));
686
+ return;
687
+ }
688
+ if (isRelationField) {
689
+ if (ignoredModels.has(field.typeName)) return;
690
+ let relation;
691
+ for (const attribute of field.attributes) if (attribute.name === "relation") relation = attribute;
692
+ else diagnostics.push(unknownAttribute(label, attribute, "@", sourceId));
693
+ build.relationFields.push({
694
+ field,
695
+ relation
696
+ });
697
+ return;
698
+ }
699
+ let storedName = field.name;
700
+ let nativeType;
701
+ let idAttribute;
702
+ let defaultAttribute;
703
+ let updatedAt;
704
+ for (const attribute of field.attributes) switch (attribute.name) {
705
+ case "map":
706
+ storedName = requireString(attribute, label, sourceId, diagnostics) ?? storedName;
707
+ break;
708
+ case "id":
709
+ idAttribute = attribute;
710
+ break;
711
+ case "default":
712
+ defaultAttribute = attribute;
713
+ break;
714
+ case "updatedAt":
715
+ updatedAt = attribute;
716
+ break;
717
+ case "unique": {
718
+ const parsed = parseFieldUnique(attribute, field.name, {
719
+ owner: label,
720
+ prefix: "@",
721
+ sourceId,
722
+ sources,
723
+ diagnostics,
724
+ compositeFields: /* @__PURE__ */ new Set()
725
+ });
726
+ if (parsed !== void 0) build.uniqueFields.push(parsed);
727
+ break;
728
+ }
729
+ default: if (attribute.name.startsWith("db.")) nativeType = attribute;
730
+ else diagnostics.push(unknownAttribute(label, attribute, "@", sourceId));
731
+ }
732
+ build.storedNames.set(field.name, storedName);
733
+ if (field.malformedType) return;
734
+ const owner = {
735
+ kind: "model",
736
+ name: symbol.name
737
+ };
738
+ const resolved = resolveFieldType(field, owner, nativeType, sourceId, ctx);
739
+ if (resolved === void 0) return;
740
+ const codecId = resolved.type.kind === "scalar" ? resolved.type.codecId : void 0;
741
+ if (idAttribute !== void 0) {
742
+ build.hasId = true;
743
+ if (codecId !== binding.objectIdCodecId || storedName !== "_id" || field.optional || field.list) {
744
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_ID_NOT_OBJECTID", `${label} is the model's @id, but it is not a required ObjectId stored as "_id". Prisma 8 identifies a MongoDB document by an ObjectId "_id"; declare the id as \`${field.name} String @id @default(auto()) @map("_id") @db.ObjectId\`. If stored documents have "_id" values that are not ObjectIds, this model cannot use this contract source until they are rewritten with ObjectId "_id" values, along with every field that refers to them.`, sourceId, idAttribute.span));
745
+ return;
746
+ }
747
+ if (defaultAttribute !== void 0 && defaultKind(defaultAttribute) !== "auto") {
748
+ diagnostics.push(defaultUnsupported(label, defaultAttribute, owner, field, sourceId));
749
+ return;
750
+ }
751
+ build.fields[field.name] = resolved;
752
+ return;
753
+ }
754
+ const isDateTime = codecId === binding.scalarCodecIds.DateTime && !field.list;
755
+ if (updatedAt !== void 0 && !isDateTime) {
756
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_UPDATED_AT_TYPE_UNSUPPORTED", `${label}: @updatedAt is only supported on a DateTime field. Removing it also stops the Prisma 6 client from setting the field on every update. Set the value in application code when you write documents, then remove @updatedAt.`, sourceId, updatedAt.span));
757
+ return;
758
+ }
759
+ const defaultIsNow = defaultAttribute !== void 0 && defaultKind(defaultAttribute) === "now";
760
+ if (defaultAttribute !== void 0 && (!defaultIsNow || !isDateTime)) {
761
+ diagnostics.push(defaultUnsupported(label, defaultAttribute, owner, field, sourceId));
762
+ return;
763
+ }
764
+ const generator = updatedAt !== void 0 || defaultIsNow ? dateTimeNowGenerator(ctx.generatorFunctions, binding.scalarCodecIds.DateTime) : void 0;
765
+ const phases = generator === void 0 ? void 0 : updatedAt !== void 0 ? {
766
+ onCreate: generator,
767
+ onUpdate: generator
768
+ } : defaultIsNow ? { onCreate: generator } : void 0;
769
+ if (phases !== void 0 && field.optional) {
770
+ const written = updatedAt ?? defaultAttribute;
771
+ const generator = written === void 0 ? "the generator" : attributeText(written);
772
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_OPTIONAL_GENERATED_FIELD_UNSUPPORTED", `${label} is optional and its value comes from ${generator}, which Prisma 8 cannot express on an optional field yet. Either fix also changes the Prisma 6 app: a required field makes the Prisma 6 client fail on a stored document that lacks it, and without ${generator} the Prisma 6 client no longer fills it. Make the field required once every stored document has a value, or set the value in application code and remove ${generator}.`, sourceId, written?.span ?? field.span));
773
+ return;
774
+ }
775
+ build.fields[field.name] = resolved;
776
+ if (phases !== void 0) build.executionDefaults.push({
777
+ field: storedName,
778
+ phases
779
+ });
780
+ }
781
+ /** The generator `now()` resolves to on the DateTime codec, which `@default(now())` and `@updatedAt` write. */
782
+ function dateTimeNowGenerator(generatorFunctions, codecId) {
783
+ const now = generatorFunctions.resolve({
784
+ name: "now",
785
+ args: {}
786
+ }, {
787
+ codecId,
788
+ typeParams: void 0,
789
+ length: void 0
790
+ });
791
+ if (!now.ok) throw new InternalError(`The stack binds no "now" generator function to codec "${codecId}", which the DateTime scalar maps to.`);
792
+ return now.generator;
793
+ }
794
+ function identifierList(attributeArg) {
795
+ const expression = attributeArg.expression;
796
+ const array = expression === void 0 ? void 0 : ArrayLiteralAst.cast(expression.syntax);
797
+ if (array === void 0) return void 0;
798
+ const names = [];
799
+ for (const element of array.elements()) {
800
+ const name = IdentifierAst.cast(element.syntax)?.name();
801
+ if (name === void 0) return void 0;
802
+ names.push(name);
803
+ }
804
+ return names;
805
+ }
806
+ /**
807
+ * What removing `onDelete` or `onUpdate` does to the Prisma 6 app. The Prisma 6 client emulates referential actions on MongoDB with these defaults: `onDelete` is `Restrict` on a required relation (a delete fails with P2014) and `SetNull` on an optional one, and `onUpdate` is `Cascade`.
808
+ */
809
+ function referentialActionRemoval(key, declared, sides) {
810
+ const fallback = key === "onUpdate" ? {
811
+ action: "Cascade",
812
+ when: "its default",
813
+ effect: `changing the field a ${sides.model} refers to in a ${sides.target} updates the key in its ${sides.model} documents`
814
+ } : sides.optional ? {
815
+ action: "SetNull",
816
+ when: "its default for an optional relation",
817
+ effect: `deleting a ${sides.target} sets the key to null in its ${sides.model} documents`
818
+ } : {
819
+ action: "Restrict",
820
+ when: "its default for a required relation",
821
+ effect: `deleting a ${sides.target} that still has ${sides.model} documents fails with P2014`
822
+ };
823
+ if (declared === fallback.action) return `Removing "${key}: ${declared}" leaves the Prisma 6 app as it is: ${declared} is already what the Prisma 6 client does for this relation.`;
824
+ return `The Prisma 6 client emulates referential actions, so removing "${key}: ${declared}" also changes the Prisma 6 app: its client then applies ${fallback.action}, ${fallback.when}, so ${fallback.effect}.`;
825
+ }
826
+ function readRelationArguments(attribute, label, sides, sourceId, diagnostics) {
827
+ let name;
828
+ let fields;
829
+ let references;
830
+ let rejected = false;
831
+ const invalid = (what, span) => {
832
+ rejected = true;
833
+ diagnostics.push({
834
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
835
+ message: `${label}: @relation ${what}.`,
836
+ sourceId,
837
+ span
838
+ });
839
+ };
840
+ for (const arg of attribute.args) {
841
+ const key = arg.kind === "positional" ? "name" : arg.name;
842
+ switch (key) {
843
+ case "name": {
844
+ const expression = arg.expression;
845
+ name = expression === void 0 ? void 0 : StringLiteralExprAst.cast(expression.syntax)?.value();
846
+ if (name === void 0) invalid("name must be a string", arg.span);
847
+ break;
848
+ }
849
+ case "fields":
850
+ fields = identifierList(arg);
851
+ if (fields === void 0) invalid("fields must be a list of field names", arg.span);
852
+ break;
853
+ case "references":
854
+ references = identifierList(arg);
855
+ if (references === void 0) invalid("references must be a list of field names", arg.span);
856
+ break;
857
+ case "onDelete":
858
+ case "onUpdate":
859
+ case "map":
860
+ rejected = true;
861
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_REFERENTIAL_ACTION_UNSUPPORTED", key === "map" ? `${label}: @relation argument "map" is not supported; it names a foreign key constraint, and MongoDB has none. Remove "map"; the Prisma 6 app has no foreign key on MongoDB either, so nothing changes there.` : `${label}: @relation argument "${key}" is not supported; Prisma 8 enforces no referential actions on MongoDB. ${referentialActionRemoval(key, arg.value, sides)} Handle related documents in application code, then remove "${key}".`, sourceId, arg.span));
862
+ break;
863
+ default: invalid(`argument "${key ?? ""}" is not supported`, arg.span);
864
+ }
865
+ }
866
+ return rejected ? void 0 : {
867
+ name,
868
+ fields,
869
+ references
870
+ };
871
+ }
872
+ function ignoredFieldReferenced(modelName, fieldNames, usedBy, sourceId, span) {
873
+ const one = fieldNames.length === 1;
874
+ const fields = fieldNames.map((name) => `"${modelName}.${name}"`).join(", ");
875
+ const removal = usedBy.kind === "index" ? "which makes Prisma 6 `db push` drop the index" : "which removes that relation from the Prisma 6 client";
876
+ return prisma6Diagnostic("PSL.PRISMA6_MONGO_IGNORED_FIELD_REFERENCED", `${one ? "Field" : "Fields"} ${fields} ${one ? "is" : "are"} marked @ignore, but ${usedBy.text} uses ${one ? "it" : "them"}. Remove @ignore from ${fields}, which adds ${one ? "it" : "them"} to the Prisma 6 client, or remove ${usedBy.text}, ${removal}.`, sourceId, span);
877
+ }
878
+ function readRelationFields(build, builds, out, diagnostics, namespaceId) {
879
+ const { symbol, sourceId, sources } = build.located;
880
+ for (const { field, relation } of build.relationFields) {
881
+ const label = `Relation field "${symbol.name}.${field.name}"`;
882
+ const reject = () => {
883
+ out.invalidFkPairings.push({
884
+ pairKey: fkRelationPairKey(symbol.name, field.typeName),
885
+ ...ifDefined("relationName", relation === void 0 ? void 0 : stringArgument(relation))
886
+ });
887
+ };
888
+ const args = relation === void 0 ? void 0 : readRelationArguments(relation, label, {
889
+ model: symbol.name,
890
+ target: field.typeName,
891
+ optional: field.optional
892
+ }, sourceId, diagnostics);
893
+ if (relation !== void 0 && args === void 0) {
894
+ reject();
895
+ continue;
896
+ }
897
+ const target = builds.get(field.typeName);
898
+ if (target === void 0) continue;
899
+ if (!(args?.fields !== void 0 || args?.references !== void 0)) {
900
+ out.backRelations.push({
901
+ modelName: symbol.name,
902
+ field,
903
+ targetModelName: field.typeName,
904
+ ...ifDefined("relationName", args?.name),
905
+ cardinality: field.list ? "1:N" : "1:1",
906
+ sources
907
+ });
908
+ continue;
909
+ }
910
+ if (field.list) {
911
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_LIST_RELATION_UNSUPPORTED", `${label} is a list relation that stores its keys in a list field (a many-to-many relation on MongoDB), which Prisma 8 does not support yet. Remove the relation fields from the schema this contract source reads and keep the key list as a plain field. The Prisma 6 client then loses the relation fields too, so Prisma 6 code that reads or writes the relation through them (\`include\`, \`connect\`) has to use the key list instead.`, sourceId, relation?.span ?? field.span));
912
+ reject();
913
+ continue;
914
+ }
915
+ const localNames = args?.fields ?? [];
916
+ const targetNames = args?.references ?? [];
917
+ const ignoredLocal = localNames.filter((name) => build.ignoredFields.has(name));
918
+ if (ignoredLocal.length > 0) {
919
+ diagnostics.push(ignoredFieldReferenced(symbol.name, ignoredLocal, {
920
+ kind: "relation",
921
+ text: `relation field "${symbol.name}.${field.name}"`
922
+ }, sourceId, relation?.span ?? field.span));
923
+ reject();
924
+ continue;
925
+ }
926
+ const ignoredTarget = targetNames.filter((name) => target.ignoredFields.has(name));
927
+ if (ignoredTarget.length > 0) {
928
+ diagnostics.push(ignoredFieldReferenced(target.located.symbol.name, ignoredTarget, {
929
+ kind: "relation",
930
+ text: `relation field "${symbol.name}.${field.name}"`
931
+ }, sourceId, relation?.span ?? field.span));
932
+ reject();
933
+ continue;
934
+ }
935
+ const localFields = localNames.map((name) => build.storedNames.get(name));
936
+ const targetFields = targetNames.map((name) => target.storedNames.get(name));
937
+ if (localFields.some((name) => name === void 0) || targetFields.some((name) => name === void 0) || localNames.length !== targetNames.length || localNames.length === 0) {
938
+ diagnostics.push({
939
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
940
+ message: `${label}: @relation fields and references must name the same number of scalar fields of "${symbol.name}" and "${field.typeName}".`,
941
+ sourceId,
942
+ span: relation?.span ?? field.span
943
+ });
944
+ reject();
945
+ continue;
946
+ }
947
+ if (resolveToOneRelationNullable({
948
+ declaredNullable: field.optional,
949
+ localFieldNullability: localNames.map((name) => symbol.fields[name]?.optional === true),
950
+ ownsReference: true
951
+ }).contradiction !== void 0) {
952
+ diagnostics.push({
953
+ code: "PSL_RELATION_NULLABILITY_MISMATCH",
954
+ message: field.optional ? `${label} is optional but every field in @relation(fields: [...]) is required. Make one of those fields optional with "?" or remove "?" from "${field.name}".` : `${label} is required but a field in @relation(fields: [...]) is optional. Add "?" to "${field.name}" or make those fields required.`,
955
+ sourceId,
956
+ span: field.span
957
+ });
958
+ reject();
959
+ continue;
960
+ }
961
+ build.relations[field.name] = {
962
+ to: crossRef(field.typeName, namespaceId),
963
+ cardinality: "N:1",
964
+ nullable: field.optional,
965
+ on: {
966
+ localFields: localNames,
967
+ targetFields: targetNames
968
+ }
969
+ };
970
+ out.foreignKeys.push({
971
+ declaringModel: symbol.name,
972
+ targetModel: field.typeName,
973
+ ...ifDefined("relationName", args?.name),
974
+ localFields: localNames,
975
+ targetFields: targetNames
976
+ });
977
+ }
978
+ }
979
+ function buildIndexes(build, diagnostics) {
980
+ const { symbol, sourceId } = build.located;
981
+ const indexes = [];
982
+ let textIndexes = 0;
983
+ const keyFor = (field, text) => ({
984
+ field: build.storedNames.get(field.name) ?? field.name,
985
+ direction: field.direction ?? (text ? "text" : 1)
986
+ });
987
+ for (const attribute of [...build.uniqueFields, ...build.modelIndexes]) {
988
+ const names = attribute.fields.map((field) => field.name);
989
+ const usedBy = {
990
+ kind: "index",
991
+ text: build.uniqueFields.includes(attribute) ? `@unique on field "${symbol.name}.${attribute.fields[0]?.name ?? ""}"` : `@@${attribute.kind} on model "${symbol.name}"`
992
+ };
993
+ const ignored = names.filter((name) => build.ignoredFields.has(name));
994
+ if (ignored.length > 0) {
995
+ diagnostics.push(ignoredFieldReferenced(symbol.name, ignored, usedBy, sourceId, attribute.span));
996
+ continue;
997
+ }
998
+ if (names.some((name) => build.rejectedFields.has(name))) continue;
999
+ const unknown = names.find((name) => !build.storedNames.has(name));
1000
+ if (unknown !== void 0) {
1001
+ diagnostics.push({
1002
+ code: "PSL_INDEX_FIELD_NOT_FOUND",
1003
+ message: `Index on model "${symbol.name}" references unknown field "${unknown}"`,
1004
+ sourceId,
1005
+ span: attribute.span
1006
+ });
1007
+ continue;
1008
+ }
1009
+ if (attribute.kind === "fulltext") {
1010
+ textIndexes++;
1011
+ if (textIndexes > 1) {
1012
+ diagnostics.push(prisma6Diagnostic("PSL.PRISMA6_MONGO_TEXT_INDEX_LIMIT", `Model "${symbol.name}" has more than one @@fulltext; MongoDB allows one text index per collection. Merge the fields into one @@fulltext.`, sourceId, attribute.span));
1013
+ continue;
1014
+ }
1015
+ }
1016
+ indexes.push(new MongoIndex({
1017
+ keys: attribute.fields.map((field) => keyFor(field, attribute.kind === "fulltext")),
1018
+ ...attribute.kind === "unique" ? { unique: true } : {}
1019
+ }));
1020
+ }
1021
+ return indexes;
1022
+ }
1023
+ function assembleContract(input) {
1024
+ const target = input.binding.target.targetId;
1025
+ const targetFamily = input.binding.target.familyId;
1026
+ const builtEnums = Object.fromEntries(input.enums);
1027
+ const collections = {};
1028
+ for (const [name, collection] of Object.entries(input.collections)) collections[name] = collection.indexes.length > 0 ? { indexes: collection.indexes } : {};
1029
+ const storage = buildMongoStorage({
1030
+ collections,
1031
+ valueSets: mongoValueSetsOf(builtEnums)
1032
+ });
1033
+ const models = {};
1034
+ for (const [modelName, build] of input.builds) models[modelName] = {
1035
+ fields: build.fields,
1036
+ relations: build.relations,
1037
+ storage: {
1038
+ collection: build.collection,
1039
+ fields: Object.fromEntries(Object.keys(build.fields).map((name) => [name, { field: build.storedNames.get(name) ?? name }]))
1040
+ }
1041
+ };
1042
+ const capabilities = {};
1043
+ const execution = buildExecutionSection({
1044
+ target,
1045
+ targetFamily,
1046
+ defaults: input.executionDefaults
1047
+ });
1048
+ return {
1049
+ targetFamily,
1050
+ target,
1051
+ roots: input.roots,
1052
+ domain: { namespaces: { [input.namespaceId]: {
1053
+ models: blindCast(models),
1054
+ ...Object.keys(input.valueObjects).length > 0 ? { valueObjects: input.valueObjects } : {},
1055
+ ...Object.keys(builtEnums).length > 0 ? { enum: builtEnums } : {}
1056
+ } } },
1057
+ storage,
1058
+ extensions: {},
1059
+ capabilities,
1060
+ profileHash: computeProfileHash({
1061
+ target,
1062
+ targetFamily,
1063
+ capabilities
1064
+ }),
1065
+ meta: {},
1066
+ ...execution !== void 0 ? { execution } : {}
1067
+ };
1068
+ }
1069
+ function mergedSources(documents) {
1070
+ const [first, ...rest] = documents.map((document) => document.sources);
1071
+ if (first === void 0) throw new InternalError("A Prisma 6 schema has at least one document");
1072
+ return first.merge(...rest);
1073
+ }
1074
+ function defaultOutputFromSchemaPath(schemaPath) {
1075
+ return join(dirname(schemaPath), "contract.json");
1076
+ }
1077
+ function mapParseDiagnostics(diagnostics, sourceFile, sourceId) {
1078
+ return diagnostics.map((diagnostic) => ({
1079
+ code: diagnostic.code,
1080
+ message: diagnostic.message,
1081
+ sourceId,
1082
+ span: sourceFile.rangeToPslSpan(diagnostic.range)
1083
+ }));
1084
+ }
1085
+ /**
1086
+ * The files a Prisma 6 schema input names: the file itself, or every regular `.prisma` file under the directory, nested directories and symbolic links included, as Prisma 6 reads a schema directory. Sorted by path so duplicate detection blames the later file deterministically.
1087
+ */
1088
+ async function listSchemaFiles(absolutePath, displayPath) {
1089
+ if (!(await stat(absolutePath)).isDirectory()) return [{
1090
+ sourceId: displayPath,
1091
+ absolutePath
1092
+ }];
1093
+ const entries = await readdir(absolutePath, { recursive: true });
1094
+ const files = [];
1095
+ for (const entry of entries.filter((name) => extname(name) === ".prisma").map((name) => normalize(name)).sort()) {
1096
+ const entryPath = join(absolutePath, entry);
1097
+ if ((await stat(entryPath)).isFile()) files.push({
1098
+ sourceId: join(displayPath, entry),
1099
+ absolutePath: entryPath
1100
+ });
1101
+ }
1102
+ return files;
1103
+ }
1104
+ function isMissingPath(error) {
1105
+ return error instanceof Error && Reflect.get(error, "code") === "ENOENT";
1106
+ }
1107
+ function readFailure(schemaPath, message, meta) {
1108
+ return notOk({
1109
+ summary: `Failed to read Prisma 6 schema at "${schemaPath}"`,
1110
+ diagnostics: [prisma6Diagnostic("PSL.PRISMA6_MONGO_SCHEMA_READ_FAILED", message, schemaPath, void 0)],
1111
+ meta
1112
+ });
1113
+ }
1114
+ /**
1115
+ * A `ContractConfig` that reads a Prisma 6 MongoDB `schema.prisma` (a file, or a directory of `.prisma` files) as the contract source.
1116
+ */
1117
+ function prisma6Contract(schemaPath, options) {
1118
+ const parserOptions = { grammar: "prisma-7" };
1119
+ return {
1120
+ source: {
1121
+ format: "psl",
1122
+ inputs: [schemaPath],
1123
+ parserOptions,
1124
+ async load(context) {
1125
+ const [absolutePath] = context.resolvedInputs;
1126
+ if (absolutePath === void 0) throw new InternalError("prisma6Contract: context.resolvedInputs is empty. The CLI config loader should populate it from source.inputs.");
1127
+ let files;
1128
+ try {
1129
+ files = await listSchemaFiles(absolutePath, schemaPath);
1130
+ } catch (error) {
1131
+ const cause = String(error);
1132
+ return readFailure(schemaPath, isMissingPath(error) ? `There is no file or directory at "${schemaPath}". Fix the path passed to prisma6Schema() in prisma.config.ts.` : cause, {
1133
+ schemaPath,
1134
+ absolutePath,
1135
+ cause
1136
+ });
1137
+ }
1138
+ if (files.length === 0) return readFailure(schemaPath, `The schema directory "${schemaPath}" contains no .prisma file.`, {
1139
+ schemaPath,
1140
+ absolutePath
1141
+ });
1142
+ const documents = [];
1143
+ const seedDiagnostics = [];
1144
+ for (const file of files) {
1145
+ let schema;
1146
+ try {
1147
+ schema = await readFile(file.absolutePath, "utf-8");
1148
+ } catch (error) {
1149
+ const message = String(error);
1150
+ return readFailure(file.sourceId, message, {
1151
+ schemaPath: file.sourceId,
1152
+ absoluteSchemaPath: file.absolutePath,
1153
+ cause: message
1154
+ });
1155
+ }
1156
+ const { document, sources, diagnostics } = parse(schema, file.sourceId, parserOptions);
1157
+ const sourceFile = sources.sourceFileFor(document.syntax);
1158
+ seedDiagnostics.push(...mapParseDiagnostics(diagnostics, sourceFile, file.sourceId));
1159
+ documents.push({
1160
+ document,
1161
+ sources,
1162
+ sourceFile,
1163
+ sourceId: file.sourceId
1164
+ });
1165
+ }
1166
+ let contract;
1167
+ try {
1168
+ const interpreted = interpretPrisma6Documents({
1169
+ documents,
1170
+ seedDiagnostics,
1171
+ binding: options.binding,
1172
+ generatorFunctions: context.generatorFunctions,
1173
+ authoringContributions: context.authoringContributions,
1174
+ codecLookup: context.codecLookup,
1175
+ dataTypes: context.dataTypes,
1176
+ defaultNamespaceId: context.defaultNamespaceId
1177
+ });
1178
+ if (!interpreted.ok) return interpreted;
1179
+ contract = applySpecifierDefaultControlPolicy(interpreted.value, options.defaultControlPolicy);
1180
+ validateContractDomain(contract);
1181
+ validateMongoStorage(blindCast(contract));
1182
+ } catch (error) {
1183
+ if (!isStructuredError(error)) throw error;
1184
+ return notOk({
1185
+ summary: "Prisma 6 MongoDB schema interpretation failed",
1186
+ diagnostics: [prisma6Diagnostic("PSL.PRISMA6_MONGO_CONTRACT_INVALID", `This schema gives a contract that Prisma 8 rejects, and the Prisma 6 MongoDB 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)],
1187
+ meta: {
1188
+ schemaPath,
1189
+ code: error.code
1190
+ }
1191
+ });
1192
+ }
1193
+ return ok(contract);
1194
+ }
1195
+ },
1196
+ output: options.output ?? defaultOutputFromSchemaPath(schemaPath)
1197
+ };
1198
+ }
1199
+ //#endregion
1200
+ export { prisma6Contract };
1201
+
1202
+ //# sourceMappingURL=contract-prisma6__provider.mjs.map