@prisma-next/mongo-contract-psl 0.5.0-dev.7 → 0.5.0-dev.70

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.
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.mts","names":[],"sources":["../../src/provider.ts"],"sourcesContent":[],"mappings":";;;UAOiB,oBAAA;;AAAjB;AAIgB,iBAAA,aAAA,CAA4C,UAAA,EAAA,MAAuB,EAAA,OAAc,CAAd,EAAvB,oBAAqC,CAAA,EAAd,cAAc"}
1
+ {"version":3,"file":"provider.d.mts","names":[],"sources":["../../src/provider.ts"],"mappings":";;;UAOiB,oBAAA;EAAA,SACN,MAAA;AAAA;AAAA,iBAGK,aAAA,CAAc,UAAA,UAAoB,OAAA,GAAU,oBAAA,GAAuB,cAAA"}
@@ -1,9 +1,8 @@
1
- import { t as interpretPslDocumentToMongoContract } from "../interpreter-CWOjqYYA.mjs";
1
+ import { t as interpretPslDocumentToMongoContract } from "../interpreter-mbG5P270.mjs";
2
2
  import { notOk, ok } from "@prisma-next/utils/result";
3
3
  import { parsePslDocument } from "@prisma-next/psl-parser";
4
4
  import { readFile } from "node:fs/promises";
5
5
  import { ifDefined } from "@prisma-next/utils/defined";
6
-
7
6
  //#region src/provider.ts
8
7
  function mongoContract(schemaPath, options) {
9
8
  return {
@@ -46,7 +45,7 @@ function mongoContract(schemaPath, options) {
46
45
  ...ifDefined("output", options?.output)
47
46
  };
48
47
  }
49
-
50
48
  //#endregion
51
49
  export { mongoContract };
50
+
52
51
  //# sourceMappingURL=provider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.mjs","names":["schema: string"],"sources":["../../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { interpretPslDocumentToMongoContract } from './interpreter';\n\nexport interface MongoContractOptions {\n readonly output?: string;\n}\n\nexport function mongoContract(schemaPath: string, options?: MongoContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'mongoContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n });\n\n const interpreted = interpretPslDocumentToMongoContract({\n document,\n scalarTypeDescriptors: context.scalarTypeDescriptors,\n codecLookup: context.codecLookup,\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(interpreted.value);\n },\n },\n ...ifDefined('output', options?.output),\n };\n}\n"],"mappings":";;;;;;;AAWA,SAAgB,cAAc,YAAoB,SAAgD;AAChG,QAAO;EACL,QAAQ;GACN,QAAQ,CAAC,WAAW;GACpB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;AACrC,QAAI,uBAAuB,OACzB,OAAM,IAAI,MACR,kIACD;IAEH,IAAIA;AACJ,QAAI;AACF,cAAS,MAAM,SAAS,oBAAoB,QAAQ;aAC7C,OAAO;KACd,MAAM,UAAU,OAAO,MAAM;AAC7B,YAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;OACX,CACF;MACD,MAAM;OAAE;OAAY;OAAoB,OAAO;OAAS;MACzD,CAAC;;IAQJ,MAAM,cAAc,oCAAoC;KACtD,UANe,iBAAiB;MAChC;MACA,UAAU;MACX,CAAC;KAIA,uBAAuB,QAAQ;KAC/B,aAAa,QAAQ;KACtB,CAAC;AACF,QAAI,CAAC,YAAY,GACf,QAAO;AAGT,WAAO,GAAG,YAAY,MAAM;;GAE/B;EACD,GAAG,UAAU,UAAU,SAAS,OAAO;EACxC"}
1
+ {"version":3,"file":"provider.mjs","names":[],"sources":["../../src/provider.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { ContractConfig } from '@prisma-next/config/config-types';\nimport { parsePslDocument } from '@prisma-next/psl-parser';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { interpretPslDocumentToMongoContract } from './interpreter';\n\nexport interface MongoContractOptions {\n readonly output?: string;\n}\n\nexport function mongoContract(schemaPath: string, options?: MongoContractOptions): ContractConfig {\n return {\n source: {\n inputs: [schemaPath],\n load: async (context) => {\n const [absoluteSchemaPath] = context.resolvedInputs;\n if (absoluteSchemaPath === undefined) {\n throw new Error(\n 'mongoContract: context.resolvedInputs is empty. The CLI config loader should populate it positional-matched with source.inputs.',\n );\n }\n let schema: string;\n try {\n schema = await readFile(absoluteSchemaPath, 'utf-8');\n } catch (error) {\n const message = String(error);\n return notOk({\n summary: `Failed to read Prisma schema at \"${schemaPath}\"`,\n diagnostics: [\n {\n code: 'PSL_SCHEMA_READ_FAILED',\n message,\n sourceId: schemaPath,\n },\n ],\n meta: { schemaPath, absoluteSchemaPath, cause: message },\n });\n }\n\n const document = parsePslDocument({\n schema,\n sourceId: schemaPath,\n });\n\n const interpreted = interpretPslDocumentToMongoContract({\n document,\n scalarTypeDescriptors: context.scalarTypeDescriptors,\n codecLookup: context.codecLookup,\n });\n if (!interpreted.ok) {\n return interpreted;\n }\n\n return ok(interpreted.value);\n },\n },\n ...ifDefined('output', options?.output),\n };\n}\n"],"mappings":";;;;;;AAWA,SAAgB,cAAc,YAAoB,SAAgD;CAChG,OAAO;EACL,QAAQ;GACN,QAAQ,CAAC,WAAW;GACpB,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,sBAAsB,QAAQ;IACrC,IAAI,uBAAuB,KAAA,GACzB,MAAM,IAAI,MACR,kIACD;IAEH,IAAI;IACJ,IAAI;KACF,SAAS,MAAM,SAAS,oBAAoB,QAAQ;aAC7C,OAAO;KACd,MAAM,UAAU,OAAO,MAAM;KAC7B,OAAO,MAAM;MACX,SAAS,oCAAoC,WAAW;MACxD,aAAa,CACX;OACE,MAAM;OACN;OACA,UAAU;OACX,CACF;MACD,MAAM;OAAE;OAAY;OAAoB,OAAO;OAAS;MACzD,CAAC;;IAQJ,MAAM,cAAc,oCAAoC;KACtD,UANe,iBAAiB;MAChC;MACA,UAAU;MACX,CAGS;KACR,uBAAuB,QAAQ;KAC/B,aAAa,QAAQ;KACtB,CAAC;IACF,IAAI,CAAC,YAAY,IACf,OAAO;IAGT,OAAO,GAAG,YAAY,MAAM;;GAE/B;EACD,GAAG,UAAU,UAAU,SAAS,OAAO;EACxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/interpreter.ts"],"sourcesContent":[],"mappings":";;;;;;;UA2BiB,wCAAA;qBACI;EADJ,SAAA,qBAAA,EAEiB,WAFuB,CAAA,MAAA,EAAA,MAAA,CAAA;EACpC,SAAA,WAAA,CAAA,EAEI,WAFJ;;AAEI,iBA2oBT,mCAAA,CA3oBS,KAAA,EA4oBhB,wCA5oBgB,CAAA,EA6oBtB,MA7oBsB,CA6oBf,QA7oBe,EA6oBL,yBA7oBK,CAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/interpreter.ts"],"mappings":";;;;;;;UA+BiB,wCAAA;EAAA,SACN,QAAA,EAAU,sBAAA;EAAA,SACV,qBAAA,EAAuB,WAAA;EAAA,SACvB,WAAA,GAAc,WAAA;AAAA;AAAA,iBAsvBT,mCAAA,CACd,KAAA,EAAO,wCAAA,GACN,MAAA,CAAO,QAAA,EAAU,yBAAA"}
package/dist/index.mjs CHANGED
@@ -1,3 +1,2 @@
1
- import { t as interpretPslDocumentToMongoContract } from "./interpreter-CWOjqYYA.mjs";
2
-
3
- export { interpretPslDocumentToMongoContract };
1
+ import { t as interpretPslDocumentToMongoContract } from "./interpreter-mbG5P270.mjs";
2
+ export { interpretPslDocumentToMongoContract };
@@ -1,10 +1,10 @@
1
1
  import { computeProfileHash, computeStorageHash } from "@prisma-next/contract/hashing";
2
+ import { applyPolymorphicScopeToMongoIndex } from "@prisma-next/mongo-contract";
2
3
  import { notOk, ok } from "@prisma-next/utils/result";
3
4
  import { getPositionalArgument, parseQuotedStringLiteral } from "@prisma-next/psl-parser";
4
-
5
5
  //#region src/derive-json-schema.ts
6
6
  function resolveBsonType(codecId, codecLookup) {
7
- return (codecLookup?.get(codecId))?.targetTypes[0];
7
+ return codecLookup?.targetTypesFor(codecId)?.[0];
8
8
  }
