@prisma/orm-family-mongo 8.0.0-rc.8-dev.2 → 8.0.0-rc.8-dev.3
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.
- package/dist/contract-psl.mjs +1 -1
- package/dist/contract-psl__provider.mjs +1 -1
- package/dist/contract-psl__provider.mjs.map +1 -1
- package/dist/{interpreter-BxbUTQ3k-ClR98Ned.mjs → interpreter-O09WlHk7-BiV9gBae.mjs} +494 -363
- package/dist/interpreter-O09WlHk7-BiV9gBae.mjs.map +1 -0
- package/package.json +19 -19
- package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs.map +0 -1
|
@@ -7,11 +7,11 @@ import { blindCast } from "@prisma/orm-framework/utils/casts";
|
|
|
7
7
|
import { computeProfileHash, computeStorageHash } from "@prisma/orm-framework/contract/hashing";
|
|
8
8
|
import { errorEnumCodecNotInPackStack } from "@prisma/orm-framework/errors/control";
|
|
9
9
|
import { instantiateAuthoringEntityType, isAuthoringEntityTypeDescriptor } from "@prisma/orm-framework/components/authoring";
|
|
10
|
-
import { nodePslSpan,
|
|
10
|
+
import { bool, entityRef, fieldAttribute, fieldRef, funcCall, identifier, int, interpretAttribute, json, list, modelAttribute, nodePslSpan, num, oneOf, optional, record, str } from "@prisma/orm-framework/psl-parser";
|
|
11
11
|
import { assertDefined } from "@prisma/orm-framework/utils/assertions";
|
|
12
12
|
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
13
13
|
import { notOk, ok } from "@prisma/orm-framework/utils/result";
|
|
14
|
-
//#region ../../../2-mongo-family/2-authoring/contract-psl/dist/interpreter-
|
|
14
|
+
//#region ../../../2-mongo-family/2-authoring/contract-psl/dist/interpreter-O09WlHk7.mjs
|
|
15
15
|
function resolveBsonType(codecId, codecLookup) {
|
|
16
16
|
return codecLookup?.targetTypesFor(codecId)?.[0];
|
|
17
17
|
}
|
|
@@ -113,91 +113,166 @@ function derivePolymorphicJsonSchema(baseFields, discriminatorField, variants, v
|
|
|
113
113
|
validationAction: "error"
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
|
-
function
|
|
117
|
-
|
|
116
|
+
function findModelAttributeNode(model, name) {
|
|
117
|
+
for (const attribute of model.node.attributes()) if (attribute.name()?.isSimpleName(name) === true) return attribute;
|
|
118
118
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
119
|
+
function findFieldAttributeNode(field, name) {
|
|
120
|
+
for (const attribute of field.node.attributes()) if (attribute.name()?.isSimpleName(name) === true) return attribute;
|
|
121
121
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
function parseIndexFieldSegment(segment) {
|
|
131
|
-
const wildcardMatch = segment.match(/^wildcard\(\s*(.*?)\s*\)$/);
|
|
132
|
-
if (wildcardMatch) {
|
|
133
|
-
const scope = wildcardMatch[1] ?? "";
|
|
134
|
-
return {
|
|
135
|
-
name: scope.length > 0 ? `${scope}.$**` : "$**",
|
|
136
|
-
isWildcard: true
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
const modifierMatch = segment.match(/^(\w+)\(\s*sort:\s*(\w+)\s*\)$/);
|
|
140
|
-
if (modifierMatch) return {
|
|
141
|
-
name: modifierMatch[1] ?? segment,
|
|
142
|
-
isWildcard: false,
|
|
143
|
-
direction: modifierMatch[2] === "Desc" ? -1 : 1
|
|
122
|
+
function buildModelInterpretCtx(input) {
|
|
123
|
+
return {
|
|
124
|
+
level: "model",
|
|
125
|
+
sourceId: input.sourceId,
|
|
126
|
+
sourceFile: input.sourceFile,
|
|
127
|
+
selfModel: input.selfModel,
|
|
128
|
+
resolveReferencedModel: () => void 0
|
|
144
129
|
};
|
|
130
|
+
}
|
|
131
|
+
function buildFieldInterpretCtx(input) {
|
|
145
132
|
return {
|
|
146
|
-
|
|
147
|
-
|
|
133
|
+
level: "field",
|
|
134
|
+
sourceId: input.sourceId,
|
|
135
|
+
sourceFile: input.sourceFile,
|
|
136
|
+
selfModel: input.selfModel,
|
|
137
|
+
resolveReferencedModel: input.resolveReferencedModel ?? (() => void 0),
|
|
138
|
+
field: input.field
|
|
148
139
|
};
|
|
149
140
|
}
|
|
150
|
-
function
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
parts.push(input.slice(start, i));
|
|
160
|
-
start = i + 1;
|
|
161
|
-
}
|
|
141
|
+
function interpretModelAttribute(input) {
|
|
142
|
+
const result = interpretAttribute(input.node, input.spec, buildModelInterpretCtx({
|
|
143
|
+
selfModel: input.model,
|
|
144
|
+
sourceFile: input.sourceFile,
|
|
145
|
+
sourceId: input.sourceId
|
|
146
|
+
}));
|
|
147
|
+
if (!result.ok) {
|
|
148
|
+
for (const failure of result.failure) input.diagnostics.push(failure);
|
|
149
|
+
return;
|
|
162
150
|
}
|
|
163
|
-
|
|
164
|
-
return parts;
|
|
151
|
+
return result.value;
|
|
165
152
|
}
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
153
|
+
function interpretFieldAttribute(input) {
|
|
154
|
+
const result = interpretAttribute(input.node, input.spec, buildFieldInterpretCtx({
|
|
155
|
+
selfModel: input.model,
|
|
156
|
+
field: input.field,
|
|
157
|
+
sourceFile: input.sourceFile,
|
|
158
|
+
sourceId: input.sourceId,
|
|
159
|
+
resolveReferencedModel: input.resolveReferencedModel
|
|
160
|
+
}));
|
|
161
|
+
if (!result.ok) {
|
|
162
|
+
for (const failure of result.failure) input.diagnostics.push(failure);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
return result.value;
|
|
169
166
|
}
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
const mapModelSpec = modelAttribute("map", { positional: [{
|
|
168
|
+
key: "name",
|
|
169
|
+
type: str()
|
|
170
|
+
}] });
|
|
171
|
+
const mapFieldSpec = fieldAttribute("map", { positional: [{
|
|
172
|
+
key: "name",
|
|
173
|
+
type: str()
|
|
174
|
+
}] });
|
|
175
|
+
const relationFieldSpec = fieldAttribute("relation", {
|
|
176
|
+
positional: [{
|
|
177
|
+
key: "name",
|
|
178
|
+
type: optional(str())
|
|
179
|
+
}],
|
|
180
|
+
named: {
|
|
181
|
+
name: optional(str()),
|
|
182
|
+
fields: optional(list(fieldRef("self"), {
|
|
183
|
+
nonEmpty: true,
|
|
184
|
+
unique: true
|
|
185
|
+
})),
|
|
186
|
+
references: optional(list(fieldRef("referenced"), {
|
|
187
|
+
nonEmpty: true,
|
|
188
|
+
unique: true
|
|
189
|
+
}))
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
const discriminatorModelSpec = modelAttribute("discriminator", { positional: [{
|
|
193
|
+
key: "field",
|
|
194
|
+
type: fieldRef("self")
|
|
195
|
+
}] });
|
|
196
|
+
const baseModelSpec = modelAttribute("base", { positional: [{
|
|
197
|
+
key: "base",
|
|
198
|
+
type: entityRef()
|
|
199
|
+
}, {
|
|
200
|
+
key: "value",
|
|
201
|
+
type: str()
|
|
202
|
+
}] });
|
|
203
|
+
const sortSig = { named: { sort: oneOf(identifier("Asc"), identifier("Desc")) } };
|
|
204
|
+
function indexFieldElement(fieldNames) {
|
|
205
|
+
return oneOf(...[
|
|
206
|
+
fieldRef("self"),
|
|
207
|
+
funcCall("wildcard", { positional: [{
|
|
208
|
+
key: "scope",
|
|
209
|
+
type: optional(entityRef())
|
|
210
|
+
}] }),
|
|
211
|
+
...fieldNames.map((name) => funcCall(name, sortSig))
|
|
212
|
+
]);
|
|
172
213
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
214
|
+
const collationNamedArgs = {
|
|
215
|
+
collationLocale: optional(str()),
|
|
216
|
+
collationStrength: optional(oneOf(num(1), num(2), num(3), num(4), num(5))),
|
|
217
|
+
collationCaseLevel: optional(bool()),
|
|
218
|
+
collationCaseFirst: optional(oneOf(str("upper"), str("lower"), str("off"))),
|
|
219
|
+
collationNumericOrdering: optional(bool()),
|
|
220
|
+
collationAlternate: optional(oneOf(str("non-ignorable"), str("shifted"))),
|
|
221
|
+
collationMaxVariable: optional(oneOf(str("punct"), str("space"))),
|
|
222
|
+
collationBackwards: optional(bool()),
|
|
223
|
+
collationNormalization: optional(bool())
|
|
224
|
+
};
|
|
225
|
+
function buildIndexModelSpec(name, fieldElement) {
|
|
226
|
+
return modelAttribute(name, {
|
|
227
|
+
positional: [{
|
|
228
|
+
key: "fields",
|
|
229
|
+
type: list(fieldElement, { nonEmpty: true })
|
|
230
|
+
}],
|
|
231
|
+
named: {
|
|
232
|
+
type: optional(oneOf(num(1), num(-1), str("text"), str("2dsphere"), str("2d"), str("hashed"))),
|
|
233
|
+
sparse: optional(bool()),
|
|
234
|
+
expireAfterSeconds: optional(int()),
|
|
235
|
+
filter: optional(json()),
|
|
236
|
+
include: optional(list(str())),
|
|
237
|
+
exclude: optional(list(str())),
|
|
238
|
+
default_language: optional(str()),
|
|
239
|
+
languageOverride: optional(str()),
|
|
240
|
+
...collationNamedArgs
|
|
241
|
+
}
|
|
242
|
+
});
|
|
179
243
|
}
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
244
|
+
function buildTextIndexModelSpec(fieldElement) {
|
|
245
|
+
return modelAttribute("textIndex", {
|
|
246
|
+
positional: [{
|
|
247
|
+
key: "fields",
|
|
248
|
+
type: list(fieldElement, { nonEmpty: true })
|
|
249
|
+
}],
|
|
250
|
+
named: {
|
|
251
|
+
filter: optional(json()),
|
|
252
|
+
weights: optional(record(int({
|
|
253
|
+
min: 1,
|
|
254
|
+
max: 99999
|
|
255
|
+
}))),
|
|
256
|
+
language: optional(str()),
|
|
257
|
+
languageOverride: optional(str()),
|
|
258
|
+
...collationNamedArgs
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function buildIndexModelSpecs(fieldNames) {
|
|
263
|
+
const fieldElement = indexFieldElement(fieldNames);
|
|
192
264
|
return {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
265
|
+
index: buildIndexModelSpec("index", fieldElement),
|
|
266
|
+
unique: buildIndexModelSpec("unique", fieldElement),
|
|
267
|
+
textIndex: buildTextIndexModelSpec(fieldElement)
|
|
196
268
|
};
|
|
197
269
|
}
|
|
198
|
-
function
|
|
199
|
-
if (value.
|
|
200
|
-
return value;
|
|
270
|
+
function lowerFirst(value) {
|
|
271
|
+
if (value.length === 0) return value;
|
|
272
|
+
return value[0]?.toLowerCase() + value.slice(1);
|
|
273
|
+
}
|
|
274
|
+
function getAttribute(attributes, name) {
|
|
275
|
+
return attributes.find((attr) => attr.name === name);
|
|
201
276
|
}
|
|
202
277
|
/**
|
|
203
278
|
* Encode an authored enum value to its codec-encoded JSON form via the codec resolved by id from the
|
|
@@ -226,79 +301,87 @@ function validateNamespaceBlocksForMongoTarget(input) {
|
|
|
226
301
|
function fkRelationPairKey(declaringModel, targetModel) {
|
|
227
302
|
return `${declaringModel}::${targetModel}`;
|
|
228
303
|
}
|
|
229
|
-
function resolveFieldMappings(
|
|
304
|
+
function resolveFieldMappings(input) {
|
|
305
|
+
const { model, sourceFile, sourceId, diagnostics } = input;
|
|
230
306
|
const pslNameToMapped = /* @__PURE__ */ new Map();
|
|
231
307
|
for (const field of Object.values(model.fields)) {
|
|
232
|
-
const
|
|
308
|
+
const mapNode = findFieldAttributeNode(field, "map");
|
|
309
|
+
const mapped = (mapNode ? interpretFieldAttribute({
|
|
310
|
+
node: mapNode,
|
|
311
|
+
spec: mapFieldSpec,
|
|
312
|
+
model,
|
|
313
|
+
field,
|
|
314
|
+
sourceFile,
|
|
315
|
+
sourceId,
|
|
316
|
+
diagnostics
|
|
317
|
+
})?.name : void 0) ?? field.name;
|
|
233
318
|
pslNameToMapped.set(field.name, mapped);
|
|
234
319
|
}
|
|
235
320
|
return { pslNameToMapped };
|
|
236
321
|
}
|
|
237
|
-
function resolveCollectionName(
|
|
238
|
-
|
|
322
|
+
function resolveCollectionName(input) {
|
|
323
|
+
const { model, sourceFile, sourceId, diagnostics } = input;
|
|
324
|
+
const mapNode = findModelAttributeNode(model, "map");
|
|
325
|
+
return (mapNode ? interpretModelAttribute({
|
|
326
|
+
node: mapNode,
|
|
327
|
+
spec: mapModelSpec,
|
|
328
|
+
model,
|
|
329
|
+
sourceFile,
|
|
330
|
+
sourceId,
|
|
331
|
+
diagnostics
|
|
332
|
+
})?.name : void 0) ?? lowerFirst(model.name);
|
|
239
333
|
}
|
|
240
334
|
function mongoCrossRef(modelName) {
|
|
241
335
|
return crossRef(modelName, UNBOUND_NAMESPACE_ID);
|
|
242
336
|
}
|
|
243
|
-
function collectPolymorphismDeclarations(models, sourceId, diagnostics) {
|
|
337
|
+
function collectPolymorphismDeclarations(models, modelMetadataByName, sourceFile, sourceId, diagnostics) {
|
|
244
338
|
const discriminatorDeclarations = /* @__PURE__ */ new Map();
|
|
245
339
|
const baseDeclarations = /* @__PURE__ */ new Map();
|
|
246
|
-
for (const model of models)
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
diagnostics.push({
|
|
340
|
+
for (const model of models) {
|
|
341
|
+
const discNode = findModelAttributeNode(model, "discriminator");
|
|
342
|
+
if (discNode) {
|
|
343
|
+
const parsed = interpretModelAttribute({
|
|
344
|
+
node: discNode,
|
|
345
|
+
spec: discriminatorModelSpec,
|
|
346
|
+
model,
|
|
347
|
+
sourceFile,
|
|
348
|
+
sourceId,
|
|
349
|
+
diagnostics
|
|
350
|
+
});
|
|
351
|
+
if (parsed) {
|
|
352
|
+
const fieldName = parsed.field;
|
|
353
|
+
const discField = model.fields[fieldName];
|
|
354
|
+
if (discField && discField.typeName !== "String") diagnostics.push({
|
|
261
355
|
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
262
356
|
message: `Discriminator field "${fieldName}" on model "${model.name}" must be of type String, but is "${discField.typeName}"`,
|
|
263
357
|
sourceId,
|
|
264
|
-
span:
|
|
358
|
+
span: nodePslSpan(discNode.syntax, sourceFile)
|
|
265
359
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
fieldName,
|
|
270
|
-
span: attr.span
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
if (attr.name === "base") {
|
|
274
|
-
const baseName = getPositionalArgument(attr, 0);
|
|
275
|
-
const rawValue = getPositionalArgument(attr, 1);
|
|
276
|
-
if (!baseName || !rawValue) {
|
|
277
|
-
diagnostics.push({
|
|
278
|
-
code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
|
|
279
|
-
message: `Model "${model.name}" @@base requires two arguments: base model name and discriminator value`,
|
|
280
|
-
sourceId,
|
|
281
|
-
span: attr.span
|
|
360
|
+
else discriminatorDeclarations.set(model.name, {
|
|
361
|
+
fieldName,
|
|
362
|
+
span: nodePslSpan(discNode.syntax, sourceFile)
|
|
282
363
|
});
|
|
283
|
-
continue;
|
|
284
364
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
365
|
+
}
|
|
366
|
+
const baseNode = findModelAttributeNode(model, "base");
|
|
367
|
+
if (baseNode) {
|
|
368
|
+
const parsed = interpretModelAttribute({
|
|
369
|
+
node: baseNode,
|
|
370
|
+
spec: baseModelSpec,
|
|
371
|
+
model,
|
|
372
|
+
sourceFile,
|
|
373
|
+
sourceId,
|
|
374
|
+
diagnostics
|
|
375
|
+
});
|
|
376
|
+
if (parsed) {
|
|
377
|
+
const collectionName = modelMetadataByName.get(model.name)?.collectionName ?? lowerFirst(model.name);
|
|
378
|
+
baseDeclarations.set(model.name, {
|
|
379
|
+
baseName: parsed.base,
|
|
380
|
+
value: parsed.value,
|
|
381
|
+
collectionName,
|
|
382
|
+
span: nodePslSpan(baseNode.syntax, sourceFile)
|
|
292
383
|
});
|
|
293
|
-
continue;
|
|
294
384
|
}
|
|
295
|
-
const collectionName = resolveCollectionName(model);
|
|
296
|
-
baseDeclarations.set(model.name, {
|
|
297
|
-
baseName,
|
|
298
|
-
value,
|
|
299
|
-
collectionName,
|
|
300
|
-
span: attr.span
|
|
301
|
-
});
|
|
302
385
|
}
|
|
303
386
|
}
|
|
304
387
|
return {
|
|
@@ -307,7 +390,7 @@ function collectPolymorphismDeclarations(models, sourceId, diagnostics) {
|
|
|
307
390
|
};
|
|
308
391
|
}
|
|
309
392
|
function resolvePolymorphism(input) {
|
|
310
|
-
const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, allModels: allModelViews, indexSpans, modelIndexesByName } = input;
|
|
393
|
+
const { discriminatorDeclarations, baseDeclarations, modelNames, modelMetadataByName, sourceId, allModels: allModelViews, indexSpans, modelIndexesByName } = input;
|
|
311
394
|
let patched = input.models;
|
|
312
395
|
let roots = input.roots;
|
|
313
396
|
let collections = input.collections;
|
|
@@ -324,8 +407,7 @@ function resolvePolymorphism(input) {
|
|
|
324
407
|
}
|
|
325
408
|
const model = patched[modelName];
|
|
326
409
|
if (!model) continue;
|
|
327
|
-
const
|
|
328
|
-
const mappedDiscriminatorField = modelView ? resolveFieldMappings(modelView).pslNameToMapped.get(decl.fieldName) ?? decl.fieldName : decl.fieldName;
|
|
410
|
+
const mappedDiscriminatorField = modelMetadataByName.get(modelName)?.fieldMappings.pslNameToMapped.get(decl.fieldName) ?? decl.fieldName;
|
|
329
411
|
if (!Object.hasOwn(model.fields, mappedDiscriminatorField)) {
|
|
330
412
|
diagnostics.push({
|
|
331
413
|
code: "PSL_DISCRIMINATOR_FIELD_NOT_FOUND",
|
|
@@ -381,7 +463,7 @@ function resolvePolymorphism(input) {
|
|
|
381
463
|
const baseModel = patched[baseDecl.baseName];
|
|
382
464
|
const variantModelView = allModelViews.find((m) => m.name === variantName);
|
|
383
465
|
if (!variantModelView) continue;
|
|
384
|
-
if (
|
|
466
|
+
if (getAttribute(variantModelView.attributes, "map") !== void 0 && baseModel && baseDecl.collectionName !== baseModel.storage.collection) {
|
|
385
467
|
diagnostics.push({
|
|
386
468
|
code: "PSL_MONGO_VARIANT_SEPARATE_COLLECTION",
|
|
387
469
|
message: `Mongo variant "${variantName}" cannot use a different collection than its base "${baseDecl.baseName}". Mongo only supports single-collection polymorphism.`,
|
|
@@ -400,7 +482,7 @@ function resolvePolymorphism(input) {
|
|
|
400
482
|
storage: { collection: baseCollection }
|
|
401
483
|
}
|
|
402
484
|
};
|
|
403
|
-
const variantCollectionName =
|
|
485
|
+
const variantCollectionName = modelMetadataByName.get(variantName)?.collectionName ?? lowerFirst(variantName);
|
|
404
486
|
if (roots[variantCollectionName]?.model === variantName) if (variantCollectionName === baseCollection && baseModel) roots = {
|
|
405
487
|
...roots,
|
|
406
488
|
[variantCollectionName]: mongoCrossRef(baseDecl.baseName)
|
|
@@ -432,7 +514,7 @@ function resolvePolymorphism(input) {
|
|
|
432
514
|
if (variantCollectionName !== baseCollection) {
|
|
433
515
|
const filtered = Object.fromEntries(Object.entries(collections).filter(([key]) => key !== variantCollectionName));
|
|
434
516
|
if (scopedVariantIndexes.length > 0 && baseColl) {
|
|
435
|
-
const baseIndexes = baseColl
|
|
517
|
+
const baseIndexes = collectionIndexes(baseColl);
|
|
436
518
|
collections = {
|
|
437
519
|
...filtered,
|
|
438
520
|
[baseCollection]: {
|
|
@@ -442,7 +524,7 @@ function resolvePolymorphism(input) {
|
|
|
442
524
|
};
|
|
443
525
|
} else collections = filtered;
|
|
444
526
|
} else if (baseColl) {
|
|
445
|
-
const existingIndexes = baseColl
|
|
527
|
+
const existingIndexes = collectionIndexes(baseColl);
|
|
446
528
|
const variantIndexSet = new Set(variantOwnIndexes);
|
|
447
529
|
const withoutUnscopedVariants = existingIndexes.filter((idx) => !variantIndexSet.has(idx));
|
|
448
530
|
const mergedIndexes = [...withoutUnscopedVariants];
|
|
@@ -468,84 +550,225 @@ function resolvePolymorphism(input) {
|
|
|
468
550
|
diagnostics
|
|
469
551
|
};
|
|
470
552
|
}
|
|
553
|
+
function collectionIndexes(collection) {
|
|
554
|
+
return blindCast(collection["indexes"] ?? []);
|
|
555
|
+
}
|
|
471
556
|
function canonicalJson(value) {
|
|
472
557
|
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
473
558
|
if (value && typeof value === "object") return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
|
|
474
559
|
return JSON.stringify(value);
|
|
475
560
|
}
|
|
476
|
-
function
|
|
477
|
-
if (
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if ([
|
|
482
|
-
"
|
|
483
|
-
"
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
function parseBooleanArg(raw) {
|
|
495
|
-
if (raw === "true") return true;
|
|
496
|
-
if (raw === "false") return false;
|
|
497
|
-
}
|
|
498
|
-
function parseJsonArg(raw) {
|
|
499
|
-
if (!raw) return void 0;
|
|
500
|
-
const stripped = raw.replace(/^["']/, "").replace(/["']$/, "").replace(/\\"/g, "\"");
|
|
501
|
-
try {
|
|
502
|
-
const parsed = JSON.parse(stripped);
|
|
503
|
-
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
|
|
504
|
-
} catch {}
|
|
561
|
+
function normalizeIndexField(element) {
|
|
562
|
+
if (typeof element === "string") return {
|
|
563
|
+
kind: "field",
|
|
564
|
+
name: element
|
|
565
|
+
};
|
|
566
|
+
if (element.fn === "wildcard" && element.args["sort"] === void 0) {
|
|
567
|
+
const scope = element.args["scope"];
|
|
568
|
+
return typeof scope === "string" ? {
|
|
569
|
+
kind: "wildcard",
|
|
570
|
+
scope
|
|
571
|
+
} : { kind: "wildcard" };
|
|
572
|
+
}
|
|
573
|
+
const sort = element.args["sort"];
|
|
574
|
+
return {
|
|
575
|
+
kind: "field",
|
|
576
|
+
name: element.fn,
|
|
577
|
+
direction: sort === "Desc" ? -1 : 1
|
|
578
|
+
};
|
|
505
579
|
}
|
|
506
|
-
function
|
|
507
|
-
const locale =
|
|
508
|
-
if (
|
|
580
|
+
function buildCollationFromSpec(args) {
|
|
581
|
+
const locale = args.collationLocale;
|
|
582
|
+
if (locale === void 0) return args.collationStrength !== void 0 || args.collationCaseLevel !== void 0 || args.collationCaseFirst !== void 0 || args.collationNumericOrdering !== void 0 || args.collationAlternate !== void 0 || args.collationMaxVariable !== void 0 || args.collationBackwards !== void 0 || args.collationNormalization !== void 0 ? null : void 0;
|
|
509
583
|
const collation = { locale };
|
|
510
|
-
|
|
511
|
-
if (
|
|
512
|
-
|
|
513
|
-
if (
|
|
514
|
-
|
|
515
|
-
if (
|
|
516
|
-
|
|
517
|
-
if (
|
|
518
|
-
const alternate = stripQuotesHelper(getNamedArgument(attr, "collationAlternate"));
|
|
519
|
-
if (alternate != null) collation.alternate = alternate;
|
|
520
|
-
const maxVariable = stripQuotesHelper(getNamedArgument(attr, "collationMaxVariable"));
|
|
521
|
-
if (maxVariable != null) collation.maxVariable = maxVariable;
|
|
522
|
-
const backwards = parseBooleanArg(getNamedArgument(attr, "collationBackwards"));
|
|
523
|
-
if (backwards != null) collation.backwards = backwards;
|
|
524
|
-
const normalization = parseBooleanArg(getNamedArgument(attr, "collationNormalization"));
|
|
525
|
-
if (normalization != null) collation.normalization = normalization;
|
|
584
|
+
if (args.collationStrength !== void 0) collation.strength = args.collationStrength;
|
|
585
|
+
if (args.collationCaseLevel !== void 0) collation.caseLevel = args.collationCaseLevel;
|
|
586
|
+
if (args.collationCaseFirst !== void 0) collation.caseFirst = args.collationCaseFirst;
|
|
587
|
+
if (args.collationNumericOrdering !== void 0) collation.numericOrdering = args.collationNumericOrdering;
|
|
588
|
+
if (args.collationAlternate !== void 0) collation.alternate = args.collationAlternate;
|
|
589
|
+
if (args.collationMaxVariable !== void 0) collation.maxVariable = args.collationMaxVariable;
|
|
590
|
+
if (args.collationBackwards !== void 0) collation.backwards = args.collationBackwards;
|
|
591
|
+
if (args.collationNormalization !== void 0) collation.normalization = args.collationNormalization;
|
|
526
592
|
return collation;
|
|
527
593
|
}
|
|
528
|
-
function
|
|
529
|
-
|
|
530
|
-
|
|
594
|
+
function resolveIndexKeys(parsedFields, defaultDirection, ctx) {
|
|
595
|
+
const wildcardCount = parsedFields.filter((field) => field.kind === "wildcard").length;
|
|
596
|
+
if (wildcardCount > 1) {
|
|
597
|
+
ctx.diagnostics.push({
|
|
598
|
+
code: "PSL_INVALID_INDEX",
|
|
599
|
+
message: "An index can contain at most one wildcard() field",
|
|
600
|
+
sourceId: ctx.sourceId,
|
|
601
|
+
span: ctx.span
|
|
602
|
+
});
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
for (const field of parsedFields) {
|
|
606
|
+
const fieldName = field.kind === "wildcard" ? field.scope : field.name;
|
|
607
|
+
if (fieldName !== void 0 && !ctx.indexableFieldNames.has(fieldName)) {
|
|
608
|
+
ctx.diagnostics.push({
|
|
609
|
+
code: "PSL_INDEX_FIELD_NOT_FOUND",
|
|
610
|
+
message: `Index on model "${ctx.pslModel.name}" references unknown field "${fieldName}"`,
|
|
611
|
+
sourceId: ctx.sourceId,
|
|
612
|
+
span: ctx.span
|
|
613
|
+
});
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
keys: parsedFields.map((field) => {
|
|
619
|
+
if (field.kind === "wildcard") {
|
|
620
|
+
if (field.scope === void 0) return {
|
|
621
|
+
field: "$**",
|
|
622
|
+
direction: defaultDirection
|
|
623
|
+
};
|
|
624
|
+
return {
|
|
625
|
+
field: `${ctx.fieldMappings.pslNameToMapped.get(field.scope) ?? field.scope}.$**`,
|
|
626
|
+
direction: defaultDirection
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
return {
|
|
630
|
+
field: ctx.fieldMappings.pslNameToMapped.get(field.name) ?? field.name,
|
|
631
|
+
direction: field.direction ?? defaultDirection
|
|
632
|
+
};
|
|
633
|
+
}),
|
|
634
|
+
hasWildcard: wildcardCount === 1
|
|
635
|
+
};
|
|
531
636
|
}
|
|
532
|
-
function
|
|
533
|
-
if (
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
637
|
+
function buildProjection(include, exclude, hasWildcard, ctx) {
|
|
638
|
+
if (include !== void 0 && exclude !== void 0) {
|
|
639
|
+
ctx.diagnostics.push({
|
|
640
|
+
code: "PSL_INVALID_INDEX",
|
|
641
|
+
message: "Cannot specify both include and exclude on the same index",
|
|
642
|
+
sourceId: ctx.sourceId,
|
|
643
|
+
span: ctx.span
|
|
644
|
+
});
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
const fields = include ?? exclude;
|
|
648
|
+
if (fields === void 0) return void 0;
|
|
649
|
+
if (!hasWildcard) {
|
|
650
|
+
ctx.diagnostics.push({
|
|
651
|
+
code: "PSL_INVALID_INDEX",
|
|
652
|
+
message: "include/exclude options are only valid when the index contains a wildcard() field",
|
|
653
|
+
sourceId: ctx.sourceId,
|
|
654
|
+
span: ctx.span
|
|
655
|
+
});
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
if (fields.length === 0) return void 0;
|
|
659
|
+
const value = include === void 0 ? 0 : 1;
|
|
660
|
+
const projection = {};
|
|
661
|
+
for (const field of fields) projection[field] = value;
|
|
662
|
+
return projection;
|
|
663
|
+
}
|
|
664
|
+
function buildNormalIndex(parsed, unique, ctx) {
|
|
665
|
+
const parsedFields = parsed.fields.map(normalizeIndexField);
|
|
666
|
+
if (parsedFields.length === 0) return void 0;
|
|
667
|
+
const defaultDirection = parsed.type ?? 1;
|
|
668
|
+
const resolved = resolveIndexKeys(parsedFields, defaultDirection, ctx);
|
|
669
|
+
if (!resolved) return void 0;
|
|
670
|
+
if (unique && resolved.hasWildcard) {
|
|
671
|
+
ctx.diagnostics.push({
|
|
672
|
+
code: "PSL_INVALID_INDEX",
|
|
673
|
+
message: "Unique indexes cannot use wildcard() fields",
|
|
674
|
+
sourceId: ctx.sourceId,
|
|
675
|
+
span: ctx.span
|
|
676
|
+
});
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (resolved.hasWildcard && typeof defaultDirection === "string" && [
|
|
680
|
+
"hashed",
|
|
681
|
+
"2dsphere",
|
|
682
|
+
"2d"
|
|
683
|
+
].includes(defaultDirection)) {
|
|
684
|
+
ctx.diagnostics.push({
|
|
685
|
+
code: "PSL_INVALID_INDEX",
|
|
686
|
+
message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,
|
|
687
|
+
sourceId: ctx.sourceId,
|
|
688
|
+
span: ctx.span
|
|
689
|
+
});
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
if (defaultDirection === "hashed" && parsedFields.length > 1) {
|
|
693
|
+
ctx.diagnostics.push({
|
|
694
|
+
code: "PSL_INVALID_INDEX",
|
|
695
|
+
message: "Hashed indexes must have exactly one field",
|
|
696
|
+
sourceId: ctx.sourceId,
|
|
697
|
+
span: ctx.span
|
|
698
|
+
});
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if (resolved.hasWildcard && parsed.expireAfterSeconds !== void 0) {
|
|
702
|
+
ctx.diagnostics.push({
|
|
703
|
+
code: "PSL_INVALID_INDEX",
|
|
704
|
+
message: "expireAfterSeconds cannot be combined with wildcard() fields",
|
|
705
|
+
sourceId: ctx.sourceId,
|
|
706
|
+
span: ctx.span
|
|
707
|
+
});
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const wildcardProjection = buildProjection(parsed.include, parsed.exclude, resolved.hasWildcard, ctx);
|
|
711
|
+
if (wildcardProjection === null) return void 0;
|
|
712
|
+
const collation = buildCollationFromSpec(parsed);
|
|
713
|
+
if (collation === null) {
|
|
714
|
+
ctx.diagnostics.push({
|
|
715
|
+
code: "PSL_INVALID_INDEX",
|
|
716
|
+
message: "collationLocale is required when using collation options",
|
|
717
|
+
sourceId: ctx.sourceId,
|
|
718
|
+
span: ctx.span
|
|
719
|
+
});
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
return new MongoIndex({
|
|
723
|
+
keys: resolved.keys,
|
|
724
|
+
...unique && { unique: true },
|
|
725
|
+
...parsed.sparse !== void 0 && { sparse: parsed.sparse },
|
|
726
|
+
...parsed.expireAfterSeconds !== void 0 && { expireAfterSeconds: parsed.expireAfterSeconds },
|
|
727
|
+
...parsed.filter !== void 0 && { partialFilterExpression: parsed.filter },
|
|
728
|
+
...wildcardProjection !== void 0 && { wildcardProjection },
|
|
729
|
+
...collation !== void 0 && { collation },
|
|
730
|
+
...parsed.default_language !== void 0 && { default_language: parsed.default_language },
|
|
731
|
+
...parsed.languageOverride !== void 0 && { language_override: parsed.languageOverride }
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
function buildTextIndex(parsed, ctx) {
|
|
735
|
+
const parsedFields = parsed.fields.map(normalizeIndexField);
|
|
736
|
+
if (parsedFields.length === 0) return void 0;
|
|
737
|
+
const resolved = resolveIndexKeys(parsedFields, "text", ctx);
|
|
738
|
+
if (!resolved) return void 0;
|
|
739
|
+
if (resolved.hasWildcard) {
|
|
740
|
+
ctx.diagnostics.push({
|
|
741
|
+
code: "PSL_INVALID_INDEX",
|
|
742
|
+
message: "wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex",
|
|
743
|
+
sourceId: ctx.sourceId,
|
|
744
|
+
span: ctx.span
|
|
745
|
+
});
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const collation = buildCollationFromSpec(parsed);
|
|
749
|
+
if (collation === null) {
|
|
750
|
+
ctx.diagnostics.push({
|
|
751
|
+
code: "PSL_INVALID_INDEX",
|
|
752
|
+
message: "collationLocale is required when using collation options",
|
|
753
|
+
sourceId: ctx.sourceId,
|
|
754
|
+
span: ctx.span
|
|
755
|
+
});
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
return new MongoIndex({
|
|
759
|
+
keys: resolved.keys,
|
|
760
|
+
...parsed.filter !== void 0 && { partialFilterExpression: parsed.filter },
|
|
761
|
+
...collation !== void 0 && { collation },
|
|
762
|
+
...ifDefined("weights", parsed.weights),
|
|
763
|
+
...parsed.language !== void 0 && { default_language: parsed.language },
|
|
764
|
+
...parsed.languageOverride !== void 0 && { language_override: parsed.languageOverride }
|
|
765
|
+
});
|
|
540
766
|
}
|
|
541
|
-
function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics, indexSpans) {
|
|
767
|
+
function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, sourceFile, diagnostics, indexSpans) {
|
|
542
768
|
const indexes = [];
|
|
543
769
|
let textIndexCount = 0;
|
|
544
770
|
const indexableFieldNames = /* @__PURE__ */ new Set();
|
|
545
|
-
for (const
|
|
546
|
-
if (modelNames.has(f.typeName)) continue;
|
|
547
|
-
indexableFieldNames.add(f.name);
|
|
548
|
-
}
|
|
771
|
+
for (const field of Object.values(pslModel.fields)) if (!modelNames.has(field.typeName)) indexableFieldNames.add(field.name);
|
|
549
772
|
for (const field of Object.values(pslModel.fields)) {
|
|
550
773
|
if (modelNames.has(field.typeName)) continue;
|
|
551
774
|
const uniqueAttr = getAttribute(field.attributes, "unique");
|
|
@@ -560,35 +783,31 @@ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnosti
|
|
|
560
783
|
indexes.push(fieldUniqueIndex);
|
|
561
784
|
indexSpans.set(fieldUniqueIndex, uniqueAttr.span);
|
|
562
785
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
code: "PSL_INVALID_INDEX",
|
|
585
|
-
message: "Unique indexes cannot use wildcard() fields",
|
|
786
|
+
const specs = buildIndexModelSpecs(Object.keys(pslModel.fields));
|
|
787
|
+
const attributeNodes = Array.from(pslModel.node.attributes());
|
|
788
|
+
for (const [attrIndex, attr] of pslModel.attributes.entries()) {
|
|
789
|
+
if (attr.name !== "index" && attr.name !== "unique" && attr.name !== "textIndex") continue;
|
|
790
|
+
const node = attributeNodes[attrIndex];
|
|
791
|
+
if (!node) continue;
|
|
792
|
+
const ctx = {
|
|
793
|
+
pslModel,
|
|
794
|
+
fieldMappings,
|
|
795
|
+
indexableFieldNames,
|
|
796
|
+
sourceId,
|
|
797
|
+
span: attr.span,
|
|
798
|
+
diagnostics
|
|
799
|
+
};
|
|
800
|
+
let index;
|
|
801
|
+
if (attr.name === "textIndex") {
|
|
802
|
+
const parsed = interpretModelAttribute({
|
|
803
|
+
node,
|
|
804
|
+
spec: specs.textIndex,
|
|
805
|
+
model: pslModel,
|
|
806
|
+
sourceFile,
|
|
586
807
|
sourceId,
|
|
587
|
-
|
|
808
|
+
diagnostics
|
|
588
809
|
});
|
|
589
|
-
continue;
|
|
590
|
-
}
|
|
591
|
-
if (isTextIndex) {
|
|
810
|
+
if (!parsed || parsed.fields.length === 0) continue;
|
|
592
811
|
textIndexCount++;
|
|
593
812
|
if (textIndexCount > 1) {
|
|
594
813
|
diagnostics.push({
|
|
@@ -599,135 +818,21 @@ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnosti
|
|
|
599
818
|
});
|
|
600
819
|
continue;
|
|
601
820
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
const typeArg = getNamedArgument(attr, "type");
|
|
613
|
-
const defaultDirection = isTextIndex ? "text" : parseIndexDirection(typeArg);
|
|
614
|
-
if (hasWildcard && typeof defaultDirection === "string" && [
|
|
615
|
-
"hashed",
|
|
616
|
-
"2dsphere",
|
|
617
|
-
"2d"
|
|
618
|
-
].includes(defaultDirection)) {
|
|
619
|
-
diagnostics.push({
|
|
620
|
-
code: "PSL_INVALID_INDEX",
|
|
621
|
-
message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,
|
|
622
|
-
sourceId,
|
|
623
|
-
span: attr.span
|
|
624
|
-
});
|
|
625
|
-
continue;
|
|
626
|
-
}
|
|
627
|
-
if (defaultDirection === "hashed" && parsedFields.length > 1) {
|
|
628
|
-
diagnostics.push({
|
|
629
|
-
code: "PSL_INVALID_INDEX",
|
|
630
|
-
message: "Hashed indexes must have exactly one field",
|
|
631
|
-
sourceId,
|
|
632
|
-
span: attr.span
|
|
633
|
-
});
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
636
|
-
let missingField;
|
|
637
|
-
for (const pf of parsedFields) {
|
|
638
|
-
let fieldNameForLookup;
|
|
639
|
-
if (pf.isWildcard) {
|
|
640
|
-
const wildcardMatch = pf.name.match(/^(.+)\.\$\*\*$/);
|
|
641
|
-
fieldNameForLookup = wildcardMatch ? wildcardMatch[1] : void 0;
|
|
642
|
-
} else fieldNameForLookup = pf.name;
|
|
643
|
-
if (fieldNameForLookup === void 0 || fieldNameForLookup.length === 0) continue;
|
|
644
|
-
if (!indexableFieldNames.has(fieldNameForLookup)) {
|
|
645
|
-
missingField = fieldNameForLookup;
|
|
646
|
-
break;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
if (missingField !== void 0) {
|
|
650
|
-
diagnostics.push({
|
|
651
|
-
code: "PSL_INDEX_FIELD_NOT_FOUND",
|
|
652
|
-
message: `Index on model "${pslModel.name}" references unknown field "${missingField}"`,
|
|
653
|
-
sourceId,
|
|
654
|
-
span: attr.span
|
|
655
|
-
});
|
|
656
|
-
continue;
|
|
657
|
-
}
|
|
658
|
-
const keys = parsedFields.map((pf) => {
|
|
659
|
-
return {
|
|
660
|
-
field: pf.isWildcard ? pf.name.replace(/^(.+)\.\$\*\*$/, (_, prefix) => {
|
|
661
|
-
const mapped = fieldMappings.pslNameToMapped.get(prefix);
|
|
662
|
-
return mapped ? `${mapped}.$**` : `${prefix}.$**`;
|
|
663
|
-
}) : fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name,
|
|
664
|
-
direction: pf.direction != null ? pf.direction : defaultDirection
|
|
665
|
-
};
|
|
666
|
-
});
|
|
667
|
-
const unique = isUnique ? true : void 0;
|
|
668
|
-
const sparse = isTextIndex ? void 0 : parseBooleanArg(getNamedArgument(attr, "sparse"));
|
|
669
|
-
const expireAfterSeconds = isTextIndex ? void 0 : parseNumericArg(getNamedArgument(attr, "expireAfterSeconds"));
|
|
670
|
-
if (hasWildcard && expireAfterSeconds != null) {
|
|
671
|
-
diagnostics.push({
|
|
672
|
-
code: "PSL_INVALID_INDEX",
|
|
673
|
-
message: "expireAfterSeconds cannot be combined with wildcard() fields",
|
|
674
|
-
sourceId,
|
|
675
|
-
span: attr.span
|
|
676
|
-
});
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
const partialFilterExpression = parseJsonArg(getNamedArgument(attr, "filter"));
|
|
680
|
-
const includeArg = getNamedArgument(attr, "include");
|
|
681
|
-
const excludeArg = getNamedArgument(attr, "exclude");
|
|
682
|
-
if (includeArg != null && excludeArg != null) {
|
|
683
|
-
diagnostics.push({
|
|
684
|
-
code: "PSL_INVALID_INDEX",
|
|
685
|
-
message: "Cannot specify both include and exclude on the same index",
|
|
686
|
-
sourceId,
|
|
687
|
-
span: attr.span
|
|
688
|
-
});
|
|
689
|
-
continue;
|
|
690
|
-
}
|
|
691
|
-
if ((includeArg != null || excludeArg != null) && !hasWildcard) {
|
|
692
|
-
diagnostics.push({
|
|
693
|
-
code: "PSL_INVALID_INDEX",
|
|
694
|
-
message: "include/exclude options are only valid when the index contains a wildcard() field",
|
|
821
|
+
index = buildTextIndex(parsed, ctx);
|
|
822
|
+
} else {
|
|
823
|
+
const unique = attr.name === "unique";
|
|
824
|
+
const parsed = interpretModelAttribute({
|
|
825
|
+
node,
|
|
826
|
+
spec: unique ? specs.unique : specs.index,
|
|
827
|
+
model: pslModel,
|
|
828
|
+
sourceFile,
|
|
695
829
|
sourceId,
|
|
696
|
-
|
|
830
|
+
diagnostics
|
|
697
831
|
});
|
|
698
|
-
continue;
|
|
832
|
+
if (!parsed) continue;
|
|
833
|
+
index = buildNormalIndex(parsed, unique, ctx);
|
|
699
834
|
}
|
|
700
|
-
|
|
701
|
-
const collation = parseCollation(attr);
|
|
702
|
-
if (collation === null) {
|
|
703
|
-
diagnostics.push({
|
|
704
|
-
code: "PSL_INVALID_INDEX",
|
|
705
|
-
message: "collationLocale is required when using collation options",
|
|
706
|
-
sourceId,
|
|
707
|
-
span: attr.span
|
|
708
|
-
});
|
|
709
|
-
continue;
|
|
710
|
-
}
|
|
711
|
-
const rawWeights = parseJsonArg(getNamedArgument(attr, "weights"));
|
|
712
|
-
let weights;
|
|
713
|
-
if (rawWeights) {
|
|
714
|
-
weights = {};
|
|
715
|
-
for (const [k, v] of Object.entries(rawWeights)) if (typeof v === "number") weights[k] = v;
|
|
716
|
-
}
|
|
717
|
-
const default_language = stripQuotesHelper(isTextIndex ? getNamedArgument(attr, "language") : getNamedArgument(attr, "default_language"));
|
|
718
|
-
const language_override = stripQuotesHelper(getNamedArgument(attr, "languageOverride"));
|
|
719
|
-
const index = new MongoIndex({
|
|
720
|
-
keys,
|
|
721
|
-
...unique != null && { unique },
|
|
722
|
-
...sparse != null && { sparse },
|
|
723
|
-
...expireAfterSeconds != null && { expireAfterSeconds },
|
|
724
|
-
...partialFilterExpression != null && { partialFilterExpression },
|
|
725
|
-
...wildcardProjection != null && { wildcardProjection },
|
|
726
|
-
...collation != null && { collation },
|
|
727
|
-
...weights != null && { weights },
|
|
728
|
-
...default_language != null && { default_language },
|
|
729
|
-
...language_override != null && { language_override }
|
|
730
|
-
});
|
|
835
|
+
if (!index) continue;
|
|
731
836
|
indexes.push(index);
|
|
732
837
|
indexSpans.set(index, attr.span);
|
|
733
838
|
}
|
|
@@ -839,6 +944,21 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
839
944
|
const allCompositeTypes = Object.values(topLevel.compositeTypes);
|
|
840
945
|
const modelNames = new Set(allModels.map((m) => m.name));
|
|
841
946
|
const compositeTypeNames = new Set(allCompositeTypes.map((ct) => ct.name));
|
|
947
|
+
const modelMetadataByName = /* @__PURE__ */ new Map();
|
|
948
|
+
for (const model of allModels) modelMetadataByName.set(model.name, {
|
|
949
|
+
collectionName: resolveCollectionName({
|
|
950
|
+
model,
|
|
951
|
+
sourceFile,
|
|
952
|
+
sourceId,
|
|
953
|
+
diagnostics
|
|
954
|
+
}),
|
|
955
|
+
fieldMappings: resolveFieldMappings({
|
|
956
|
+
model,
|
|
957
|
+
sourceFile,
|
|
958
|
+
sourceId,
|
|
959
|
+
diagnostics
|
|
960
|
+
})
|
|
961
|
+
});
|
|
842
962
|
const builtEnums = processEnumDeclarations({
|
|
843
963
|
enumBlocks: Object.values(topLevel.blocks).filter((b) => b.keyword === "enum").map((b) => b.block),
|
|
844
964
|
sourceId,
|
|
@@ -864,19 +984,30 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
864
984
|
const modelIndexesByName = /* @__PURE__ */ new Map();
|
|
865
985
|
const backrelationCandidates = [];
|
|
866
986
|
for (const pslModel of allModels) {
|
|
867
|
-
const
|
|
868
|
-
|
|
987
|
+
const metadata = modelMetadataByName.get(pslModel.name);
|
|
988
|
+
if (!metadata) continue;
|
|
989
|
+
const { collectionName, fieldMappings } = metadata;
|
|
869
990
|
const fields = {};
|
|
870
991
|
const relations = {};
|
|
871
992
|
for (const field of Object.values(pslModel.fields)) {
|
|
872
993
|
if (isRelationField(field, modelNames)) {
|
|
873
|
-
const
|
|
994
|
+
const relationNode = findFieldAttributeNode(field, "relation");
|
|
995
|
+
const relation = relationNode ? interpretFieldAttribute({
|
|
996
|
+
node: relationNode,
|
|
997
|
+
spec: relationFieldSpec,
|
|
998
|
+
model: pslModel,
|
|
999
|
+
field,
|
|
1000
|
+
sourceFile,
|
|
1001
|
+
sourceId,
|
|
1002
|
+
diagnostics,
|
|
1003
|
+
resolveReferencedModel: () => allModels.find((m) => m.name === field.typeName)
|
|
1004
|
+
}) : void 0;
|
|
874
1005
|
if (field.list || !(relation?.fields && relation?.references)) {
|
|
875
1006
|
backrelationCandidates.push({
|
|
876
1007
|
modelName: pslModel.name,
|
|
877
1008
|
fieldName: field.name,
|
|
878
1009
|
targetModelName: field.typeName,
|
|
879
|
-
...ifDefined("relationName", relation?.
|
|
1010
|
+
...ifDefined("relationName", relation?.name),
|
|
880
1011
|
cardinality: field.list ? "1:N" : "1:1",
|
|
881
1012
|
field
|
|
882
1013
|
});
|
|
@@ -884,8 +1015,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
884
1015
|
}
|
|
885
1016
|
if (relation?.fields && relation?.references) {
|
|
886
1017
|
const localMapped = relation.fields.map((f) => fieldMappings.pslNameToMapped.get(f) ?? f);
|
|
887
|
-
const
|
|
888
|
-
const targetFieldMappings = targetModel ? resolveFieldMappings(targetModel) : void 0;
|
|
1018
|
+
const targetFieldMappings = modelMetadataByName.get(field.typeName)?.fieldMappings;
|
|
889
1019
|
const targetMapped = relation.references.map((f) => targetFieldMappings?.pslNameToMapped.get(f) ?? f);
|
|
890
1020
|
relations[field.name] = {
|
|
891
1021
|
to: mongoCrossRef(field.typeName),
|
|
@@ -899,7 +1029,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
899
1029
|
declaringModel: pslModel.name,
|
|
900
1030
|
fieldName: field.name,
|
|
901
1031
|
targetModel: field.typeName,
|
|
902
|
-
...ifDefined("relationName", relation.
|
|
1032
|
+
...ifDefined("relationName", relation.name),
|
|
903
1033
|
localFields: localMapped,
|
|
904
1034
|
targetFields: targetMapped
|
|
905
1035
|
});
|
|
@@ -932,10 +1062,10 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
932
1062
|
relations,
|
|
933
1063
|
storage: { collection: collectionName }
|
|
934
1064
|
};
|
|
935
|
-
const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics, indexSpans);
|
|
1065
|
+
const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, sourceFile, diagnostics, indexSpans);
|
|
936
1066
|
modelIndexesByName.set(pslModel.name, modelIndexes);
|
|
937
1067
|
const existingColl = collections[collectionName];
|
|
938
|
-
if (existingColl && modelIndexes.length > 0) collections[collectionName] = { indexes: [...existingColl
|
|
1068
|
+
if (existingColl && modelIndexes.length > 0) collections[collectionName] = { indexes: [...collectionIndexes(existingColl), ...modelIndexes] };
|
|
939
1069
|
else if (!existingColl) collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};
|
|
940
1070
|
roots[collectionName] = mongoCrossRef(pslModel.name);
|
|
941
1071
|
}
|
|
@@ -991,7 +1121,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
991
1121
|
}
|
|
992
1122
|
};
|
|
993
1123
|
}
|
|
994
|
-
const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(allModels, sourceId, diagnostics);
|
|
1124
|
+
const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(allModels, modelMetadataByName, sourceFile, sourceId, diagnostics);
|
|
995
1125
|
const polyResult = resolvePolymorphism({
|
|
996
1126
|
models,
|
|
997
1127
|
roots,
|
|
@@ -1002,6 +1132,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
1002
1132
|
modelNames,
|
|
1003
1133
|
indexSpans,
|
|
1004
1134
|
modelIndexesByName,
|
|
1135
|
+
modelMetadataByName,
|
|
1005
1136
|
sourceId
|
|
1006
1137
|
});
|
|
1007
1138
|
if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) return notOk({
|
|
@@ -1048,7 +1179,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
1048
1179
|
...Object.keys(storageValueSets).length > 0 ? { valueSet: storageValueSets } : {}
|
|
1049
1180
|
}
|
|
1050
1181
|
});
|
|
1051
|
-
const storage = new MongoStorage({
|
|
1182
|
+
const storage = blindCast(new MongoStorage({
|
|
1052
1183
|
storageHash: computeStorageHash({
|
|
1053
1184
|
target,
|
|
1054
1185
|
targetFamily,
|
|
@@ -1062,7 +1193,7 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
1062
1193
|
...mongoContractCanonicalizationHooks
|
|
1063
1194
|
}),
|
|
1064
1195
|
namespaces: { [UNBOUND_NAMESPACE_ID]: unboundNamespace }
|
|
1065
|
-
});
|
|
1196
|
+
}));
|
|
1066
1197
|
const capabilities = {};
|
|
1067
1198
|
const hasEnums = Object.keys(builtEnums).length > 0;
|
|
1068
1199
|
return ok({
|
|
@@ -1088,4 +1219,4 @@ function interpretPslDocumentToMongoContract(input) {
|
|
|
1088
1219
|
//#endregion
|
|
1089
1220
|
export { derivePolymorphicJsonSchema as n, interpretPslDocumentToMongoContract as r, deriveJsonSchema as t };
|
|
1090
1221
|
|
|
1091
|
-
//# sourceMappingURL=interpreter-
|
|
1222
|
+
//# sourceMappingURL=interpreter-O09WlHk7-BiV9gBae.mjs.map
|