9
9
  function fieldToBsonSchema(field, valueObjects, codecLookup) {
10
10
  if (field.type.kind === "scalar") {
@@ -84,7 +84,6 @@ function derivePolymorphicJsonSchema(baseFields, discriminatorField, variants, v
84
84
  validationAction: "error"
85
85
  };
86
86
  }
87
-
88
87
  //#endregion
89
88
  //#region src/psl-helpers.ts
90
89
  function getNamedArgument(attr, name) {
@@ -170,7 +169,6 @@ function stripQuotes(value) {
170
169
  if (value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
171
170
  return value;
172
171
  }
173
-
174
172
  //#endregion
175
173
  //#region src/interpreter.ts
176
174
  function fkRelationPairKey(declaringModel, targetModel) {
@@ -254,7 +252,7 @@ function collectPolymorphismDeclarations(document, sourceId, diagnostics) {
254
252
  };
255
253
  }
256
254
  function resolvePolymorphism(input) {
257
- const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document } = input;
255
+ const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document, indexSpans, modelIndexesByName } = input;
258
256
  let patched = input.models;
259
257
  let roots = input.roots;
260
258
  let collections = input.collections;
@@ -353,31 +351,59 @@ function resolvePolymorphism(input) {
353
351
  [variantCollectionName]: baseDecl.baseName
354
352
  };
355
353
  else roots = Object.fromEntries(Object.entries(roots).filter(([key]) => key !== variantCollectionName));
356
- const variantIndexes = collections[variantCollectionName]?.["indexes"] ?? [];
354
+ const variantOwnIndexes = modelIndexesByName.get(variantName) ?? [];
357
355
  const baseColl = collections[baseCollection];
356
+ const discriminatorField = patched[baseDecl.baseName]?.discriminator?.field;
357
+ const scopedVariantIndexes = [];
358
+ if (discriminatorField) for (const idx of variantOwnIndexes) {
359
+ const result = applyPolymorphicScopeToMongoIndex(idx, {
360
+ discriminatorField,
361
+ discriminatorValue: baseDecl.value
362
+ });
363
+ if (result.kind === "conflict") {
364
+ const span = indexSpans.get(idx) ?? baseDecl.span;
365
+ diagnostics.push({
366
+ code: "PSL_INVALID_INDEX",
367
+ message: `Variant "${variantName}" index conflicts with discriminator scope: ${result.reason}`,
368
+ sourceId,
369
+ span
370
+ });
371
+ continue;
372
+ }
373
+ if (result.index !== idx) indexSpans.set(result.index, indexSpans.get(idx) ?? baseDecl.span);
374
+ scopedVariantIndexes.push(result.index);
375
+ }
376
+ else scopedVariantIndexes.push(...variantOwnIndexes);
358
377
  if (variantCollectionName !== baseCollection) {
359
378
  const filtered = Object.fromEntries(Object.entries(collections).filter(([key]) => key !== variantCollectionName));
360
- if (variantIndexes.length > 0 && baseColl) {
379
+ if (scopedVariantIndexes.length > 0 && baseColl) {
361
380
  const baseIndexes = baseColl["indexes"] ?? [];
362
381
  collections = {
363
382
  ...filtered,
364
383
  [baseCollection]: {
365
384
  ...baseColl,
366
- indexes: [...baseIndexes, ...variantIndexes]
385
+ indexes: [...baseIndexes, ...scopedVariantIndexes]
367
386
  }
368
387
  };
369
388
  } else collections = filtered;
370
- } else if (variantIndexes.length > 0 && baseColl) {
371
- const baseIndexes = baseColl["indexes"] ?? [];
372
- const mergedIndexes = [...baseIndexes];
373
- for (const idx of variantIndexes) if (!baseIndexes.some((existing) => JSON.stringify(existing) === JSON.stringify(idx))) mergedIndexes.push(idx);
374
- if (mergedIndexes.length > baseIndexes.length) collections = {
375
- ...collections,
376
- [baseCollection]: {
377
- ...baseColl,
378
- indexes: mergedIndexes
379
- }
380
- };
389
+ } else if (baseColl) {
390
+ const existingIndexes = baseColl["indexes"] ?? [];
391
+ const variantIndexSet = new Set(variantOwnIndexes);
392
+ const withoutUnscopedVariants = existingIndexes.filter((idx) => !variantIndexSet.has(idx));
393
+ const mergedIndexes = [...withoutUnscopedVariants];
394
+ for (const idx of scopedVariantIndexes) {
395
+ const idxKey = canonicalJson(idx);
396
+ if (!withoutUnscopedVariants.some((existing) => canonicalJson(existing) === idxKey)) mergedIndexes.push(idx);
397
+ }
398
+ if (mergedIndexes.length !== existingIndexes.length || mergedIndexes.some((idx, i) => idx !== existingIndexes[i])) {
399
+ const next = { ...baseColl };
400
+ if (mergedIndexes.length > 0) next["indexes"] = mergedIndexes;
401
+ else delete next["indexes"];
402
+ collections = {
403
+ ...collections,
404
+ [baseCollection]: next
405
+ };
406
+ }
381
407
  }
382
408
  }
383
409
  return {
@@ -387,6 +413,11 @@ function resolvePolymorphism(input) {
387
413
  diagnostics
388
414
  };
389
415
  }
416
+ function canonicalJson(value) {
417
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
418
+ if (value && typeof value === "object") return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
419
+ return JSON.stringify(value);
420
+ }
390
421
  function parseIndexDirection(raw) {
391
422
  if (!raw) return 1;
392
423
  const stripped = raw.replace(/^["']/, "").replace(/["']$/, "");
@@ -452,20 +483,27 @@ function parseProjectionList(raw, value) {
452
483
  for (const f of fields) result[f] = value;
453
484
  return result;
454
485
  }
455
- function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics) {
486
+ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics, indexSpans) {
456
487
  const indexes = [];
457
488
  let textIndexCount = 0;
489
+ const indexableFieldNames = /* @__PURE__ */ new Set();
490
+ for (const f of pslModel.fields) {
491
+ if (modelNames.has(f.typeName)) continue;
492
+ indexableFieldNames.add(f.name);
493
+ }
458
494
  for (const field of pslModel.fields) {
459
495
  if (modelNames.has(field.typeName)) continue;
460
- if (!getAttribute(field.attributes, "unique")) continue;
461
- const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;
462
- indexes.push({
496
+ const uniqueAttr = getAttribute(field.attributes, "unique");
497
+ if (!uniqueAttr) continue;
498
+ const fieldUniqueIndex = {
463
499
  keys: [{
464
- field: mappedName,
500
+ field: fieldMappings.pslNameToMapped.get(field.name) ?? field.name,
465
501
  direction: 1
466
502
  }],
467
503
  unique: true
468
- });
504
+ };
505
+ indexes.push(fieldUniqueIndex);
506
+ indexSpans.set(fieldUniqueIndex, uniqueAttr.span);
469
507
  }
470
508
  for (const attr of pslModel.attributes) {
471
509
  const isIndex = attr.name === "index";
@@ -540,6 +578,28 @@ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnosti
540
578
  });
541
579
  continue;
542
580
  }
581
+ let missingField;
582
+ for (const pf of parsedFields) {
583
+ let fieldNameForLookup;
584
+ if (pf.isWildcard) {
585
+ const wildcardMatch = pf.name.match(/^(.+)\.\$\*\*$/);
586
+ fieldNameForLookup = wildcardMatch ? wildcardMatch[1] : void 0;
587
+ } else fieldNameForLookup = pf.name;
588
+ if (fieldNameForLookup === void 0 || fieldNameForLookup.length === 0) continue;
589
+ if (!indexableFieldNames.has(fieldNameForLookup)) {
590
+ missingField = fieldNameForLookup;
591
+ break;
592
+ }
593
+ }
594
+ if (missingField !== void 0) {
595
+ diagnostics.push({
596
+ code: "PSL_INDEX_FIELD_NOT_FOUND",
597
+ message: `Index on model "${pslModel.name}" references unknown field "${missingField}"`,
598
+ sourceId,
599
+ span: attr.span
600
+ });
601
+ continue;
602
+ }
543
603
  const keys = parsedFields.map((pf) => {
544
604
  return {
545
605
  field: pf.isWildcard ? pf.name.replace(/^(.+)\.\$\*\*$/, (_, prefix) => {
@@ -614,6 +674,7 @@ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnosti
614
674
  ...language_override != null && { language_override }
615
675
  };
616
676
  indexes.push(index);
677
+ indexSpans.set(index, attr.span);
617
678
  }
618
679
  return indexes;
619
680
  }
@@ -625,7 +686,7 @@ function resolveFieldCodecId(field, scalarTypeDescriptors) {
625
686
  }
626
687
  function resolveNonRelationField(field, ownerName, compositeTypeNames, scalarTypeDescriptors, sourceId, diagnostics) {
627
688
  if (compositeTypeNames.has(field.typeName)) {
628
- const result$1 = {
689
+ const result = {
629
690
  type: {
630
691
  kind: "valueObject",
631
692
  name: field.typeName
@@ -633,9 +694,9 @@ function resolveNonRelationField(field, ownerName, compositeTypeNames, scalarTyp
633
694
  nullable: field.optional
634
695
  };
635
696
  return field.list ? {
636
- ...result$1,
697
+ ...result,
637
698
  many: true
638
- } : result$1;
699
+ } : result;
639
700
  }
640
701
  const codecId = resolveFieldCodecId(field, scalarTypeDescriptors);
641
702
  if (!codecId) {
@@ -669,6 +730,8 @@ function interpretPslDocumentToMongoContract(input) {
669
730
  const collections = {};
670
731
  const roots = {};
671
732
  const allFkRelations = [];
733
+ const indexSpans = /* @__PURE__ */ new Map();
734
+ const modelIndexesByName = /* @__PURE__ */ new Map();
672
735
  const backrelationCandidates = [];
673
736
  for (const pslModel of document.ast.models) {
674
737
  const collectionName = resolveCollectionName(pslModel);
@@ -729,7 +792,8 @@ function interpretPslDocumentToMongoContract(input) {
729
792
  relations,
730
793
  storage: { collection: collectionName }
731
794
  };
732
- const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);
795
+ const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics, indexSpans);
796
+ modelIndexesByName.set(pslModel.name, modelIndexes);
733
797
  const existingColl = collections[collectionName];
734
798
  if (existingColl && modelIndexes.length > 0) collections[collectionName] = { indexes: [...existingColl["indexes"] ?? [], ...modelIndexes] };
735
799
  else if (!existingColl) collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};
@@ -796,6 +860,8 @@ function interpretPslDocumentToMongoContract(input) {
796
860
  discriminatorDeclarations,
797
861
  baseDeclarations,
798
862
  modelNames,
863
+ indexSpans,
864
+ modelIndexesByName,
799
865
  sourceId
800
866
  });
801
867
  if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) return notOk({
@@ -845,7 +911,7 @@ function interpretPslDocumentToMongoContract(input) {
845
911
  meta: {}
846
912
  });
847
913
  }
848
-
849
914
  //#endregion
850
915
  export { interpretPslDocumentToMongoContract as t };
851
- //# sourceMappingURL=interpreter-CWOjqYYA.mjs.map
916
+
917
+ //# sourceMappingURL=interpreter-mbG5P270.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter-mbG5P270.mjs","names":[],"sources":["../src/derive-json-schema.ts","../src/psl-helpers.ts","../src/interpreter.ts"],"sourcesContent":["import type { ContractField, ContractValueObject } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { MongoStorageValidator } from '@prisma-next/mongo-contract';\n\nfunction resolveBsonType(\n codecId: string,\n codecLookup: CodecLookup | undefined,\n): string | undefined {\n return codecLookup?.targetTypesFor(codecId)?.[0];\n}\n\nfunction fieldToBsonSchema(\n field: ContractField,\n valueObjects: Record<string, ContractValueObject> | undefined,\n codecLookup: CodecLookup | undefined,\n): Record<string, unknown> | undefined {\n if (field.type.kind === 'scalar') {\n const bsonType = resolveBsonType(field.type.codecId, codecLookup);\n if (!bsonType) return undefined;\n\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: { bsonType } };\n }\n\n if (field.nullable) {\n return { bsonType: ['null', bsonType] };\n }\n\n return { bsonType };\n }\n\n if (field.type.kind === 'valueObject') {\n const vo = valueObjects?.[field.type.name];\n if (!vo) return undefined;\n const voSchema = deriveObjectSchema(vo.fields, valueObjects, codecLookup);\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: voSchema };\n }\n if (field.nullable) {\n return { oneOf: [{ bsonType: 'null' }, voSchema] };\n }\n return voSchema;\n }\n\n return undefined;\n}\n\nfunction deriveObjectSchema(\n fields: Record<string, ContractField>,\n valueObjects: Record<string, ContractValueObject> | undefined,\n codecLookup: CodecLookup | undefined,\n): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [fieldName, field] of Object.entries(fields)) {\n const schema = fieldToBsonSchema(field, valueObjects, codecLookup);\n if (schema) {\n properties[fieldName] = schema;\n if (!field.nullable) {\n required.push(fieldName);\n }\n }\n }\n\n const result: Record<string, unknown> = {\n bsonType: 'object',\n properties,\n };\n if (required.length > 0) {\n result['required'] = required.sort();\n }\n return result;\n}\n\nexport function deriveJsonSchema(\n fields: Record<string, ContractField>,\n valueObjects?: Record<string, ContractValueObject>,\n codecLookup?: CodecLookup,\n): MongoStorageValidator {\n return {\n jsonSchema: deriveObjectSchema(fields, valueObjects, codecLookup),\n validationLevel: 'strict',\n validationAction: 'error',\n };\n}\n\nexport interface PolymorphicVariant {\n readonly discriminatorValue: string;\n readonly fields: Record<string, ContractField>;\n}\n\nexport function derivePolymorphicJsonSchema(\n baseFields: Record<string, ContractField>,\n discriminatorField: string,\n variants: readonly PolymorphicVariant[],\n valueObjects?: Record<string, ContractValueObject>,\n codecLookup?: CodecLookup,\n): MongoStorageValidator {\n const baseSchema = deriveObjectSchema(baseFields, valueObjects, codecLookup);\n\n const oneOf: Record<string, unknown>[] = [];\n for (const variant of variants) {\n const variantOnlyFields: Record<string, ContractField> = {};\n for (const [name, field] of Object.entries(variant.fields)) {\n if (!(name in baseFields)) {\n variantOnlyFields[name] = field;\n }\n }\n\n const entry: Record<string, unknown> = {\n properties: {\n [discriminatorField]: { enum: [variant.discriminatorValue] },\n },\n };\n\n const variantProperties: Record<string, unknown> = {};\n const variantRequired: string[] = [discriminatorField];\n for (const [name, field] of Object.entries(variantOnlyFields)) {\n const schema = fieldToBsonSchema(field, valueObjects, codecLookup);\n if (schema) {\n variantProperties[name] = schema;\n if (!field.nullable) {\n variantRequired.push(name);\n }\n }\n }\n\n if (Object.keys(variantProperties).length > 0) {\n (entry['properties'] as Record<string, unknown>) = {\n ...(entry['properties'] as Record<string, unknown>),\n ...variantProperties,\n };\n }\n entry['required'] = variantRequired.sort();\n\n oneOf.push(entry);\n }\n\n const jsonSchema = { ...baseSchema };\n if (oneOf.length > 0) {\n jsonSchema['oneOf'] = oneOf;\n }\n\n return {\n jsonSchema,\n validationLevel: 'strict',\n validationAction: 'error',\n };\n}\n","import type { PslAttribute, PslAttributeArgument } from '@prisma-next/psl-parser';\nimport { getPositionalArgument, parseQuotedStringLiteral } from '@prisma-next/psl-parser';\n\nexport { getPositionalArgument, parseQuotedStringLiteral };\n\nexport function getNamedArgument(attr: PslAttribute, name: string): string | undefined {\n const arg = attr.args.find((a) => a.kind === 'named' && a.name === name);\n return arg?.value;\n}\n\nexport function parseFieldList(value: string): readonly string[] {\n const inner = value.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return [];\n return splitTopLevel(inner).map((s) => s.trim());\n}\n\nexport interface ParsedIndexField {\n readonly name: string;\n readonly isWildcard: boolean;\n readonly direction?: number;\n}\n\nexport function parseIndexFieldList(value: string): readonly ParsedIndexField[] {\n const segments = parseFieldList(value);\n return segments.map(parseIndexFieldSegment);\n}\n\nfunction parseIndexFieldSegment(segment: string): ParsedIndexField {\n const wildcardMatch = segment.match(/^wildcard\\(\\s*(.*?)\\s*\\)$/);\n if (wildcardMatch) {\n const scope = wildcardMatch[1] ?? '';\n return {\n name: scope.length > 0 ? `${scope}.$**` : '$**',\n isWildcard: true,\n };\n }\n\n const modifierMatch = segment.match(/^(\\w+)\\(\\s*sort:\\s*(\\w+)\\s*\\)$/);\n if (modifierMatch) {\n const fieldName = modifierMatch[1] ?? segment;\n const sortValue = modifierMatch[2];\n return {\n name: fieldName,\n isWildcard: false,\n direction: sortValue === 'Desc' ? -1 : 1,\n };\n }\n\n return { name: segment, isWildcard: false };\n}\n\nfunction splitTopLevel(input: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '(' || ch === '[' || ch === '{') depth++;\n else if (ch === ')' || ch === ']' || ch === '}') depth = Math.max(0, depth - 1);\n else if (ch === ',' && depth === 0) {\n parts.push(input.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(input.slice(start));\n return parts;\n}\n\nexport function lowerFirst(value: string): string {\n if (value.length === 0) return value;\n return value[0]?.toLowerCase() + value.slice(1);\n}\n\nexport function getAttribute(\n attributes: readonly PslAttribute[],\n name: string,\n): PslAttribute | undefined {\n return attributes.find((attr) => attr.name === name);\n}\n\nexport function getMapName(attributes: readonly PslAttribute[]): string | undefined {\n const mapAttr = getAttribute(attributes, 'map');\n if (!mapAttr) return undefined;\n const arg = mapAttr.args[0];\n if (!arg) return undefined;\n return stripQuotes(arg.value);\n}\n\nexport interface ParsedRelationAttribute {\n readonly relationName?: string;\n readonly fields?: readonly string[];\n readonly references?: readonly string[];\n}\n\nexport function parseRelationAttribute(\n attributes: readonly PslAttribute[],\n): ParsedRelationAttribute | undefined {\n const relationAttr = getAttribute(attributes, 'relation');\n if (!relationAttr) return undefined;\n\n let relationName: string | undefined;\n let fieldsArg: PslAttributeArgument | undefined;\n let referencesArg: PslAttributeArgument | undefined;\n\n for (const arg of relationAttr.args) {\n if (arg.kind === 'positional') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'name') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'fields') {\n fieldsArg = arg;\n } else if (arg.name === 'references') {\n referencesArg = arg;\n }\n }\n\n const fields = fieldsArg ? parseFieldList(fieldsArg.value) : undefined;\n const references = referencesArg ? parseFieldList(referencesArg.value) : undefined;\n\n return {\n ...(relationName !== undefined ? { relationName } : {}),\n ...(fields !== undefined ? { fields } : {}),\n ...(references !== undefined ? { references } : {}),\n };\n}\n\nfunction stripQuotes(value: string): string {\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n ContractSourceDiagnostic,\n ContractSourceDiagnostics,\n} from '@prisma-next/config/config-types';\nimport { computeProfileHash, computeStorageHash } from '@prisma-next/contract/hashing';\nimport type {\n Contract,\n ContractField,\n ContractReferenceRelation,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport {\n applyPolymorphicScopeToMongoIndex,\n type MongoIndexKeyDirection,\n type MongoStorageIndex,\n} from '@prisma-next/mongo-contract';\nimport type { ParsePslDocumentResult, PslField, PslModel, PslSpan } from '@prisma-next/psl-parser';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { deriveJsonSchema, derivePolymorphicJsonSchema } from './derive-json-schema';\nimport {\n getAttribute,\n getMapName,\n getNamedArgument,\n getPositionalArgument,\n lowerFirst,\n parseIndexFieldList,\n parseQuotedStringLiteral,\n parseRelationAttribute,\n} from './psl-helpers';\n\nexport interface InterpretPslDocumentToMongoContractInput {\n readonly document: ParsePslDocumentResult;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n readonly codecLookup?: CodecLookup;\n}\n\ninterface FieldMappings {\n readonly pslNameToMapped: Map<string, string>;\n}\n\ninterface FkRelation {\n readonly declaringModel: string;\n readonly fieldName: string;\n readonly targetModel: string;\n readonly relationName?: string;\n readonly localFields: readonly string[];\n readonly targetFields: readonly string[];\n}\n\nfunction fkRelationPairKey(declaringModel: string, targetModel: string): string {\n return `${declaringModel}::${targetModel}`;\n}\n\nfunction resolveFieldMappings(model: PslModel): FieldMappings {\n const pslNameToMapped = new Map<string, string>();\n for (const field of model.fields) {\n const mapped = getMapName(field.attributes) ?? field.name;\n pslNameToMapped.set(field.name, mapped);\n }\n return { pslNameToMapped };\n}\n\nfunction resolveCollectionName(model: PslModel): string {\n return getMapName(model.attributes) ?? lowerFirst(model.name);\n}\n\ninterface MongoModelEntry {\n readonly fields: Record<string, ContractField>;\n readonly relations: Record<string, ContractReferenceRelation>;\n readonly storage: { readonly collection: string };\n readonly discriminator?: { readonly field: string };\n readonly variants?: Record<string, { readonly value: string }>;\n readonly base?: string;\n}\n\ntype DiscriminatorDeclaration = { readonly fieldName: string; readonly span: PslModel['span'] };\ntype BaseDeclaration = {\n readonly baseName: string;\n readonly value: string;\n readonly collectionName: string;\n readonly span: PslModel['span'];\n};\n\nfunction collectPolymorphismDeclarations(\n document: ParsePslDocumentResult,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): {\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n} {\n const discriminatorDeclarations = new Map<string, DiscriminatorDeclaration>();\n const baseDeclarations = new Map<string, BaseDeclaration>();\n\n for (const pslModel of document.ast.models) {\n for (const attr of pslModel.attributes) {\n if (attr.name === 'discriminator') {\n const fieldName = getPositionalArgument(attr);\n if (!fieldName) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@discriminator requires a field name argument`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const discField = pslModel.fields.find((f) => f.name === fieldName);\n if (discField && discField.typeName !== 'String') {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Discriminator field \"${fieldName}\" on model \"${pslModel.name}\" must be of type String, but is \"${discField.typeName}\"`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n discriminatorDeclarations.set(pslModel.name, { fieldName, span: attr.span });\n }\n if (attr.name === 'base') {\n const baseName = getPositionalArgument(attr, 0);\n const rawValue = getPositionalArgument(attr, 1);\n if (!baseName || !rawValue) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base requires two arguments: base model name and discriminator value`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const value = parseQuotedStringLiteral(rawValue);\n if (value === undefined) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base discriminator value must be a quoted string literal`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const collectionName = resolveCollectionName(pslModel);\n baseDeclarations.set(pslModel.name, { baseName, value, collectionName, span: attr.span });\n }\n }\n }\n\n return { discriminatorDeclarations, baseDeclarations };\n}\n\nfunction resolvePolymorphism(input: {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n collections: Record<string, Record<string, unknown>>;\n document: ParsePslDocumentResult;\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n modelNames: ReadonlySet<string>;\n indexSpans: Map<MongoStorageIndex, PslSpan>;\n modelIndexesByName: Map<string, readonly MongoStorageIndex[]>;\n sourceId: string;\n}): {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n collections: Record<string, Record<string, unknown>>;\n diagnostics: ContractSourceDiagnostic[];\n} {\n const {\n discriminatorDeclarations,\n baseDeclarations,\n modelNames,\n sourceId,\n document,\n indexSpans,\n modelIndexesByName,\n } = input;\n let patched = input.models;\n let roots = input.roots;\n let collections = input.collections;\n const diagnostics: ContractSourceDiagnostic[] = [];\n\n for (const [modelName, decl] of discriminatorDeclarations) {\n if (baseDeclarations.has(modelName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_AND_BASE',\n message: `Model \"${modelName}\" cannot have both @@discriminator and @@base`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const model = patched[modelName];\n if (!model) continue;\n\n const pslModel = document.ast.models.find((m) => m.name === modelName);\n const mappedDiscriminatorField = pslModel\n ? (resolveFieldMappings(pslModel).pslNameToMapped.get(decl.fieldName) ?? decl.fieldName)\n : decl.fieldName;\n\n if (!Object.hasOwn(model.fields, mappedDiscriminatorField)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_FIELD_NOT_FOUND',\n message: `Discriminator field \"${decl.fieldName}\" is not a field on model \"${modelName}\"`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const variants: Record<string, { readonly value: string }> = {};\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (baseDecl.baseName !== modelName) continue;\n variants[variantName] = { value: baseDecl.value };\n }\n\n if (Object.keys(variants).length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_DISCRIMINATOR',\n message: `Model \"${modelName}\" has @@discriminator but no variant models declare @@base(${modelName}, ...)`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n patched = {\n ...patched,\n [modelName]: { ...model, discriminator: { field: mappedDiscriminatorField }, variants },\n };\n }\n\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (!modelNames.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_BASE_TARGET_NOT_FOUND',\n message: `Model \"${variantName}\" @@base references non-existent model \"${baseDecl.baseName}\"`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (!discriminatorDeclarations.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BASE',\n message: `Model \"${variantName}\" declares @@base(${baseDecl.baseName}, ...) but \"${baseDecl.baseName}\" has no @@discriminator`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (discriminatorDeclarations.has(variantName)) {\n continue;\n }\n\n const baseModel = patched[baseDecl.baseName];\n const variantPslModel = document.ast.models.find((m) => m.name === variantName);\n if (!variantPslModel) continue;\n const hasExplicitMap = getMapName(variantPslModel.attributes) !== undefined;\n\n if (hasExplicitMap && baseModel && baseDecl.collectionName !== baseModel.storage.collection) {\n diagnostics.push({\n code: 'PSL_MONGO_VARIANT_SEPARATE_COLLECTION',\n message: `Mongo variant \"${variantName}\" cannot use a different collection than its base \"${baseDecl.baseName}\". Mongo only supports single-collection polymorphism.`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n const baseCollection = baseModel?.storage.collection ?? baseDecl.collectionName;\n const variantModel = patched[variantName];\n if (variantModel) {\n patched = {\n ...patched,\n [variantName]: {\n ...variantModel,\n base: baseDecl.baseName,\n storage: { collection: baseCollection },\n },\n };\n }\n\n const variantCollectionName = resolveCollectionName(variantPslModel);\n if (roots[variantCollectionName] === variantName) {\n if (variantCollectionName === baseCollection && baseModel) {\n roots = { ...roots, [variantCollectionName]: baseDecl.baseName };\n } else {\n roots = Object.fromEntries(\n Object.entries(roots).filter(([key]) => key !== variantCollectionName),\n );\n }\n }\n\n const variantOwnIndexes = modelIndexesByName.get(variantName) ?? [];\n const baseColl = collections[baseCollection];\n\n const baseModelEntry = patched[baseDecl.baseName];\n const discriminatorField = baseModelEntry?.discriminator?.field;\n const scopedVariantIndexes: MongoStorageIndex[] = [];\n if (discriminatorField) {\n for (const idx of variantOwnIndexes) {\n const result = applyPolymorphicScopeToMongoIndex(idx, {\n discriminatorField,\n discriminatorValue: baseDecl.value,\n });\n if (result.kind === 'conflict') {\n const span = indexSpans.get(idx) ?? baseDecl.span;\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `Variant \"${variantName}\" index conflicts with discriminator scope: ${result.reason}`,\n sourceId,\n span,\n });\n continue;\n }\n if (result.index !== idx) {\n indexSpans.set(result.index, indexSpans.get(idx) ?? baseDecl.span);\n }\n scopedVariantIndexes.push(result.index);\n }\n } else {\n scopedVariantIndexes.push(...variantOwnIndexes);\n }\n\n if (variantCollectionName !== baseCollection) {\n const filtered = Object.fromEntries(\n Object.entries(collections).filter(([key]) => key !== variantCollectionName),\n );\n if (scopedVariantIndexes.length > 0 && baseColl) {\n const baseIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];\n collections = {\n ...filtered,\n [baseCollection]: {\n ...baseColl,\n indexes: [...baseIndexes, ...scopedVariantIndexes],\n },\n };\n } else {\n collections = filtered;\n }\n } else if (baseColl) {\n const existingIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];\n const variantIndexSet = new Set<MongoStorageIndex>(variantOwnIndexes);\n const withoutUnscopedVariants = existingIndexes.filter((idx) => !variantIndexSet.has(idx));\n const mergedIndexes = [...withoutUnscopedVariants];\n for (const idx of scopedVariantIndexes) {\n const idxKey = canonicalJson(idx);\n const isDuplicate = withoutUnscopedVariants.some(\n (existing) => canonicalJson(existing) === idxKey,\n );\n if (!isDuplicate) {\n mergedIndexes.push(idx);\n }\n }\n if (\n mergedIndexes.length !== existingIndexes.length ||\n mergedIndexes.some((idx, i) => idx !== existingIndexes[i])\n ) {\n const next: Record<string, unknown> = { ...baseColl };\n if (mergedIndexes.length > 0) {\n next['indexes'] = mergedIndexes;\n } else {\n delete next['indexes'];\n }\n collections = { ...collections, [baseCollection]: next };\n }\n }\n }\n\n return { models: patched, roots, collections, diagnostics };\n}\n\n// Property-order-stable serialization for structural equality of plain\n// JSON-compatible values. Used for comparing MongoStorageIndex shapes in\n// the variant-merge dedup path where a future change to the spread order\n// would otherwise produce JSON-stringify mismatches even though the\n// indexes are structurally identical.\nfunction canonicalJson(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(canonicalJson).join(',')}]`;\n }\n if (value && typeof value === 'object') {\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`)\n .join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\nfunction parseIndexDirection(raw: string | undefined): MongoIndexKeyDirection {\n if (!raw) return 1;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const num = Number(stripped);\n if (num === 1 || num === -1) return num;\n if (['text', '2dsphere', '2d', 'hashed'].includes(stripped))\n return stripped as MongoIndexKeyDirection;\n return 1;\n}\n\nfunction parseNumericArg(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const n = Number(raw);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction parseBooleanArg(raw: string | undefined): boolean | undefined {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n return undefined;\n}\n\nfunction parseJsonArg(raw: string | undefined): Record<string, unknown> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '').replace(/\\\\\"/g, '\"');\n try {\n const parsed = JSON.parse(stripped);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // not valid JSON\n }\n return undefined;\n}\n\nfunction parseCollation(\n attr: import('@prisma-next/psl-parser').PslAttribute,\n): Record<string, unknown> | null | undefined {\n const locale = stripQuotesHelper(getNamedArgument(attr, 'collationLocale'));\n if (!locale) {\n const hasAnyCollationArg =\n getNamedArgument(attr, 'collationStrength') != null ||\n getNamedArgument(attr, 'collationCaseLevel') != null ||\n getNamedArgument(attr, 'collationCaseFirst') != null ||\n getNamedArgument(attr, 'collationNumericOrdering') != null ||\n getNamedArgument(attr, 'collationAlternate') != null ||\n getNamedArgument(attr, 'collationMaxVariable') != null ||\n getNamedArgument(attr, 'collationBackwards') != null ||\n getNamedArgument(attr, 'collationNormalization') != null;\n return hasAnyCollationArg ? null : undefined;\n }\n\n const collation: Record<string, unknown> = { locale };\n const strength = parseNumericArg(getNamedArgument(attr, 'collationStrength'));\n if (strength != null) collation['strength'] = strength;\n const caseLevel = parseBooleanArg(getNamedArgument(attr, 'collationCaseLevel'));\n if (caseLevel != null) collation['caseLevel'] = caseLevel;\n const caseFirst = stripQuotesHelper(getNamedArgument(attr, 'collationCaseFirst'));\n if (caseFirst != null) collation['caseFirst'] = caseFirst;\n const numericOrdering = parseBooleanArg(getNamedArgument(attr, 'collationNumericOrdering'));\n if (numericOrdering != null) collation['numericOrdering'] = numericOrdering;\n const alternate = stripQuotesHelper(getNamedArgument(attr, 'collationAlternate'));\n if (alternate != null) collation['alternate'] = alternate;\n const maxVariable = stripQuotesHelper(getNamedArgument(attr, 'collationMaxVariable'));\n if (maxVariable != null) collation['maxVariable'] = maxVariable;\n const backwards = parseBooleanArg(getNamedArgument(attr, 'collationBackwards'));\n if (backwards != null) collation['backwards'] = backwards;\n const normalization = parseBooleanArg(getNamedArgument(attr, 'collationNormalization'));\n if (normalization != null) collation['normalization'] = normalization;\n return collation;\n}\n\nfunction stripQuotesHelper(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n}\n\nfunction parseProjectionList(\n raw: string | undefined,\n value: 0 | 1,\n): Record<string, 0 | 1> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const inner = stripped.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return undefined;\n const fields = inner\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n const result: Record<string, 0 | 1> = {};\n for (const f of fields) {\n result[f] = value;\n }\n return result;\n}\n\nfunction collectIndexes(\n pslModel: PslModel,\n fieldMappings: FieldMappings,\n modelNames: ReadonlySet<string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n indexSpans: Map<MongoStorageIndex, PslSpan>,\n): MongoStorageIndex[] {\n const indexes: MongoStorageIndex[] = [];\n let textIndexCount = 0;\n\n // Storage-indexable PSL field names — i.e. all declared fields except\n // relation fields (which don't materialize a column on this model). The\n // index field-existence check (PSL_INDEX_FIELD_NOT_FOUND) consults this\n // rather than fieldMappings.pslNameToMapped because the latter contains\n // every PSL field including relation fields.\n const indexableFieldNames = new Set<string>();\n for (const f of pslModel.fields) {\n if (modelNames.has(f.typeName)) continue;\n indexableFieldNames.add(f.name);\n }\n\n for (const field of pslModel.fields) {\n if (modelNames.has(field.typeName)) continue;\n const uniqueAttr = getAttribute(field.attributes, 'unique');\n if (!uniqueAttr) continue;\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n const fieldUniqueIndex: MongoStorageIndex = {\n keys: [{ field: mappedName, direction: 1 }],\n unique: true,\n };\n indexes.push(fieldUniqueIndex);\n indexSpans.set(fieldUniqueIndex, uniqueAttr.span);\n }\n\n for (const attr of pslModel.attributes) {\n const isIndex = attr.name === 'index';\n const isUnique = attr.name === 'unique';\n const isTextIndex = attr.name === 'textIndex';\n if (!isIndex && !isUnique && !isTextIndex) continue;\n\n const fieldsArg = getPositionalArgument(attr, 0);\n if (!fieldsArg) continue;\n const parsedFields = parseIndexFieldList(fieldsArg);\n if (parsedFields.length === 0) continue;\n\n const hasWildcard = parsedFields.some((f) => f.isWildcard);\n const wildcardCount = parsedFields.filter((f) => f.isWildcard).length;\n\n if (wildcardCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'An index can contain at most one wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isUnique && hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Unique indexes cannot use wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isTextIndex) {\n textIndexCount++;\n if (textIndexCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `Only one @@textIndex is allowed per collection (model \"${pslModel.name}\")`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n }\n\n const typeArg = getNamedArgument(attr, 'type');\n const defaultDirection: MongoIndexKeyDirection = isTextIndex\n ? 'text'\n : parseIndexDirection(typeArg);\n\n if (\n hasWildcard &&\n typeof defaultDirection === 'string' &&\n ['hashed', '2dsphere', '2d'].includes(defaultDirection)\n ) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (defaultDirection === 'hashed' && parsedFields.length > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Hashed indexes must have exactly one field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n let missingField: string | undefined;\n for (const pf of parsedFields) {\n let fieldNameForLookup: string | undefined;\n if (pf.isWildcard) {\n const wildcardMatch = pf.name.match(/^(.+)\\.\\$\\*\\*$/);\n fieldNameForLookup = wildcardMatch ? wildcardMatch[1] : undefined;\n } else {\n fieldNameForLookup = pf.name;\n }\n if (fieldNameForLookup === undefined || fieldNameForLookup.length === 0) continue;\n if (!indexableFieldNames.has(fieldNameForLookup)) {\n missingField = fieldNameForLookup;\n break;\n }\n }\n if (missingField !== undefined) {\n diagnostics.push({\n code: 'PSL_INDEX_FIELD_NOT_FOUND',\n message: `Index on model \"${pslModel.name}\" references unknown field \"${missingField}\"`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const keys = parsedFields.map((pf) => {\n const mappedName = pf.isWildcard\n ? pf.name.replace(/^(.+)\\.\\$\\*\\*$/, (_, prefix: string) => {\n const mapped = fieldMappings.pslNameToMapped.get(prefix);\n return mapped ? `${mapped}.$**` : `${prefix}.$**`;\n })\n : (fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name);\n const direction: MongoIndexKeyDirection =\n pf.direction != null ? (pf.direction as MongoIndexKeyDirection) : defaultDirection;\n return { field: mappedName, direction };\n });\n\n const unique = isUnique ? true : undefined;\n const sparse = isTextIndex ? undefined : parseBooleanArg(getNamedArgument(attr, 'sparse'));\n const expireAfterSeconds = isTextIndex\n ? undefined\n : parseNumericArg(getNamedArgument(attr, 'expireAfterSeconds'));\n\n if (hasWildcard && expireAfterSeconds != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'expireAfterSeconds cannot be combined with wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const partialFilterExpression = parseJsonArg(getNamedArgument(attr, 'filter'));\n\n const includeArg = getNamedArgument(attr, 'include');\n const excludeArg = getNamedArgument(attr, 'exclude');\n\n if (includeArg != null && excludeArg != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Cannot specify both include and exclude on the same index',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if ((includeArg != null || excludeArg != null) && !hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'include/exclude options are only valid when the index contains a wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const wildcardProjection =\n includeArg != null\n ? parseProjectionList(includeArg, 1)\n : excludeArg != null\n ? parseProjectionList(excludeArg, 0)\n : undefined;\n\n const collation = parseCollation(attr);\n if (collation === null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'collationLocale is required when using collation options',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const rawWeights = parseJsonArg(getNamedArgument(attr, 'weights'));\n let weights: Record<string, number> | undefined;\n if (rawWeights) {\n weights = {};\n for (const [k, v] of Object.entries(rawWeights)) {\n if (typeof v === 'number') weights[k] = v;\n }\n }\n\n const rawDefaultLang = isTextIndex\n ? getNamedArgument(attr, 'language')\n : getNamedArgument(attr, 'default_language');\n const default_language = stripQuotesHelper(rawDefaultLang);\n\n const rawLangOverride = getNamedArgument(attr, 'languageOverride');\n const language_override = stripQuotesHelper(rawLangOverride);\n\n const index: MongoStorageIndex = {\n keys,\n ...(unique != null && { unique }),\n ...(sparse != null && { sparse }),\n ...(expireAfterSeconds != null && { expireAfterSeconds }),\n ...(partialFilterExpression != null && { partialFilterExpression }),\n ...(wildcardProjection != null && { wildcardProjection }),\n ...(collation != null && { collation }),\n ...(weights != null && { weights }),\n ...(default_language != null && { default_language }),\n ...(language_override != null && { language_override }),\n };\n\n indexes.push(index);\n indexSpans.set(index, attr.span);\n }\n\n return indexes;\n}\n\nfunction isRelationField(field: PslField, modelNames: ReadonlySet<string>): boolean {\n return modelNames.has(field.typeName);\n}\n\nfunction resolveFieldCodecId(\n field: PslField,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n): string | undefined {\n return scalarTypeDescriptors.get(field.typeName);\n}\n\nfunction resolveNonRelationField(\n field: PslField,\n ownerName: string,\n compositeTypeNames: ReadonlySet<string>,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): ContractField | undefined {\n if (compositeTypeNames.has(field.typeName)) {\n const result: ContractField = {\n type: { kind: 'valueObject', name: field.typeName },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n }\n\n const codecId = resolveFieldCodecId(field, scalarTypeDescriptors);\n if (!codecId) {\n diagnostics.push({\n code: 'PSL_UNSUPPORTED_FIELD_TYPE',\n message: `Field \"${ownerName}.${field.name}\" type \"${field.typeName}\" is not supported in Mongo PSL interpreter`,\n sourceId,\n span: field.span,\n });\n return undefined;\n }\n\n const result: ContractField = {\n type: { kind: 'scalar', codecId },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n}\n\nexport function interpretPslDocumentToMongoContract(\n input: InterpretPslDocumentToMongoContractInput,\n): Result<Contract, ContractSourceDiagnostics> {\n const { document, scalarTypeDescriptors, codecLookup } = input;\n const sourceId = document.ast.sourceId;\n const diagnostics: ContractSourceDiagnostic[] = [];\n const modelNames = new Set(document.ast.models.map((m) => m.name));\n const compositeTypeNames = new Set(document.ast.compositeTypes.map((ct) => ct.name));\n\n const models: Record<string, MongoModelEntry> = {};\n const collections: Record<string, Record<string, unknown>> = {};\n const roots: Record<string, string> = {};\n const allFkRelations: FkRelation[] = [];\n const indexSpans = new Map<MongoStorageIndex, PslSpan>();\n const modelIndexesByName = new Map<string, readonly MongoStorageIndex[]>();\n\n interface BackrelationCandidate {\n readonly modelName: string;\n readonly fieldName: string;\n readonly targetModelName: string;\n readonly relationName?: string;\n readonly cardinality: '1:1' | '1:N';\n readonly field: PslField;\n }\n const backrelationCandidates: BackrelationCandidate[] = [];\n\n for (const pslModel of document.ast.models) {\n const collectionName = resolveCollectionName(pslModel);\n const fieldMappings = resolveFieldMappings(pslModel);\n\n const fields: Record<string, ContractField> = {};\n const relations: Record<string, ContractReferenceRelation> = {};\n\n for (const field of pslModel.fields) {\n if (isRelationField(field, modelNames)) {\n const relation = parseRelationAttribute(field.attributes);\n\n if (field.list || !(relation?.fields && relation?.references)) {\n backrelationCandidates.push({\n modelName: pslModel.name,\n fieldName: field.name,\n targetModelName: field.typeName,\n ...(relation?.relationName !== undefined\n ? { relationName: relation.relationName }\n : {}),\n cardinality: field.list ? '1:N' : '1:1',\n field,\n });\n continue;\n }\n\n if (relation?.fields && relation?.references) {\n const localMapped = relation.fields.map((f) => fieldMappings.pslNameToMapped.get(f) ?? f);\n\n const targetModel = document.ast.models.find((m) => m.name === field.typeName);\n const targetFieldMappings = targetModel ? resolveFieldMappings(targetModel) : undefined;\n const targetMapped = relation.references.map(\n (f) => targetFieldMappings?.pslNameToMapped.get(f) ?? f,\n );\n\n relations[field.name] = {\n to: field.typeName,\n cardinality: 'N:1' as const,\n on: {\n localFields: localMapped,\n targetFields: targetMapped,\n },\n };\n\n allFkRelations.push({\n declaringModel: pslModel.name,\n fieldName: field.name,\n targetModel: field.typeName,\n ...(relation.relationName !== undefined ? { relationName: relation.relationName } : {}),\n localFields: localMapped,\n targetFields: targetMapped,\n });\n }\n continue;\n }\n\n const resolved = resolveNonRelationField(\n field,\n pslModel.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n fields[mappedName] = resolved;\n }\n\n const isVariantModel = pslModel.attributes.some((attr) => attr.name === 'base');\n const hasIdField = pslModel.fields.some((f) => getAttribute(f.attributes, 'id') !== undefined);\n if (!hasIdField && !isVariantModel) {\n diagnostics.push({\n code: 'PSL_MISSING_ID_FIELD',\n message: `Model \"${pslModel.name}\" has no field with @id attribute. Every model must have exactly one @id field.`,\n sourceId,\n });\n }\n\n models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };\n const modelIndexes = collectIndexes(\n pslModel,\n fieldMappings,\n modelNames,\n sourceId,\n diagnostics,\n indexSpans,\n );\n modelIndexesByName.set(pslModel.name, modelIndexes);\n const existingColl = collections[collectionName];\n if (existingColl && modelIndexes.length > 0) {\n const existingIndexes = (existingColl['indexes'] ?? []) as MongoStorageIndex[];\n collections[collectionName] = { indexes: [...existingIndexes, ...modelIndexes] };\n } else if (!existingColl) {\n collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};\n }\n roots[collectionName] = pslModel.name;\n }\n\n const valueObjects: Record<string, ContractValueObject> = {};\n for (const compositeType of document.ast.compositeTypes) {\n const fields: Record<string, ContractField> = {};\n for (const field of compositeType.fields) {\n const resolved = resolveNonRelationField(\n field,\n compositeType.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n fields[field.name] = resolved;\n }\n valueObjects[compositeType.name] = { fields };\n }\n\n const fkRelationsByPair = new Map<string, FkRelation[]>();\n for (const fk of allFkRelations) {\n const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);\n const existing = fkRelationsByPair.get(key);\n if (existing) {\n existing.push(fk);\n } else {\n fkRelationsByPair.set(key, [fk]);\n }\n }\n\n for (const candidate of backrelationCandidates) {\n const pairKey = fkRelationPairKey(candidate.targetModelName, candidate.modelName);\n const pairMatches = fkRelationsByPair.get(pairKey) ?? [];\n const matches = candidate.relationName\n ? pairMatches.filter((r) => r.relationName === candidate.relationName)\n : [...pairMatches];\n\n if (matches.length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" has no matching FK-side relation on model \"${candidate.targetModelName}\". Add @relation(fields: [...], references: [...]) on the FK-side relation or use an explicit join model for many-to-many.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n if (matches.length > 1) {\n diagnostics.push({\n code: 'PSL_AMBIGUOUS_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" matches multiple FK-side relations on model \"${candidate.targetModelName}\". Add @relation(\"...\") to both sides to disambiguate.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n\n const fk = matches[0];\n if (!fk) continue;\n const modelEntry = models[candidate.modelName];\n if (!modelEntry) continue;\n modelEntry.relations[candidate.fieldName] = {\n to: candidate.targetModelName,\n cardinality: candidate.cardinality,\n on: {\n localFields: fk.targetFields,\n targetFields: fk.localFields,\n },\n };\n }\n\n const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(\n document,\n sourceId,\n diagnostics,\n );\n const polyResult = resolvePolymorphism({\n models,\n roots,\n collections,\n document,\n discriminatorDeclarations,\n baseDeclarations,\n modelNames,\n indexSpans,\n modelIndexesByName,\n sourceId,\n });\n\n if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) {\n return notOk({\n summary: 'PSL to Mongo contract interpretation failed',\n diagnostics: [...diagnostics, ...polyResult.diagnostics],\n });\n }\n\n const resolvedModels = polyResult.models;\n const resolvedCollections = polyResult.collections;\n\n for (const [, modelEntry] of Object.entries(resolvedModels)) {\n if (modelEntry.base) continue;\n\n const collectionName = modelEntry.storage.collection;\n const coll = resolvedCollections[collectionName];\n if (!coll) continue;\n\n if (modelEntry.discriminator && modelEntry.variants) {\n const variantEntries = Object.entries(modelEntry.variants).map(\n ([variantName, { value }]) => ({\n discriminatorValue: value,\n fields: resolvedModels[variantName]?.fields ?? {},\n }),\n );\n coll['validator'] = derivePolymorphicJsonSchema(\n modelEntry.fields,\n modelEntry.discriminator.field,\n variantEntries,\n valueObjects,\n codecLookup,\n );\n } else {\n coll['validator'] = deriveJsonSchema(modelEntry.fields, valueObjects, codecLookup);\n }\n }\n\n const target = 'mongo';\n const targetFamily = 'mongo';\n const storageWithoutHash = { collections: resolvedCollections };\n const storageHash = computeStorageHash({ target, targetFamily, storage: storageWithoutHash });\n const capabilities: Record<string, Record<string, boolean>> = {};\n\n return ok({\n targetFamily,\n target,\n roots: polyResult.roots,\n models: polyResult.models,\n ...(Object.keys(valueObjects).length > 0 ? { valueObjects } : {}),\n storage: { ...storageWithoutHash, storageHash },\n extensionPacks: {},\n capabilities,\n profileHash: computeProfileHash({ target, targetFamily, capabilities }),\n meta: {},\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,24 +1,25 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo-contract-psl",
3
- "version": "0.5.0-dev.7",
3
+ "version": "0.5.0-dev.70",
4
+ "license": "Apache-2.0",
4
5
  "type": "module",
5
6
  "sideEffects": false,
6
7
  "description": "PSL-to-Mongo ContractIR interpreter for Prisma Next",
7
8
  "dependencies": {
8
9
  "pathe": "^2.0.3",
9
- "@prisma-next/config": "0.5.0-dev.7",
10
- "@prisma-next/contract": "0.5.0-dev.7",
11
- "@prisma-next/framework-components": "0.5.0-dev.7",
12
- "@prisma-next/mongo-contract": "0.5.0-dev.7",
13
- "@prisma-next/psl-parser": "0.5.0-dev.7",
14
- "@prisma-next/utils": "0.5.0-dev.7"
10
+ "@prisma-next/config": "0.5.0-dev.70",
11
+ "@prisma-next/framework-components": "0.5.0-dev.70",
12
+ "@prisma-next/mongo-contract": "0.5.0-dev.70",
13
+ "@prisma-next/contract": "0.5.0-dev.70",
14
+ "@prisma-next/psl-parser": "0.5.0-dev.70",
15
+ "@prisma-next/utils": "0.5.0-dev.70"
15
16
  },
16
17
  "devDependencies": {
17
- "tsdown": "0.18.4",
18
+ "tsdown": "0.22.0",
18
19
  "typescript": "5.9.3",
19
- "vitest": "4.0.17",
20
- "@prisma-next/tsdown": "0.0.0",
21
- "@prisma-next/tsconfig": "0.0.0"
20
+ "vitest": "4.1.5",
21
+ "@prisma-next/tsconfig": "0.0.0",
22
+ "@prisma-next/tsdown": "0.0.0"
22
23
  },
23
24
  "files": [
24
25
  "dist",
@@ -6,8 +6,7 @@ function resolveBsonType(
6
6
  codecId: string,
7
7
  codecLookup: CodecLookup | undefined,
8
8
  ): string | undefined {
9
- const codec = codecLookup?.get(codecId);
10
- return codec?.targetTypes[0];
9
+ return codecLookup?.targetTypesFor(codecId)?.[0];
11
10
  }
12
11
 
13
12
  function fieldToBsonSchema(
@@ -10,8 +10,12 @@ import type {
10
10
  ContractValueObject,
11
11
  } from '@prisma-next/contract/types';
12
12
  import type { CodecLookup } from '@prisma-next/framework-components/codec';
13
- import type { MongoIndexKeyDirection, MongoStorageIndex } from '@prisma-next/mongo-contract';
14
- import type { ParsePslDocumentResult, PslField, PslModel } from '@prisma-next/psl-parser';
13
+ import {
14
+ applyPolymorphicScopeToMongoIndex,
15
+ type MongoIndexKeyDirection,
16
+ type MongoStorageIndex,
17
+ } from '@prisma-next/mongo-contract';
18
+ import type { ParsePslDocumentResult, PslField, PslModel, PslSpan } from '@prisma-next/psl-parser';
15
19
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
16
20
  import { deriveJsonSchema, derivePolymorphicJsonSchema } from './derive-json-schema';
17
21
  import {
@@ -153,6 +157,8 @@ function resolvePolymorphism(input: {
153
157
  discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;
154
158
  baseDeclarations: Map<string, BaseDeclaration>;
155
159
  modelNames: ReadonlySet<string>;
160
+ indexSpans: Map<MongoStorageIndex, PslSpan>;
161
+ modelIndexesByName: Map<string, readonly MongoStorageIndex[]>;
156
162
  sourceId: string;
157
163
  }): {
158
164
  models: Record<string, MongoModelEntry>;
@@ -160,7 +166,15 @@ function resolvePolymorphism(input: {
160
166
  collections: Record<string, Record<string, unknown>>;
161
167
  diagnostics: ContractSourceDiagnostic[];
162
168
  } {
163
- const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document } = input;
169
+ const {
170
+ discriminatorDeclarations,
171
+ baseDeclarations,
172
+ modelNames,
173
+ sourceId,
174
+ document,
175
+ indexSpans,
176
+ modelIndexesByName,
177
+ } = input;
164
178
  let patched = input.models;
165
179
  let roots = input.roots;
166
180
  let collections = input.collections;
@@ -281,39 +295,78 @@ function resolvePolymorphism(input: {
281
295
  }
282
296
  }
283
297
 
284
- const variantColl = collections[variantCollectionName];
285
- const variantIndexes = (variantColl?.['indexes'] ?? []) as MongoStorageIndex[];
298
+ const variantOwnIndexes = modelIndexesByName.get(variantName) ?? [];
286
299
  const baseColl = collections[baseCollection];
287
300
 
301
+ const baseModelEntry = patched[baseDecl.baseName];
302
+ const discriminatorField = baseModelEntry?.discriminator?.field;
303
+ const scopedVariantIndexes: MongoStorageIndex[] = [];
304
+ if (discriminatorField) {
305
+ for (const idx of variantOwnIndexes) {
306
+ const result = applyPolymorphicScopeToMongoIndex(idx, {
307
+ discriminatorField,
308
+ discriminatorValue: baseDecl.value,
309
+ });
310
+ if (result.kind === 'conflict') {
311
+ const span = indexSpans.get(idx) ?? baseDecl.span;
312
+ diagnostics.push({
313
+ code: 'PSL_INVALID_INDEX',
314
+ message: `Variant "${variantName}" index conflicts with discriminator scope: ${result.reason}`,
315
+ sourceId,
316
+ span,
317
+ });
318
+ continue;
319
+ }
320
+ if (result.index !== idx) {
321
+ indexSpans.set(result.index, indexSpans.get(idx) ?? baseDecl.span);
322
+ }
323
+ scopedVariantIndexes.push(result.index);
324
+ }
325
+ } else {
326
+ scopedVariantIndexes.push(...variantOwnIndexes);
327
+ }
328
+
288
329
  if (variantCollectionName !== baseCollection) {
289
330
  const filtered = Object.fromEntries(
290
331
  Object.entries(collections).filter(([key]) => key !== variantCollectionName),
291
332
  );
292
- if (variantIndexes.length > 0 && baseColl) {
333
+ if (scopedVariantIndexes.length > 0 && baseColl) {
293
334
  const baseIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];
294
335
  collections = {
295
336
  ...filtered,
296
- [baseCollection]: { ...baseColl, indexes: [...baseIndexes, ...variantIndexes] },
337
+ [baseCollection]: {
338
+ ...baseColl,
339
+ indexes: [...baseIndexes, ...scopedVariantIndexes],
340
+ },
297
341
  };
298
342
  } else {
299
343
  collections = filtered;
300
344
  }
301
- } else if (variantIndexes.length > 0 && baseColl) {
302
- const baseIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];
303
- const mergedIndexes = [...baseIndexes];
304
- for (const idx of variantIndexes) {
305
- const isDuplicate = baseIndexes.some(
306
- (existing) => JSON.stringify(existing) === JSON.stringify(idx),
345
+ } else if (baseColl) {
346
+ const existingIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];
347
+ const variantIndexSet = new Set<MongoStorageIndex>(variantOwnIndexes);
348
+ const withoutUnscopedVariants = existingIndexes.filter((idx) => !variantIndexSet.has(idx));
349
+ const mergedIndexes = [...withoutUnscopedVariants];
350
+ for (const idx of scopedVariantIndexes) {
351
+ const idxKey = canonicalJson(idx);
352
+ const isDuplicate = withoutUnscopedVariants.some(
353
+ (existing) => canonicalJson(existing) === idxKey,
307
354
  );
308
355
  if (!isDuplicate) {
309
356
  mergedIndexes.push(idx);
310
357
  }
311
358
  }
312
- if (mergedIndexes.length > baseIndexes.length) {
313
- collections = {
314
- ...collections,
315
- [baseCollection]: { ...baseColl, indexes: mergedIndexes },
316
- };
359
+ if (
360
+ mergedIndexes.length !== existingIndexes.length ||
361
+ mergedIndexes.some((idx, i) => idx !== existingIndexes[i])
362
+ ) {
363
+ const next: Record<string, unknown> = { ...baseColl };
364
+ if (mergedIndexes.length > 0) {
365
+ next['indexes'] = mergedIndexes;
366
+ } else {
367
+ delete next['indexes'];
368
+ }
369
+ collections = { ...collections, [baseCollection]: next };
317
370
  }
318
371
  }
319
372
  }
@@ -321,6 +374,24 @@ function resolvePolymorphism(input: {
321
374
  return { models: patched, roots, collections, diagnostics };
322
375
  }
323
376
 
377
+ // Property-order-stable serialization for structural equality of plain
378
+ // JSON-compatible values. Used for comparing MongoStorageIndex shapes in
379
+ // the variant-merge dedup path where a future change to the spread order
380
+ // would otherwise produce JSON-stringify mismatches even though the
381
+ // indexes are structurally identical.
382
+ function canonicalJson(value: unknown): string {
383
+ if (Array.isArray(value)) {
384
+ return `[${value.map(canonicalJson).join(',')}]`;
385
+ }
386
+ if (value && typeof value === 'object') {
387
+ return `{${Object.entries(value as Record<string, unknown>)
388
+ .sort(([left], [right]) => left.localeCompare(right))
389
+ .map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`)
390
+ .join(',')}}`;
391
+ }
392
+ return JSON.stringify(value);
393
+ }
394
+
324
395
  function parseIndexDirection(raw: string | undefined): MongoIndexKeyDirection {
325
396
  if (!raw) return 1;
326
397
  const stripped = raw.replace(/^["']/, '').replace(/["']$/, '');
@@ -424,19 +495,33 @@ function collectIndexes(
424
495
  modelNames: ReadonlySet<string>,
425
496
  sourceId: string,
426
497
  diagnostics: ContractSourceDiagnostic[],
498
+ indexSpans: Map<MongoStorageIndex, PslSpan>,
427
499
  ): MongoStorageIndex[] {
428
500
  const indexes: MongoStorageIndex[] = [];
429
501
  let textIndexCount = 0;
430
502
 
503
+ // Storage-indexable PSL field names — i.e. all declared fields except
504
+ // relation fields (which don't materialize a column on this model). The
505
+ // index field-existence check (PSL_INDEX_FIELD_NOT_FOUND) consults this
506
+ // rather than fieldMappings.pslNameToMapped because the latter contains
507
+ // every PSL field including relation fields.
508
+ const indexableFieldNames = new Set<string>();
509
+ for (const f of pslModel.fields) {
510
+ if (modelNames.has(f.typeName)) continue;
511
+ indexableFieldNames.add(f.name);
512
+ }
513
+
431
514
  for (const field of pslModel.fields) {
432
515
  if (modelNames.has(field.typeName)) continue;
433
516
  const uniqueAttr = getAttribute(field.attributes, 'unique');
434
517
  if (!uniqueAttr) continue;
435
518
  const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;
436
- indexes.push({
519
+ const fieldUniqueIndex: MongoStorageIndex = {
437
520
  keys: [{ field: mappedName, direction: 1 }],
438
521
  unique: true,
439
- });
522
+ };
523
+ indexes.push(fieldUniqueIndex);
524
+ indexSpans.set(fieldUniqueIndex, uniqueAttr.span);
440
525
  }
441
526
 
442
527
  for (const attr of pslModel.attributes) {
@@ -526,6 +611,31 @@ function collectIndexes(
526
611
  continue;
527
612
  }
528
613
 
614
+ let missingField: string | undefined;
615
+ for (const pf of parsedFields) {
616
+ let fieldNameForLookup: string | undefined;
617
+ if (pf.isWildcard) {
618
+ const wildcardMatch = pf.name.match(/^(.+)\.\$\*\*$/);
619
+ fieldNameForLookup = wildcardMatch ? wildcardMatch[1] : undefined;
620
+ } else {
621
+ fieldNameForLookup = pf.name;
622
+ }
623
+ if (fieldNameForLookup === undefined || fieldNameForLookup.length === 0) continue;
624
+ if (!indexableFieldNames.has(fieldNameForLookup)) {
625
+ missingField = fieldNameForLookup;
626
+ break;
627
+ }
628
+ }
629
+ if (missingField !== undefined) {
630
+ diagnostics.push({
631
+ code: 'PSL_INDEX_FIELD_NOT_FOUND',
632
+ message: `Index on model "${pslModel.name}" references unknown field "${missingField}"`,
633
+ sourceId,
634
+ span: attr.span,
635
+ });
636
+ continue;
637
+ }
638
+
529
639
  const keys = parsedFields.map((pf) => {
530
640
  const mappedName = pf.isWildcard
531
641
  ? pf.name.replace(/^(.+)\.\$\*\*$/, (_, prefix: string) => {
@@ -629,6 +739,7 @@ function collectIndexes(
629
739
  };
630
740
 
631
741
  indexes.push(index);
742
+ indexSpans.set(index, attr.span);
632
743
  }
633
744
 
634
745
  return indexes;
@@ -692,6 +803,8 @@ export function interpretPslDocumentToMongoContract(
692
803
  const collections: Record<string, Record<string, unknown>> = {};
693
804
  const roots: Record<string, string> = {};
694
805
  const allFkRelations: FkRelation[] = [];
806
+ const indexSpans = new Map<MongoStorageIndex, PslSpan>();
807
+ const modelIndexesByName = new Map<string, readonly MongoStorageIndex[]>();
695
808
 
696
809
  interface BackrelationCandidate {
697
810
  readonly modelName: string;
@@ -783,7 +896,15 @@ export function interpretPslDocumentToMongoContract(
783
896
  }
784
897
 
785
898
  models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };
786
- const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);
899
+ const modelIndexes = collectIndexes(
900
+ pslModel,
901
+ fieldMappings,
902
+ modelNames,
903
+ sourceId,
904
+ diagnostics,
905
+ indexSpans,
906
+ );
907
+ modelIndexesByName.set(pslModel.name, modelIndexes);
787
908
  const existingColl = collections[collectionName];
788
909
  if (existingColl && modelIndexes.length > 0) {
789
910
  const existingIndexes = (existingColl['indexes'] ?? []) as MongoStorageIndex[];
@@ -876,6 +997,8 @@ export function interpretPslDocumentToMongoContract(
876
997
  discriminatorDeclarations,
877
998
  baseDeclarations,
878
999
  modelNames,
1000
+ indexSpans,
1001
+ modelIndexesByName,
879
1002
  sourceId,
880
1003
  });
881
1004
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"interpreter-CWOjqYYA.mjs","names":["properties: Record<string, unknown>","required: string[]","result: Record<string, unknown>","oneOf: Record<string, unknown>[]","variantOnlyFields: Record<string, ContractField>","entry: Record<string, unknown>","variantProperties: Record<string, unknown>","variantRequired: string[]","parts: string[]","relationName: string | undefined","fieldsArg: PslAttributeArgument | undefined","referencesArg: PslAttributeArgument | undefined","diagnostics: ContractSourceDiagnostic[]","variants: Record<string, { readonly value: string }>","collation: Record<string, unknown>","result: Record<string, 0 | 1>","indexes: MongoStorageIndex[]","defaultDirection: MongoIndexKeyDirection","weights: Record<string, number> | undefined","index: MongoStorageIndex","result: ContractField","result","models: Record<string, MongoModelEntry>","collections: Record<string, Record<string, unknown>>","roots: Record<string, string>","allFkRelations: FkRelation[]","backrelationCandidates: BackrelationCandidate[]","fields: Record<string, ContractField>","relations: Record<string, ContractReferenceRelation>","valueObjects: Record<string, ContractValueObject>","capabilities: Record<string, Record<string, boolean>>"],"sources":["../src/derive-json-schema.ts","../src/psl-helpers.ts","../src/interpreter.ts"],"sourcesContent":["import type { ContractField, ContractValueObject } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { MongoStorageValidator } from '@prisma-next/mongo-contract';\n\nfunction resolveBsonType(\n codecId: string,\n codecLookup: CodecLookup | undefined,\n): string | undefined {\n const codec = codecLookup?.get(codecId);\n return codec?.targetTypes[0];\n}\n\nfunction fieldToBsonSchema(\n field: ContractField,\n valueObjects: Record<string, ContractValueObject> | undefined,\n codecLookup: CodecLookup | undefined,\n): Record<string, unknown> | undefined {\n if (field.type.kind === 'scalar') {\n const bsonType = resolveBsonType(field.type.codecId, codecLookup);\n if (!bsonType) return undefined;\n\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: { bsonType } };\n }\n\n if (field.nullable) {\n return { bsonType: ['null', bsonType] };\n }\n\n return { bsonType };\n }\n\n if (field.type.kind === 'valueObject') {\n const vo = valueObjects?.[field.type.name];\n if (!vo) return undefined;\n const voSchema = deriveObjectSchema(vo.fields, valueObjects, codecLookup);\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: voSchema };\n }\n if (field.nullable) {\n return { oneOf: [{ bsonType: 'null' }, voSchema] };\n }\n return voSchema;\n }\n\n return undefined;\n}\n\nfunction deriveObjectSchema(\n fields: Record<string, ContractField>,\n valueObjects: Record<string, ContractValueObject> | undefined,\n codecLookup: CodecLookup | undefined,\n): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [fieldName, field] of Object.entries(fields)) {\n const schema = fieldToBsonSchema(field, valueObjects, codecLookup);\n if (schema) {\n properties[fieldName] = schema;\n if (!field.nullable) {\n required.push(fieldName);\n }\n }\n }\n\n const result: Record<string, unknown> = {\n bsonType: 'object',\n properties,\n };\n if (required.length > 0) {\n result['required'] = required.sort();\n }\n return result;\n}\n\nexport function deriveJsonSchema(\n fields: Record<string, ContractField>,\n valueObjects?: Record<string, ContractValueObject>,\n codecLookup?: CodecLookup,\n): MongoStorageValidator {\n return {\n jsonSchema: deriveObjectSchema(fields, valueObjects, codecLookup),\n validationLevel: 'strict',\n validationAction: 'error',\n };\n}\n\nexport interface PolymorphicVariant {\n readonly discriminatorValue: string;\n readonly fields: Record<string, ContractField>;\n}\n\nexport function derivePolymorphicJsonSchema(\n baseFields: Record<string, ContractField>,\n discriminatorField: string,\n variants: readonly PolymorphicVariant[],\n valueObjects?: Record<string, ContractValueObject>,\n codecLookup?: CodecLookup,\n): MongoStorageValidator {\n const baseSchema = deriveObjectSchema(baseFields, valueObjects, codecLookup);\n\n const oneOf: Record<string, unknown>[] = [];\n for (const variant of variants) {\n const variantOnlyFields: Record<string, ContractField> = {};\n for (const [name, field] of Object.entries(variant.fields)) {\n if (!(name in baseFields)) {\n variantOnlyFields[name] = field;\n }\n }\n\n const entry: Record<string, unknown> = {\n properties: {\n [discriminatorField]: { enum: [variant.discriminatorValue] },\n },\n };\n\n const variantProperties: Record<string, unknown> = {};\n const variantRequired: string[] = [discriminatorField];\n for (const [name, field] of Object.entries(variantOnlyFields)) {\n const schema = fieldToBsonSchema(field, valueObjects, codecLookup);\n if (schema) {\n variantProperties[name] = schema;\n if (!field.nullable) {\n variantRequired.push(name);\n }\n }\n }\n\n if (Object.keys(variantProperties).length > 0) {\n (entry['properties'] as Record<string, unknown>) = {\n ...(entry['properties'] as Record<string, unknown>),\n ...variantProperties,\n };\n }\n entry['required'] = variantRequired.sort();\n\n oneOf.push(entry);\n }\n\n const jsonSchema = { ...baseSchema };\n if (oneOf.length > 0) {\n jsonSchema['oneOf'] = oneOf;\n }\n\n return {\n jsonSchema,\n validationLevel: 'strict',\n validationAction: 'error',\n };\n}\n","import type { PslAttribute, PslAttributeArgument } from '@prisma-next/psl-parser';\nimport { getPositionalArgument, parseQuotedStringLiteral } from '@prisma-next/psl-parser';\n\nexport { getPositionalArgument, parseQuotedStringLiteral };\n\nexport function getNamedArgument(attr: PslAttribute, name: string): string | undefined {\n const arg = attr.args.find((a) => a.kind === 'named' && a.name === name);\n return arg?.value;\n}\n\nexport function parseFieldList(value: string): readonly string[] {\n const inner = value.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return [];\n return splitTopLevel(inner).map((s) => s.trim());\n}\n\nexport interface ParsedIndexField {\n readonly name: string;\n readonly isWildcard: boolean;\n readonly direction?: number;\n}\n\nexport function parseIndexFieldList(value: string): readonly ParsedIndexField[] {\n const segments = parseFieldList(value);\n return segments.map(parseIndexFieldSegment);\n}\n\nfunction parseIndexFieldSegment(segment: string): ParsedIndexField {\n const wildcardMatch = segment.match(/^wildcard\\(\\s*(.*?)\\s*\\)$/);\n if (wildcardMatch) {\n const scope = wildcardMatch[1] ?? '';\n return {\n name: scope.length > 0 ? `${scope}.$**` : '$**',\n isWildcard: true,\n };\n }\n\n const modifierMatch = segment.match(/^(\\w+)\\(\\s*sort:\\s*(\\w+)\\s*\\)$/);\n if (modifierMatch) {\n const fieldName = modifierMatch[1] ?? segment;\n const sortValue = modifierMatch[2];\n return {\n name: fieldName,\n isWildcard: false,\n direction: sortValue === 'Desc' ? -1 : 1,\n };\n }\n\n return { name: segment, isWildcard: false };\n}\n\nfunction splitTopLevel(input: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '(' || ch === '[' || ch === '{') depth++;\n else if (ch === ')' || ch === ']' || ch === '}') depth = Math.max(0, depth - 1);\n else if (ch === ',' && depth === 0) {\n parts.push(input.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(input.slice(start));\n return parts;\n}\n\nexport function lowerFirst(value: string): string {\n if (value.length === 0) return value;\n return value[0]?.toLowerCase() + value.slice(1);\n}\n\nexport function getAttribute(\n attributes: readonly PslAttribute[],\n name: string,\n): PslAttribute | undefined {\n return attributes.find((attr) => attr.name === name);\n}\n\nexport function getMapName(attributes: readonly PslAttribute[]): string | undefined {\n const mapAttr = getAttribute(attributes, 'map');\n if (!mapAttr) return undefined;\n const arg = mapAttr.args[0];\n if (!arg) return undefined;\n return stripQuotes(arg.value);\n}\n\nexport interface ParsedRelationAttribute {\n readonly relationName?: string;\n readonly fields?: readonly string[];\n readonly references?: readonly string[];\n}\n\nexport function parseRelationAttribute(\n attributes: readonly PslAttribute[],\n): ParsedRelationAttribute | undefined {\n const relationAttr = getAttribute(attributes, 'relation');\n if (!relationAttr) return undefined;\n\n let relationName: string | undefined;\n let fieldsArg: PslAttributeArgument | undefined;\n let referencesArg: PslAttributeArgument | undefined;\n\n for (const arg of relationAttr.args) {\n if (arg.kind === 'positional') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'name') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'fields') {\n fieldsArg = arg;\n } else if (arg.name === 'references') {\n referencesArg = arg;\n }\n }\n\n const fields = fieldsArg ? parseFieldList(fieldsArg.value) : undefined;\n const references = referencesArg ? parseFieldList(referencesArg.value) : undefined;\n\n return {\n ...(relationName !== undefined ? { relationName } : {}),\n ...(fields !== undefined ? { fields } : {}),\n ...(references !== undefined ? { references } : {}),\n };\n}\n\nfunction stripQuotes(value: string): string {\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n ContractSourceDiagnostic,\n ContractSourceDiagnostics,\n} from '@prisma-next/config/config-types';\nimport { computeProfileHash, computeStorageHash } from '@prisma-next/contract/hashing';\nimport type {\n Contract,\n ContractField,\n ContractReferenceRelation,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { MongoIndexKeyDirection, MongoStorageIndex } from '@prisma-next/mongo-contract';\nimport type { ParsePslDocumentResult, PslField, PslModel } from '@prisma-next/psl-parser';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { deriveJsonSchema, derivePolymorphicJsonSchema } from './derive-json-schema';\nimport {\n getAttribute,\n getMapName,\n getNamedArgument,\n getPositionalArgument,\n lowerFirst,\n parseIndexFieldList,\n parseQuotedStringLiteral,\n parseRelationAttribute,\n} from './psl-helpers';\n\nexport interface InterpretPslDocumentToMongoContractInput {\n readonly document: ParsePslDocumentResult;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n readonly codecLookup?: CodecLookup;\n}\n\ninterface FieldMappings {\n readonly pslNameToMapped: Map<string, string>;\n}\n\ninterface FkRelation {\n readonly declaringModel: string;\n readonly fieldName: string;\n readonly targetModel: string;\n readonly relationName?: string;\n readonly localFields: readonly string[];\n readonly targetFields: readonly string[];\n}\n\nfunction fkRelationPairKey(declaringModel: string, targetModel: string): string {\n return `${declaringModel}::${targetModel}`;\n}\n\nfunction resolveFieldMappings(model: PslModel): FieldMappings {\n const pslNameToMapped = new Map<string, string>();\n for (const field of model.fields) {\n const mapped = getMapName(field.attributes) ?? field.name;\n pslNameToMapped.set(field.name, mapped);\n }\n return { pslNameToMapped };\n}\n\nfunction resolveCollectionName(model: PslModel): string {\n return getMapName(model.attributes) ?? lowerFirst(model.name);\n}\n\ninterface MongoModelEntry {\n readonly fields: Record<string, ContractField>;\n readonly relations: Record<string, ContractReferenceRelation>;\n readonly storage: { readonly collection: string };\n readonly discriminator?: { readonly field: string };\n readonly variants?: Record<string, { readonly value: string }>;\n readonly base?: string;\n}\n\ntype DiscriminatorDeclaration = { readonly fieldName: string; readonly span: PslModel['span'] };\ntype BaseDeclaration = {\n readonly baseName: string;\n readonly value: string;\n readonly collectionName: string;\n readonly span: PslModel['span'];\n};\n\nfunction collectPolymorphismDeclarations(\n document: ParsePslDocumentResult,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): {\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n} {\n const discriminatorDeclarations = new Map<string, DiscriminatorDeclaration>();\n const baseDeclarations = new Map<string, BaseDeclaration>();\n\n for (const pslModel of document.ast.models) {\n for (const attr of pslModel.attributes) {\n if (attr.name === 'discriminator') {\n const fieldName = getPositionalArgument(attr);\n if (!fieldName) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@discriminator requires a field name argument`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const discField = pslModel.fields.find((f) => f.name === fieldName);\n if (discField && discField.typeName !== 'String') {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Discriminator field \"${fieldName}\" on model \"${pslModel.name}\" must be of type String, but is \"${discField.typeName}\"`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n discriminatorDeclarations.set(pslModel.name, { fieldName, span: attr.span });\n }\n if (attr.name === 'base') {\n const baseName = getPositionalArgument(attr, 0);\n const rawValue = getPositionalArgument(attr, 1);\n if (!baseName || !rawValue) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base requires two arguments: base model name and discriminator value`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const value = parseQuotedStringLiteral(rawValue);\n if (value === undefined) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base discriminator value must be a quoted string literal`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const collectionName = resolveCollectionName(pslModel);\n baseDeclarations.set(pslModel.name, { baseName, value, collectionName, span: attr.span });\n }\n }\n }\n\n return { discriminatorDeclarations, baseDeclarations };\n}\n\nfunction resolvePolymorphism(input: {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n collections: Record<string, Record<string, unknown>>;\n document: ParsePslDocumentResult;\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n modelNames: ReadonlySet<string>;\n sourceId: string;\n}): {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n collections: Record<string, Record<string, unknown>>;\n diagnostics: ContractSourceDiagnostic[];\n} {\n const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document } = input;\n let patched = input.models;\n let roots = input.roots;\n let collections = input.collections;\n const diagnostics: ContractSourceDiagnostic[] = [];\n\n for (const [modelName, decl] of discriminatorDeclarations) {\n if (baseDeclarations.has(modelName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_AND_BASE',\n message: `Model \"${modelName}\" cannot have both @@discriminator and @@base`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const model = patched[modelName];\n if (!model) continue;\n\n const pslModel = document.ast.models.find((m) => m.name === modelName);\n const mappedDiscriminatorField = pslModel\n ? (resolveFieldMappings(pslModel).pslNameToMapped.get(decl.fieldName) ?? decl.fieldName)\n : decl.fieldName;\n\n if (!Object.hasOwn(model.fields, mappedDiscriminatorField)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_FIELD_NOT_FOUND',\n message: `Discriminator field \"${decl.fieldName}\" is not a field on model \"${modelName}\"`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const variants: Record<string, { readonly value: string }> = {};\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (baseDecl.baseName !== modelName) continue;\n variants[variantName] = { value: baseDecl.value };\n }\n\n if (Object.keys(variants).length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_DISCRIMINATOR',\n message: `Model \"${modelName}\" has @@discriminator but no variant models declare @@base(${modelName}, ...)`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n patched = {\n ...patched,\n [modelName]: { ...model, discriminator: { field: mappedDiscriminatorField }, variants },\n };\n }\n\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (!modelNames.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_BASE_TARGET_NOT_FOUND',\n message: `Model \"${variantName}\" @@base references non-existent model \"${baseDecl.baseName}\"`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (!discriminatorDeclarations.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BASE',\n message: `Model \"${variantName}\" declares @@base(${baseDecl.baseName}, ...) but \"${baseDecl.baseName}\" has no @@discriminator`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (discriminatorDeclarations.has(variantName)) {\n continue;\n }\n\n const baseModel = patched[baseDecl.baseName];\n const variantPslModel = document.ast.models.find((m) => m.name === variantName);\n if (!variantPslModel) continue;\n const hasExplicitMap = getMapName(variantPslModel.attributes) !== undefined;\n\n if (hasExplicitMap && baseModel && baseDecl.collectionName !== baseModel.storage.collection) {\n diagnostics.push({\n code: 'PSL_MONGO_VARIANT_SEPARATE_COLLECTION',\n message: `Mongo variant \"${variantName}\" cannot use a different collection than its base \"${baseDecl.baseName}\". Mongo only supports single-collection polymorphism.`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n const baseCollection = baseModel?.storage.collection ?? baseDecl.collectionName;\n const variantModel = patched[variantName];\n if (variantModel) {\n patched = {\n ...patched,\n [variantName]: {\n ...variantModel,\n base: baseDecl.baseName,\n storage: { collection: baseCollection },\n },\n };\n }\n\n const variantCollectionName = resolveCollectionName(variantPslModel);\n if (roots[variantCollectionName] === variantName) {\n if (variantCollectionName === baseCollection && baseModel) {\n roots = { ...roots, [variantCollectionName]: baseDecl.baseName };\n } else {\n roots = Object.fromEntries(\n Object.entries(roots).filter(([key]) => key !== variantCollectionName),\n );\n }\n }\n\n const variantColl = collections[variantCollectionName];\n const variantIndexes = (variantColl?.['indexes'] ?? []) as MongoStorageIndex[];\n const baseColl = collections[baseCollection];\n\n if (variantCollectionName !== baseCollection) {\n const filtered = Object.fromEntries(\n Object.entries(collections).filter(([key]) => key !== variantCollectionName),\n );\n if (variantIndexes.length > 0 && baseColl) {\n const baseIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];\n collections = {\n ...filtered,\n [baseCollection]: { ...baseColl, indexes: [...baseIndexes, ...variantIndexes] },\n };\n } else {\n collections = filtered;\n }\n } else if (variantIndexes.length > 0 && baseColl) {\n const baseIndexes = (baseColl['indexes'] ?? []) as MongoStorageIndex[];\n const mergedIndexes = [...baseIndexes];\n for (const idx of variantIndexes) {\n const isDuplicate = baseIndexes.some(\n (existing) => JSON.stringify(existing) === JSON.stringify(idx),\n );\n if (!isDuplicate) {\n mergedIndexes.push(idx);\n }\n }\n if (mergedIndexes.length > baseIndexes.length) {\n collections = {\n ...collections,\n [baseCollection]: { ...baseColl, indexes: mergedIndexes },\n };\n }\n }\n }\n\n return { models: patched, roots, collections, diagnostics };\n}\n\nfunction parseIndexDirection(raw: string | undefined): MongoIndexKeyDirection {\n if (!raw) return 1;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const num = Number(stripped);\n if (num === 1 || num === -1) return num;\n if (['text', '2dsphere', '2d', 'hashed'].includes(stripped))\n return stripped as MongoIndexKeyDirection;\n return 1;\n}\n\nfunction parseNumericArg(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const n = Number(raw);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction parseBooleanArg(raw: string | undefined): boolean | undefined {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n return undefined;\n}\n\nfunction parseJsonArg(raw: string | undefined): Record<string, unknown> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '').replace(/\\\\\"/g, '\"');\n try {\n const parsed = JSON.parse(stripped);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // not valid JSON\n }\n return undefined;\n}\n\nfunction parseCollation(\n attr: import('@prisma-next/psl-parser').PslAttribute,\n): Record<string, unknown> | null | undefined {\n const locale = stripQuotesHelper(getNamedArgument(attr, 'collationLocale'));\n if (!locale) {\n const hasAnyCollationArg =\n getNamedArgument(attr, 'collationStrength') != null ||\n getNamedArgument(attr, 'collationCaseLevel') != null ||\n getNamedArgument(attr, 'collationCaseFirst') != null ||\n getNamedArgument(attr, 'collationNumericOrdering') != null ||\n getNamedArgument(attr, 'collationAlternate') != null ||\n getNamedArgument(attr, 'collationMaxVariable') != null ||\n getNamedArgument(attr, 'collationBackwards') != null ||\n getNamedArgument(attr, 'collationNormalization') != null;\n return hasAnyCollationArg ? null : undefined;\n }\n\n const collation: Record<string, unknown> = { locale };\n const strength = parseNumericArg(getNamedArgument(attr, 'collationStrength'));\n if (strength != null) collation['strength'] = strength;\n const caseLevel = parseBooleanArg(getNamedArgument(attr, 'collationCaseLevel'));\n if (caseLevel != null) collation['caseLevel'] = caseLevel;\n const caseFirst = stripQuotesHelper(getNamedArgument(attr, 'collationCaseFirst'));\n if (caseFirst != null) collation['caseFirst'] = caseFirst;\n const numericOrdering = parseBooleanArg(getNamedArgument(attr, 'collationNumericOrdering'));\n if (numericOrdering != null) collation['numericOrdering'] = numericOrdering;\n const alternate = stripQuotesHelper(getNamedArgument(attr, 'collationAlternate'));\n if (alternate != null) collation['alternate'] = alternate;\n const maxVariable = stripQuotesHelper(getNamedArgument(attr, 'collationMaxVariable'));\n if (maxVariable != null) collation['maxVariable'] = maxVariable;\n const backwards = parseBooleanArg(getNamedArgument(attr, 'collationBackwards'));\n if (backwards != null) collation['backwards'] = backwards;\n const normalization = parseBooleanArg(getNamedArgument(attr, 'collationNormalization'));\n if (normalization != null) collation['normalization'] = normalization;\n return collation;\n}\n\nfunction stripQuotesHelper(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n}\n\nfunction parseProjectionList(\n raw: string | undefined,\n value: 0 | 1,\n): Record<string, 0 | 1> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const inner = stripped.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return undefined;\n const fields = inner\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n const result: Record<string, 0 | 1> = {};\n for (const f of fields) {\n result[f] = value;\n }\n return result;\n}\n\nfunction collectIndexes(\n pslModel: PslModel,\n fieldMappings: FieldMappings,\n modelNames: ReadonlySet<string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): MongoStorageIndex[] {\n const indexes: MongoStorageIndex[] = [];\n let textIndexCount = 0;\n\n for (const field of pslModel.fields) {\n if (modelNames.has(field.typeName)) continue;\n const uniqueAttr = getAttribute(field.attributes, 'unique');\n if (!uniqueAttr) continue;\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n indexes.push({\n keys: [{ field: mappedName, direction: 1 }],\n unique: true,\n });\n }\n\n for (const attr of pslModel.attributes) {\n const isIndex = attr.name === 'index';\n const isUnique = attr.name === 'unique';\n const isTextIndex = attr.name === 'textIndex';\n if (!isIndex && !isUnique && !isTextIndex) continue;\n\n const fieldsArg = getPositionalArgument(attr, 0);\n if (!fieldsArg) continue;\n const parsedFields = parseIndexFieldList(fieldsArg);\n if (parsedFields.length === 0) continue;\n\n const hasWildcard = parsedFields.some((f) => f.isWildcard);\n const wildcardCount = parsedFields.filter((f) => f.isWildcard).length;\n\n if (wildcardCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'An index can contain at most one wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isUnique && hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Unique indexes cannot use wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isTextIndex) {\n textIndexCount++;\n if (textIndexCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `Only one @@textIndex is allowed per collection (model \"${pslModel.name}\")`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n }\n\n const typeArg = getNamedArgument(attr, 'type');\n const defaultDirection: MongoIndexKeyDirection = isTextIndex\n ? 'text'\n : parseIndexDirection(typeArg);\n\n if (\n hasWildcard &&\n typeof defaultDirection === 'string' &&\n ['hashed', '2dsphere', '2d'].includes(defaultDirection)\n ) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (defaultDirection === 'hashed' && parsedFields.length > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Hashed indexes must have exactly one field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const keys = parsedFields.map((pf) => {\n const mappedName = pf.isWildcard\n ? pf.name.replace(/^(.+)\\.\\$\\*\\*$/, (_, prefix: string) => {\n const mapped = fieldMappings.pslNameToMapped.get(prefix);\n return mapped ? `${mapped}.$**` : `${prefix}.$**`;\n })\n : (fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name);\n const direction: MongoIndexKeyDirection =\n pf.direction != null ? (pf.direction as MongoIndexKeyDirection) : defaultDirection;\n return { field: mappedName, direction };\n });\n\n const unique = isUnique ? true : undefined;\n const sparse = isTextIndex ? undefined : parseBooleanArg(getNamedArgument(attr, 'sparse'));\n const expireAfterSeconds = isTextIndex\n ? undefined\n : parseNumericArg(getNamedArgument(attr, 'expireAfterSeconds'));\n\n if (hasWildcard && expireAfterSeconds != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'expireAfterSeconds cannot be combined with wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const partialFilterExpression = parseJsonArg(getNamedArgument(attr, 'filter'));\n\n const includeArg = getNamedArgument(attr, 'include');\n const excludeArg = getNamedArgument(attr, 'exclude');\n\n if (includeArg != null && excludeArg != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Cannot specify both include and exclude on the same index',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if ((includeArg != null || excludeArg != null) && !hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'include/exclude options are only valid when the index contains a wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const wildcardProjection =\n includeArg != null\n ? parseProjectionList(includeArg, 1)\n : excludeArg != null\n ? parseProjectionList(excludeArg, 0)\n : undefined;\n\n const collation = parseCollation(attr);\n if (collation === null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'collationLocale is required when using collation options',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const rawWeights = parseJsonArg(getNamedArgument(attr, 'weights'));\n let weights: Record<string, number> | undefined;\n if (rawWeights) {\n weights = {};\n for (const [k, v] of Object.entries(rawWeights)) {\n if (typeof v === 'number') weights[k] = v;\n }\n }\n\n const rawDefaultLang = isTextIndex\n ? getNamedArgument(attr, 'language')\n : getNamedArgument(attr, 'default_language');\n const default_language = stripQuotesHelper(rawDefaultLang);\n\n const rawLangOverride = getNamedArgument(attr, 'languageOverride');\n const language_override = stripQuotesHelper(rawLangOverride);\n\n const index: MongoStorageIndex = {\n keys,\n ...(unique != null && { unique }),\n ...(sparse != null && { sparse }),\n ...(expireAfterSeconds != null && { expireAfterSeconds }),\n ...(partialFilterExpression != null && { partialFilterExpression }),\n ...(wildcardProjection != null && { wildcardProjection }),\n ...(collation != null && { collation }),\n ...(weights != null && { weights }),\n ...(default_language != null && { default_language }),\n ...(language_override != null && { language_override }),\n };\n\n indexes.push(index);\n }\n\n return indexes;\n}\n\nfunction isRelationField(field: PslField, modelNames: ReadonlySet<string>): boolean {\n return modelNames.has(field.typeName);\n}\n\nfunction resolveFieldCodecId(\n field: PslField,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n): string | undefined {\n return scalarTypeDescriptors.get(field.typeName);\n}\n\nfunction resolveNonRelationField(\n field: PslField,\n ownerName: string,\n compositeTypeNames: ReadonlySet<string>,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): ContractField | undefined {\n if (compositeTypeNames.has(field.typeName)) {\n const result: ContractField = {\n type: { kind: 'valueObject', name: field.typeName },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n }\n\n const codecId = resolveFieldCodecId(field, scalarTypeDescriptors);\n if (!codecId) {\n diagnostics.push({\n code: 'PSL_UNSUPPORTED_FIELD_TYPE',\n message: `Field \"${ownerName}.${field.name}\" type \"${field.typeName}\" is not supported in Mongo PSL interpreter`,\n sourceId,\n span: field.span,\n });\n return undefined;\n }\n\n const result: ContractField = {\n type: { kind: 'scalar', codecId },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n}\n\nexport function interpretPslDocumentToMongoContract(\n input: InterpretPslDocumentToMongoContractInput,\n): Result<Contract, ContractSourceDiagnostics> {\n const { document, scalarTypeDescriptors, codecLookup } = input;\n const sourceId = document.ast.sourceId;\n const diagnostics: ContractSourceDiagnostic[] = [];\n const modelNames = new Set(document.ast.models.map((m) => m.name));\n const compositeTypeNames = new Set(document.ast.compositeTypes.map((ct) => ct.name));\n\n const models: Record<string, MongoModelEntry> = {};\n const collections: Record<string, Record<string, unknown>> = {};\n const roots: Record<string, string> = {};\n const allFkRelations: FkRelation[] = [];\n\n interface BackrelationCandidate {\n readonly modelName: string;\n readonly fieldName: string;\n readonly targetModelName: string;\n readonly relationName?: string;\n readonly cardinality: '1:1' | '1:N';\n readonly field: PslField;\n }\n const backrelationCandidates: BackrelationCandidate[] = [];\n\n for (const pslModel of document.ast.models) {\n const collectionName = resolveCollectionName(pslModel);\n const fieldMappings = resolveFieldMappings(pslModel);\n\n const fields: Record<string, ContractField> = {};\n const relations: Record<string, ContractReferenceRelation> = {};\n\n for (const field of pslModel.fields) {\n if (isRelationField(field, modelNames)) {\n const relation = parseRelationAttribute(field.attributes);\n\n if (field.list || !(relation?.fields && relation?.references)) {\n backrelationCandidates.push({\n modelName: pslModel.name,\n fieldName: field.name,\n targetModelName: field.typeName,\n ...(relation?.relationName !== undefined\n ? { relationName: relation.relationName }\n : {}),\n cardinality: field.list ? '1:N' : '1:1',\n field,\n });\n continue;\n }\n\n if (relation?.fields && relation?.references) {\n const localMapped = relation.fields.map((f) => fieldMappings.pslNameToMapped.get(f) ?? f);\n\n const targetModel = document.ast.models.find((m) => m.name === field.typeName);\n const targetFieldMappings = targetModel ? resolveFieldMappings(targetModel) : undefined;\n const targetMapped = relation.references.map(\n (f) => targetFieldMappings?.pslNameToMapped.get(f) ?? f,\n );\n\n relations[field.name] = {\n to: field.typeName,\n cardinality: 'N:1' as const,\n on: {\n localFields: localMapped,\n targetFields: targetMapped,\n },\n };\n\n allFkRelations.push({\n declaringModel: pslModel.name,\n fieldName: field.name,\n targetModel: field.typeName,\n ...(relation.relationName !== undefined ? { relationName: relation.relationName } : {}),\n localFields: localMapped,\n targetFields: targetMapped,\n });\n }\n continue;\n }\n\n const resolved = resolveNonRelationField(\n field,\n pslModel.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n fields[mappedName] = resolved;\n }\n\n const isVariantModel = pslModel.attributes.some((attr) => attr.name === 'base');\n const hasIdField = pslModel.fields.some((f) => getAttribute(f.attributes, 'id') !== undefined);\n if (!hasIdField && !isVariantModel) {\n diagnostics.push({\n code: 'PSL_MISSING_ID_FIELD',\n message: `Model \"${pslModel.name}\" has no field with @id attribute. Every model must have exactly one @id field.`,\n sourceId,\n });\n }\n\n models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };\n const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);\n const existingColl = collections[collectionName];\n if (existingColl && modelIndexes.length > 0) {\n const existingIndexes = (existingColl['indexes'] ?? []) as MongoStorageIndex[];\n collections[collectionName] = { indexes: [...existingIndexes, ...modelIndexes] };\n } else if (!existingColl) {\n collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};\n }\n roots[collectionName] = pslModel.name;\n }\n\n const valueObjects: Record<string, ContractValueObject> = {};\n for (const compositeType of document.ast.compositeTypes) {\n const fields: Record<string, ContractField> = {};\n for (const field of compositeType.fields) {\n const resolved = resolveNonRelationField(\n field,\n compositeType.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n fields[field.name] = resolved;\n }\n valueObjects[compositeType.name] = { fields };\n }\n\n const fkRelationsByPair = new Map<string, FkRelation[]>();\n for (const fk of allFkRelations) {\n const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);\n const existing = fkRelationsByPair.get(key);\n if (existing) {\n existing.push(fk);\n } else {\n fkRelationsByPair.set(key, [fk]);\n }\n }\n\n for (const candidate of backrelationCandidates) {\n const pairKey = fkRelationPairKey(candidate.targetModelName, candidate.modelName);\n const pairMatches = fkRelationsByPair.get(pairKey) ?? [];\n const matches = candidate.relationName\n ? pairMatches.filter((r) => r.relationName === candidate.relationName)\n : [...pairMatches];\n\n if (matches.length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" has no matching FK-side relation on model \"${candidate.targetModelName}\". Add @relation(fields: [...], references: [...]) on the FK-side relation or use an explicit join model for many-to-many.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n if (matches.length > 1) {\n diagnostics.push({\n code: 'PSL_AMBIGUOUS_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" matches multiple FK-side relations on model \"${candidate.targetModelName}\". Add @relation(\"...\") to both sides to disambiguate.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n\n const fk = matches[0];\n if (!fk) continue;\n const modelEntry = models[candidate.modelName];\n if (!modelEntry) continue;\n modelEntry.relations[candidate.fieldName] = {\n to: candidate.targetModelName,\n cardinality: candidate.cardinality,\n on: {\n localFields: fk.targetFields,\n targetFields: fk.localFields,\n },\n };\n }\n\n const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(\n document,\n sourceId,\n diagnostics,\n );\n const polyResult = resolvePolymorphism({\n models,\n roots,\n collections,\n document,\n discriminatorDeclarations,\n baseDeclarations,\n modelNames,\n sourceId,\n });\n\n if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) {\n return notOk({\n summary: 'PSL to Mongo contract interpretation failed',\n diagnostics: [...diagnostics, ...polyResult.diagnostics],\n });\n }\n\n const resolvedModels = polyResult.models;\n const resolvedCollections = polyResult.collections;\n\n for (const [, modelEntry] of Object.entries(resolvedModels)) {\n if (modelEntry.base) continue;\n\n const collectionName = modelEntry.storage.collection;\n const coll = resolvedCollections[collectionName];\n if (!coll) continue;\n\n if (modelEntry.discriminator && modelEntry.variants) {\n const variantEntries = Object.entries(modelEntry.variants).map(\n ([variantName, { value }]) => ({\n discriminatorValue: value,\n fields: resolvedModels[variantName]?.fields ?? {},\n }),\n );\n coll['validator'] = derivePolymorphicJsonSchema(\n modelEntry.fields,\n modelEntry.discriminator.field,\n variantEntries,\n valueObjects,\n codecLookup,\n );\n } else {\n coll['validator'] = deriveJsonSchema(modelEntry.fields, valueObjects, codecLookup);\n }\n }\n\n const target = 'mongo';\n const targetFamily = 'mongo';\n const storageWithoutHash = { collections: resolvedCollections };\n const storageHash = computeStorageHash({ target, targetFamily, storage: storageWithoutHash });\n const capabilities: Record<string, Record<string, boolean>> = {};\n\n return ok({\n targetFamily,\n target,\n roots: polyResult.roots,\n models: polyResult.models,\n ...(Object.keys(valueObjects).length > 0 ? { valueObjects } : {}),\n storage: { ...storageWithoutHash, storageHash },\n extensionPacks: {},\n capabilities,\n profileHash: computeProfileHash({ target, targetFamily, capabilities }),\n meta: {},\n });\n}\n"],"mappings":"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"}