@payloadcms/db-mongodb 3.91.0-internal.6e3dc85 → 4.0.0-beta.0
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/LICENSE.md +1 -1
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +4 -5
- package/dist/connect.js.map +1 -1
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +2 -1
- package/dist/create.js.map +1 -1
- package/dist/createGlobalVersion.js +1 -1
- package/dist/createGlobalVersion.js.map +1 -1
- package/dist/createMigration.d.ts.map +1 -1
- package/dist/createMigration.js +9 -2
- package/dist/createMigration.js.map +1 -1
- package/dist/createVersion.js +1 -1
- package/dist/createVersion.js.map +1 -1
- package/dist/exports/migration-utils.d.ts +2 -0
- package/dist/exports/migration-utils.d.ts.map +1 -1
- package/dist/exports/migration-utils.js +2 -0
- package/dist/exports/migration-utils.js.map +1 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +89 -67
- package/dist/init.js.map +1 -1
- package/dist/migrateFresh.d.ts +4 -2
- package/dist/migrateFresh.d.ts.map +1 -1
- package/dist/migrateFresh.js +21 -6
- package/dist/migrateFresh.js.map +1 -1
- package/dist/models/buildCollectionSchema.d.ts +8 -2
- package/dist/models/buildCollectionSchema.d.ts.map +1 -1
- package/dist/models/buildCollectionSchema.js +4 -2
- package/dist/models/buildCollectionSchema.js.map +1 -1
- package/dist/models/buildGlobalModel.d.ts +5 -1
- package/dist/models/buildGlobalModel.d.ts.map +1 -1
- package/dist/models/buildGlobalModel.js +4 -2
- package/dist/models/buildGlobalModel.js.map +1 -1
- package/dist/models/buildSchema.d.ts +4 -0
- package/dist/models/buildSchema.d.ts.map +1 -1
- package/dist/models/buildSchema.js +79 -27
- package/dist/models/buildSchema.js.map +1 -1
- package/dist/models/schemaBuildContext.d.ts +21 -0
- package/dist/models/schemaBuildContext.d.ts.map +1 -0
- package/dist/models/schemaBuildContext.js +29 -0
- package/dist/models/schemaBuildContext.js.map +1 -0
- package/dist/predefinedMigrations/localize-status.d.ts +4 -0
- package/dist/predefinedMigrations/localize-status.d.ts.map +1 -0
- package/dist/predefinedMigrations/localize-status.js +9 -0
- package/dist/predefinedMigrations/localize-status.js.map +1 -0
- package/dist/predefinedMigrations/migrateLocalizeStatus.d.ts +27 -0
- package/dist/predefinedMigrations/migrateLocalizeStatus.d.ts.map +1 -0
- package/dist/predefinedMigrations/migrateLocalizeStatus.js +324 -0
- package/dist/predefinedMigrations/migrateLocalizeStatus.js.map +1 -0
- package/dist/predefinedMigrations/migrateRelationshipsV2_V3.d.ts.map +1 -1
- package/dist/predefinedMigrations/migrateRelationshipsV2_V3.js +4 -4
- package/dist/predefinedMigrations/migrateRelationshipsV2_V3.js.map +1 -1
- package/dist/predefinedMigrations/migrateSizesToVariants.d.ts +13 -0
- package/dist/predefinedMigrations/migrateSizesToVariants.d.ts.map +1 -0
- package/dist/predefinedMigrations/migrateSizesToVariants.js +368 -0
- package/dist/predefinedMigrations/migrateSizesToVariants.js.map +1 -0
- package/dist/predefinedMigrations/sizes-to-variants.d.ts +5 -0
- package/dist/predefinedMigrations/sizes-to-variants.d.ts.map +1 -0
- package/dist/predefinedMigrations/sizes-to-variants.js +8 -0
- package/dist/predefinedMigrations/sizes-to-variants.js.map +1 -0
- package/dist/queries/buildSearchParams.d.ts.map +1 -1
- package/dist/queries/buildSearchParams.js +171 -85
- package/dist/queries/buildSearchParams.js.map +1 -1
- package/dist/queries/getLocalizedSortProperty.d.ts.map +1 -1
- package/dist/queries/getLocalizedSortProperty.js +1 -1
- package/dist/queries/getLocalizedSortProperty.js.map +1 -1
- package/dist/queries/operatorMap.d.ts.map +1 -1
- package/dist/queries/parseParams.js.map +1 -1
- package/dist/queries/sanitizeQueryValue.d.ts.map +1 -1
- package/dist/queries/sanitizeQueryValue.js +2 -3
- package/dist/queries/sanitizeQueryValue.js.map +1 -1
- package/dist/testCredentials.d.ts.map +1 -1
- package/dist/transactions/beginTransaction.d.ts.map +1 -1
- package/dist/transactions/beginTransaction.js +0 -1
- package/dist/transactions/beginTransaction.js.map +1 -1
- package/dist/updateGlobal.js +2 -2
- package/dist/updateGlobal.js.map +1 -1
- package/dist/updateGlobalVersion.js +2 -2
- package/dist/updateGlobalVersion.js.map +1 -1
- package/dist/updateJobs.d.ts.map +1 -1
- package/dist/updateJobs.js +71 -14
- package/dist/updateJobs.js.map +1 -1
- package/dist/updateMany.d.ts.map +1 -1
- package/dist/updateMany.js +0 -1
- package/dist/updateMany.js.map +1 -1
- package/dist/updateOne.js +2 -2
- package/dist/updateOne.js.map +1 -1
- package/dist/updateVersion.js +2 -2
- package/dist/updateVersion.js.map +1 -1
- package/dist/utilities/aggregatePaginate.d.ts.map +1 -1
- package/dist/utilities/aggregatePaginate.js +3 -1
- package/dist/utilities/aggregatePaginate.js.map +1 -1
- package/dist/utilities/buildProjectionFromSelect.js +1 -1
- package/dist/utilities/buildProjectionFromSelect.js.map +1 -1
- package/dist/utilities/getEntity.d.ts +1 -1
- package/dist/utilities/transform.d.ts.map +1 -1
- package/dist/utilities/transform.js +12 -35
- package/dist/utilities/transform.js.map +1 -1
- package/package.json +6 -6
- package/dist/queries/buildSearchParams.spec.js +0 -49
- package/dist/queries/buildSearchParams.spec.js.map +0 -1
- package/dist/queries/buildSortParam.spec.js +0 -123
- package/dist/queries/buildSortParam.spec.js.map +0 -1
- package/dist/queries/getLocalizedSortProperty.spec.js +0 -215
- package/dist/queries/getLocalizedSortProperty.spec.js.map +0 -1
- package/dist/utilities/transform.spec.js +0 -546
- package/dist/utilities/transform.spec.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Types } from 'mongoose';
|
|
2
2
|
import { APIError, escapeRegExp, getFieldByPath, getLocalizedPaths } from 'payload';
|
|
3
|
-
import { isNestedRelationshipQuery, validOperatorSet } from 'payload/shared';
|
|
3
|
+
import { hasManyRelationshipOperatorSet, isNestedRelationshipQuery, validOperatorSet } from 'payload/shared';
|
|
4
4
|
import { getCollection } from '../utilities/getEntity.js';
|
|
5
5
|
import { isObjectID } from '../utilities/isObjectID.js';
|
|
6
6
|
import { operatorMap } from './operatorMap.js';
|
|
@@ -8,79 +8,6 @@ import { sanitizeQueryValue } from './sanitizeQueryValue.js';
|
|
|
8
8
|
const subQueryOptions = {
|
|
9
9
|
lean: true
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
12
|
-
* Builds a MongoDB condition for a `contains` query nested on a has-many relationship or upload
|
|
13
|
-
* field.
|
|
14
|
-
*
|
|
15
|
-
* Finds the related documents matching the nested query and constrains the parent to reference
|
|
16
|
-
* them, so the user's filter and any injected access constraint resolve against the same related
|
|
17
|
-
* document.
|
|
18
|
-
*/ async function buildHasManyRelationshipContainsSearchParam({ field, locale, nestedWhere, path, payload }) {
|
|
19
|
-
if (field.type !== 'relationship' && field.type !== 'upload') {
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
if (!field.hasMany || typeof field.relationTo !== 'string' || !isNestedRelationshipQuery(nestedWhere)) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
const { Model: RelatedModel } = getCollection({
|
|
26
|
-
adapter: payload.db,
|
|
27
|
-
collectionSlug: field.relationTo
|
|
28
|
-
});
|
|
29
|
-
const pathLocale = payload.config.localization ? payload.config.localization.localeCodes.find((localeCode)=>path.split('.').at(-1) === localeCode) : undefined;
|
|
30
|
-
const matchingRelatedDocumentsQuery = await RelatedModel.buildQuery({
|
|
31
|
-
locale: pathLocale ?? locale,
|
|
32
|
-
payload,
|
|
33
|
-
where: nestedWhere
|
|
34
|
-
});
|
|
35
|
-
const matchingRelatedDocumentIDs = (await RelatedModel.find(matchingRelatedDocumentsQuery).lean().select({
|
|
36
|
-
_id: true
|
|
37
|
-
})).map((document)=>document._id);
|
|
38
|
-
return {
|
|
39
|
-
path,
|
|
40
|
-
value: {
|
|
41
|
-
$in: matchingRelatedDocumentIDs
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Builds a MongoDB condition for a `contains` query nested on a join field.
|
|
47
|
-
*
|
|
48
|
-
* Finds documents in the joined collection that match the nested query, then follows the join's
|
|
49
|
-
* `on` relationship to collect the parent IDs those documents point back to. Because the nested
|
|
50
|
-
* query resolves against a single joined document, the user's filter and any injected access
|
|
51
|
-
* constraint must be satisfied by the same document.
|
|
52
|
-
*/ async function buildJoinContainsSearchParam({ field, locale, nestedWhere, payload }) {
|
|
53
|
-
if (field.type !== 'join' || typeof field.collection !== 'string' || !isNestedRelationshipQuery(nestedWhere)) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
const { collectionConfig, Model: JoinedModel } = getCollection({
|
|
57
|
-
adapter: payload.db,
|
|
58
|
-
collectionSlug: field.collection
|
|
59
|
-
});
|
|
60
|
-
const relationshipField = getFieldByPath({
|
|
61
|
-
fields: collectionConfig.flattenedFields,
|
|
62
|
-
path: field.on
|
|
63
|
-
});
|
|
64
|
-
if (!relationshipField) {
|
|
65
|
-
throw new APIError('Relationship field was not found');
|
|
66
|
-
}
|
|
67
|
-
let joinPath = relationshipField.localizedPath;
|
|
68
|
-
if (relationshipField.pathHasLocalized && payload.config.localization) {
|
|
69
|
-
joinPath = joinPath.replace('<locale>', locale || payload.config.localization.defaultLocale);
|
|
70
|
-
}
|
|
71
|
-
const subQuery = await JoinedModel.buildQuery({
|
|
72
|
-
locale,
|
|
73
|
-
payload,
|
|
74
|
-
where: nestedWhere
|
|
75
|
-
});
|
|
76
|
-
const parentIDs = await JoinedModel.distinct(joinPath, subQuery);
|
|
77
|
-
return {
|
|
78
|
-
path: '_id',
|
|
79
|
-
value: {
|
|
80
|
-
$in: parentIDs
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
11
|
/**
|
|
85
12
|
* Convert the Payload key / value / operator into a MongoDB query
|
|
86
13
|
*/ export async function buildSearchParam({ collectionSlug, fields, globalSlug, incomingPath, locale, operator, parentIsLocalized, payload, val }) {
|
|
@@ -123,11 +50,12 @@ const subQueryOptions = {
|
|
|
123
50
|
return undefined;
|
|
124
51
|
}
|
|
125
52
|
const [{ field, path }] = paths;
|
|
126
|
-
if (operator
|
|
127
|
-
return
|
|
53
|
+
if (hasManyRelationshipOperatorSet.has(operator) && paths.length === 1 && (field.type === 'relationship' || field.type === 'upload') && field.hasMany && typeof field.relationTo === 'string' && isNestedRelationshipQuery(val)) {
|
|
54
|
+
return buildHasManyRelationshipSearchParam({
|
|
128
55
|
field,
|
|
129
56
|
locale,
|
|
130
57
|
nestedWhere: val,
|
|
58
|
+
operator: operator,
|
|
131
59
|
path,
|
|
132
60
|
payload
|
|
133
61
|
});
|
|
@@ -140,10 +68,6 @@ const subQueryOptions = {
|
|
|
140
68
|
payload
|
|
141
69
|
});
|
|
142
70
|
}
|
|
143
|
-
// Refuse plain-object (or array-of-plain-object) values for text-matching operators
|
|
144
|
-
// before sanitizeQueryValue can splice them into a rawQuery. The legitimate nested-where
|
|
145
|
-
// shapes for `contains` on hasMany relationship / join fields are handled by the two
|
|
146
|
-
// `build*ContainsSearchParam` branches above.
|
|
147
71
|
if ((operator === 'contains' || operator === 'like' || operator === 'not_like') && (isNestedRelationshipQuery(val) || Array.isArray(val) && val.some((entry)=>isNestedRelationshipQuery(entry)))) {
|
|
148
72
|
throw new APIError(`Invalid value for "${operator}" on path "${path}": expected a string.`, 400);
|
|
149
73
|
}
|
|
@@ -176,10 +100,16 @@ const subQueryOptions = {
|
|
|
176
100
|
// Remove top collection and reverse array
|
|
177
101
|
// to work backwards from top
|
|
178
102
|
const pathsToQuery = paths.slice(1).reverse();
|
|
103
|
+
const parentPaths = paths.slice(0, -1).reverse();
|
|
179
104
|
let relationshipQuery = {
|
|
180
105
|
value: {}
|
|
181
106
|
};
|
|
182
107
|
for (const [i, { collectionSlug, path: subPath }] of pathsToQuery.entries()){
|
|
108
|
+
// The arrays are reversed together, so both entries describe the same relationship hop.
|
|
109
|
+
const parentField = parentPaths[i]?.field;
|
|
110
|
+
if (!parentField) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
183
113
|
if (!collectionSlug) {
|
|
184
114
|
throw new APIError(`Collection with the slug ${collectionSlug} was not found.`);
|
|
185
115
|
}
|
|
@@ -197,15 +127,14 @@ const subQueryOptions = {
|
|
|
197
127
|
}
|
|
198
128
|
}
|
|
199
129
|
});
|
|
200
|
-
const field = paths[0].field;
|
|
201
130
|
const select = {
|
|
202
131
|
_id: true
|
|
203
132
|
};
|
|
204
133
|
let joinPath = null;
|
|
205
|
-
if (
|
|
134
|
+
if (parentField.type === 'join') {
|
|
206
135
|
const relationshipField = getFieldByPath({
|
|
207
136
|
fields: collectionConfig.flattenedFields,
|
|
208
|
-
path:
|
|
137
|
+
path: parentField.on
|
|
209
138
|
});
|
|
210
139
|
if (!relationshipField) {
|
|
211
140
|
throw new APIError('Relationship field was not found');
|
|
@@ -264,14 +193,53 @@ const subQueryOptions = {
|
|
|
264
193
|
const nextSubPath = pathsToQuery[i + 1]?.path;
|
|
265
194
|
if (nextSubPath) {
|
|
266
195
|
relationshipQuery = {
|
|
267
|
-
value: {
|
|
268
|
-
|
|
196
|
+
value: joinPath ? {
|
|
197
|
+
_id: {
|
|
198
|
+
$in
|
|
199
|
+
}
|
|
200
|
+
} : {
|
|
201
|
+
[nextSubPath]: {
|
|
202
|
+
$in
|
|
203
|
+
}
|
|
269
204
|
}
|
|
270
205
|
};
|
|
271
206
|
}
|
|
272
207
|
continue;
|
|
273
208
|
}
|
|
274
209
|
const subQuery = relationshipQuery.value;
|
|
210
|
+
/**
|
|
211
|
+
* Follow this join back to its parent IDs.
|
|
212
|
+
* For example, matching songs yield album IDs, then artist IDs.
|
|
213
|
+
*/ if (parentField.type === 'join') {
|
|
214
|
+
const relationshipField = getFieldByPath({
|
|
215
|
+
fields: collectionConfig.flattenedFields,
|
|
216
|
+
path: parentField.on
|
|
217
|
+
});
|
|
218
|
+
if (!relationshipField) {
|
|
219
|
+
throw new APIError('Relationship field was not found');
|
|
220
|
+
}
|
|
221
|
+
let joinPath = relationshipField.localizedPath;
|
|
222
|
+
if (relationshipField.pathHasLocalized && payload.config.localization) {
|
|
223
|
+
joinPath = joinPath.replace('<locale>', locale || payload.config.localization.defaultLocale);
|
|
224
|
+
}
|
|
225
|
+
const $in = await SubModel.distinct(joinPath, subQuery);
|
|
226
|
+
if (i + 1 === pathsToQuery.length) {
|
|
227
|
+
return {
|
|
228
|
+
path: '_id',
|
|
229
|
+
value: {
|
|
230
|
+
$in
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
relationshipQuery = {
|
|
235
|
+
value: {
|
|
236
|
+
_id: {
|
|
237
|
+
$in
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
275
243
|
const result = await SubModel.find(subQuery, subQueryOptions);
|
|
276
244
|
const $in = result.map((doc)=>doc._id);
|
|
277
245
|
// If it is the last recursion
|
|
@@ -396,5 +364,123 @@ const subQueryOptions = {
|
|
|
396
364
|
}
|
|
397
365
|
return undefined;
|
|
398
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Builds a MongoDB condition for an operator containing a nested has-many relationship query.
|
|
369
|
+
*
|
|
370
|
+
* First, it finds IDs from the related collection that match the nested query. The parent
|
|
371
|
+
* collection can then use `$in` or `$nin` against its stored relationship IDs.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* // Input
|
|
376
|
+
* { ingredients: { not_equals: { isHealthy: { equals: false } } } }
|
|
377
|
+
*
|
|
378
|
+
* // Simplified MongoDB result, after finding the matching ingredient IDs
|
|
379
|
+
* { ingredients: { $nin: [unhealthyIngredientID] } }
|
|
380
|
+
* ```
|
|
381
|
+
*/ async function buildHasManyRelationshipSearchParam({ field, locale, nestedWhere, operator, path, payload }) {
|
|
382
|
+
if (field.type !== 'relationship' && field.type !== 'upload' || !field.hasMany || typeof field.relationTo !== 'string' || !isNestedRelationshipQuery(nestedWhere)) {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
const { Model: RelatedModel } = getCollection({
|
|
386
|
+
adapter: payload.db,
|
|
387
|
+
collectionSlug: field.relationTo
|
|
388
|
+
});
|
|
389
|
+
const pathLocale = payload.config.localization ? payload.config.localization.localeCodes.find((localeCode)=>path.split('.').at(-1) === localeCode) : undefined;
|
|
390
|
+
const matchingRelatedDocumentsQuery = await RelatedModel.buildQuery({
|
|
391
|
+
locale: pathLocale ?? locale,
|
|
392
|
+
payload,
|
|
393
|
+
where: nestedWhere
|
|
394
|
+
});
|
|
395
|
+
const findRelatedDocumentIDs = async (query)=>(await RelatedModel.find(query).lean().select({
|
|
396
|
+
_id: true
|
|
397
|
+
})).map((document)=>document._id);
|
|
398
|
+
switch(operator){
|
|
399
|
+
case 'contains':
|
|
400
|
+
{
|
|
401
|
+
const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery);
|
|
402
|
+
return {
|
|
403
|
+
path,
|
|
404
|
+
value: {
|
|
405
|
+
$in: matchingRelatedDocumentIDs
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
case 'equals':
|
|
410
|
+
{
|
|
411
|
+
// Every related document satisfies an empty nested query.
|
|
412
|
+
if (!Object.keys(matchingRelatedDocumentsQuery).length) {
|
|
413
|
+
return {
|
|
414
|
+
path,
|
|
415
|
+
value: {
|
|
416
|
+
$nin: []
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
// MongoDB rejects `$near` and `$text` when they are inverted with `$nor`. Check the parent
|
|
421
|
+
// instead: none of its IDs may fall outside the matching IDs.
|
|
422
|
+
const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery);
|
|
423
|
+
return {
|
|
424
|
+
path,
|
|
425
|
+
value: {
|
|
426
|
+
$not: {
|
|
427
|
+
$elemMatch: {
|
|
428
|
+
$nin: matchingRelatedDocumentIDs
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
case 'not_equals':
|
|
435
|
+
{
|
|
436
|
+
const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery);
|
|
437
|
+
return {
|
|
438
|
+
path,
|
|
439
|
+
value: {
|
|
440
|
+
$nin: matchingRelatedDocumentIDs
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Builds a MongoDB condition for a `contains` query nested on a join field.
|
|
448
|
+
*
|
|
449
|
+
* Finds documents in the joined collection that match the nested query, then follows the join's
|
|
450
|
+
* `on` relationship to collect the parent IDs those documents point back to. Because the nested
|
|
451
|
+
* query resolves against a single joined document, the user's filter and any injected access
|
|
452
|
+
* constraint must be satisfied by the same document.
|
|
453
|
+
*/ async function buildJoinContainsSearchParam({ field, locale, nestedWhere, payload }) {
|
|
454
|
+
if (field.type !== 'join' || typeof field.collection !== 'string' || !isNestedRelationshipQuery(nestedWhere)) {
|
|
455
|
+
return undefined;
|
|
456
|
+
}
|
|
457
|
+
const { collectionConfig, Model: JoinedModel } = getCollection({
|
|
458
|
+
adapter: payload.db,
|
|
459
|
+
collectionSlug: field.collection
|
|
460
|
+
});
|
|
461
|
+
const relationshipField = getFieldByPath({
|
|
462
|
+
fields: collectionConfig.flattenedFields,
|
|
463
|
+
path: field.on
|
|
464
|
+
});
|
|
465
|
+
if (!relationshipField) {
|
|
466
|
+
throw new APIError('Relationship field was not found');
|
|
467
|
+
}
|
|
468
|
+
let joinPath = relationshipField.localizedPath;
|
|
469
|
+
if (relationshipField.pathHasLocalized && payload.config.localization) {
|
|
470
|
+
joinPath = joinPath.replace('<locale>', locale || payload.config.localization.defaultLocale);
|
|
471
|
+
}
|
|
472
|
+
const subQuery = await JoinedModel.buildQuery({
|
|
473
|
+
locale,
|
|
474
|
+
payload,
|
|
475
|
+
where: nestedWhere
|
|
476
|
+
});
|
|
477
|
+
const parentIDs = await JoinedModel.distinct(joinPath, subQuery);
|
|
478
|
+
return {
|
|
479
|
+
path: '_id',
|
|
480
|
+
value: {
|
|
481
|
+
$in: parentIDs
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
399
485
|
|
|
400
486
|
//# sourceMappingURL=buildSearchParams.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/queries/buildSearchParams.ts"],"sourcesContent":["import type { FilterQuery } from 'mongoose'\nimport type { FlattenedField, Operator, PathToQuery, Payload } from 'payload'\n\nimport { Types } from 'mongoose'\nimport { APIError, escapeRegExp, getFieldByPath, getLocalizedPaths } from 'payload'\nimport { isNestedRelationshipQuery, validOperatorSet } from 'payload/shared'\n\nimport type { MongooseAdapter } from '../index.js'\nimport type { OperatorMapKey } from './operatorMap.js'\n\nimport { getCollection } from '../utilities/getEntity.js'\nimport { isObjectID } from '../utilities/isObjectID.js'\nimport { operatorMap } from './operatorMap.js'\nimport { sanitizeQueryValue } from './sanitizeQueryValue.js'\n\ntype SearchParam = {\n path?: string\n rawQuery?: unknown\n value?: unknown\n}\n\nconst subQueryOptions = {\n lean: true,\n}\n\n/**\n * Builds a MongoDB condition for a `contains` query nested on a has-many relationship or upload\n * field.\n *\n * Finds the related documents matching the nested query and constrains the parent to reference\n * them, so the user's filter and any injected access constraint resolve against the same related\n * document.\n */\nasync function buildHasManyRelationshipContainsSearchParam({\n field,\n locale,\n nestedWhere,\n path,\n payload,\n}: {\n field: FlattenedField\n locale?: string\n nestedWhere: unknown\n path: string\n payload: Payload\n}): Promise<SearchParam | undefined> {\n if (field.type !== 'relationship' && field.type !== 'upload') {\n return undefined\n }\n\n if (\n !field.hasMany ||\n typeof field.relationTo !== 'string' ||\n !isNestedRelationshipQuery(nestedWhere)\n ) {\n return undefined\n }\n\n const { Model: RelatedModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug: field.relationTo,\n })\n const pathLocale = payload.config.localization\n ? payload.config.localization.localeCodes.find(\n (localeCode) => path.split('.').at(-1) === localeCode,\n )\n : undefined\n const matchingRelatedDocumentsQuery = await RelatedModel.buildQuery({\n locale: pathLocale ?? locale,\n payload,\n where: nestedWhere,\n })\n\n const matchingRelatedDocumentIDs = (\n await RelatedModel.find(matchingRelatedDocumentsQuery).lean().select({ _id: true })\n ).map((document) => document._id)\n\n return {\n path,\n value: { $in: matchingRelatedDocumentIDs },\n }\n}\n\n/**\n * Builds a MongoDB condition for a `contains` query nested on a join field.\n *\n * Finds documents in the joined collection that match the nested query, then follows the join's\n * `on` relationship to collect the parent IDs those documents point back to. Because the nested\n * query resolves against a single joined document, the user's filter and any injected access\n * constraint must be satisfied by the same document.\n */\nasync function buildJoinContainsSearchParam({\n field,\n locale,\n nestedWhere,\n payload,\n}: {\n field: FlattenedField\n locale?: string\n nestedWhere: unknown\n payload: Payload\n}): Promise<SearchParam | undefined> {\n if (\n field.type !== 'join' ||\n typeof field.collection !== 'string' ||\n !isNestedRelationshipQuery(nestedWhere)\n ) {\n return undefined\n }\n\n const { collectionConfig, Model: JoinedModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug: field.collection,\n })\n\n const relationshipField = getFieldByPath({\n fields: collectionConfig.flattenedFields,\n path: field.on,\n })\n\n if (!relationshipField) {\n throw new APIError('Relationship field was not found')\n }\n\n let joinPath = relationshipField.localizedPath\n if (relationshipField.pathHasLocalized && payload.config.localization) {\n joinPath = joinPath.replace('<locale>', locale || payload.config.localization.defaultLocale)\n }\n\n const subQuery = await JoinedModel.buildQuery({\n locale,\n payload,\n where: nestedWhere,\n })\n\n const parentIDs = await JoinedModel.distinct(joinPath, subQuery)\n\n return {\n path: '_id',\n value: { $in: parentIDs },\n }\n}\n\n/**\n * Convert the Payload key / value / operator into a MongoDB query\n */\nexport async function buildSearchParam({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath,\n locale,\n operator,\n parentIsLocalized,\n payload,\n val,\n}: {\n collectionSlug?: string\n fields: FlattenedField[]\n globalSlug?: string\n incomingPath: string\n locale?: string\n operator: Operator\n parentIsLocalized: boolean\n payload: Payload\n val: unknown\n}): Promise<SearchParam | undefined> {\n // Replace GraphQL nested field double underscore formatting\n let sanitizedPath = incomingPath.replace(/__/g, '.')\n if (sanitizedPath === 'id') {\n sanitizedPath = '_id'\n }\n\n let paths: PathToQuery[] = []\n\n let hasCustomID = false\n\n if (sanitizedPath === '_id') {\n const customIDFieldType = collectionSlug\n ? payload.collections[collectionSlug]?.customIDType\n : undefined\n\n let idFieldType: 'number' | 'text' = 'text'\n\n if (customIDFieldType) {\n idFieldType = customIDFieldType\n hasCustomID = true\n }\n\n paths.push({\n collectionSlug,\n complete: true,\n field: {\n name: 'id',\n type: idFieldType,\n } as FlattenedField,\n parentIsLocalized: parentIsLocalized ?? false,\n path: '_id',\n })\n } else {\n paths = getLocalizedPaths({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: sanitizedPath,\n locale,\n parentIsLocalized,\n payload,\n })\n }\n\n if (!paths[0]) {\n return undefined\n }\n\n const [{ field, path }] = paths\n\n if (\n operator === 'contains' &&\n paths.length === 1 &&\n (field.type === 'relationship' || field.type === 'upload') &&\n field.hasMany &&\n typeof field.relationTo === 'string' &&\n isNestedRelationshipQuery(val)\n ) {\n return buildHasManyRelationshipContainsSearchParam({\n field,\n locale,\n nestedWhere: val,\n path,\n payload,\n })\n }\n\n if (\n operator === 'contains' &&\n paths.length === 1 &&\n field.type === 'join' &&\n typeof field.collection === 'string' &&\n isNestedRelationshipQuery(val)\n ) {\n return buildJoinContainsSearchParam({\n field,\n locale,\n nestedWhere: val,\n payload,\n })\n }\n\n // Refuse plain-object (or array-of-plain-object) values for text-matching operators\n // before sanitizeQueryValue can splice them into a rawQuery. The legitimate nested-where\n // shapes for `contains` on hasMany relationship / join fields are handled by the two\n // `build*ContainsSearchParam` branches above.\n if (\n (operator === 'contains' || operator === 'like' || operator === 'not_like') &&\n (isNestedRelationshipQuery(val) ||\n (Array.isArray(val) && val.some((entry) => isNestedRelationshipQuery(entry))))\n ) {\n throw new APIError(`Invalid value for \"${operator}\" on path \"${path}\": expected a string.`, 400)\n }\n\n if (path) {\n const sanitizedQueryValue = sanitizeQueryValue({\n field,\n hasCustomID,\n locale,\n operator,\n parentIsLocalized,\n path,\n payload,\n val,\n })\n\n if (!sanitizedQueryValue) {\n return undefined\n }\n\n const { operator: formattedOperator, rawQuery, val: formattedValue } = sanitizedQueryValue\n\n if (rawQuery && paths.length === 1) {\n return { value: rawQuery }\n }\n\n if (!formattedOperator) {\n return undefined\n }\n\n // If there are multiple collections to search through,\n // Recursively build up a list of query constraints\n if (paths.length > 1) {\n // Remove top collection and reverse array\n // to work backwards from top\n const pathsToQuery = paths.slice(1).reverse()\n\n let relationshipQuery: SearchParam = {\n value: {},\n }\n\n for (const [i, { collectionSlug, path: subPath }] of pathsToQuery.entries()) {\n if (!collectionSlug) {\n throw new APIError(`Collection with the slug ${collectionSlug} was not found.`)\n }\n\n const { collectionConfig, Model: SubModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug,\n })\n\n if (i === 0) {\n const subQuery = await SubModel.buildQuery({\n locale,\n payload,\n where: {\n [subPath]: {\n [formattedOperator]: val,\n },\n },\n })\n\n const field = paths[0].field\n\n const select: Record<string, boolean> = {\n _id: true,\n }\n\n let joinPath: null | string = null\n\n if (field.type === 'join') {\n const relationshipField = getFieldByPath({\n fields: collectionConfig.flattenedFields,\n path: field.on,\n })\n if (!relationshipField) {\n throw new APIError('Relationship field was not found')\n }\n\n let path = relationshipField.localizedPath\n if (relationshipField.pathHasLocalized && payload.config.localization) {\n path = path.replace('<locale>', locale || payload.config.localization.defaultLocale)\n }\n select[path] = true\n\n joinPath = path\n }\n\n if (joinPath) {\n select[joinPath] = true\n }\n\n const result = await SubModel.find(subQuery).lean().select(select)\n\n const $in: unknown[] = []\n\n result.forEach((doc: any) => {\n if (joinPath) {\n let ref = doc\n\n for (const segment of joinPath.split('.')) {\n if (Array.isArray(ref)) {\n ref = ref\n .map((item) => (typeof item === 'object' && item ? item[segment] : undefined))\n .flat()\n .filter((item) => item != null)\n } else if (typeof ref === 'object' && ref) {\n ref = ref[segment]\n } else {\n ref = undefined\n break\n }\n }\n\n if (Array.isArray(ref)) {\n for (const item of ref) {\n if (isObjectID(item)) {\n $in.push(item)\n }\n }\n } else if (isObjectID(ref)) {\n $in.push(ref)\n }\n } else {\n const stringID = doc._id.toString()\n if (Types.ObjectId.isValid(stringID)) {\n $in.push(doc._id)\n } else {\n $in.push(stringID)\n }\n }\n })\n\n if (pathsToQuery.length === 1) {\n return {\n path: joinPath ? '_id' : path,\n value: { $in },\n }\n }\n\n const nextSubPath = pathsToQuery[i + 1]?.path\n\n if (nextSubPath) {\n relationshipQuery = { value: { [nextSubPath]: $in } }\n }\n\n continue\n }\n\n const subQuery = relationshipQuery.value as FilterQuery<any>\n const result = await SubModel.find(subQuery, subQueryOptions)\n\n const $in = result.map((doc) => doc._id)\n\n // If it is the last recursion\n // then pass through the search param\n if (i + 1 === pathsToQuery.length) {\n relationshipQuery = {\n path,\n value: { $in },\n }\n } else {\n const nextSubPath = pathsToQuery[i + 1]?.path\n if (nextSubPath) {\n relationshipQuery = {\n value: {\n [nextSubPath]: { $in },\n },\n }\n }\n }\n }\n\n return relationshipQuery\n }\n\n if (formattedOperator && validOperatorSet.has(formattedOperator as Operator)) {\n const operatorKey = operatorMap[formattedOperator as OperatorMapKey]\n\n if (field.type === 'relationship' || field.type === 'upload') {\n let hasNumberIDRelation\n let multiIDCondition = '$or'\n if (operatorKey === '$ne') {\n multiIDCondition = '$and'\n }\n\n const result = {\n value: {\n [multiIDCondition]: [{ [path]: { [operatorKey]: formattedValue } }],\n },\n }\n\n if (typeof formattedValue === 'string') {\n if (Types.ObjectId.isValid(formattedValue)) {\n result.value[multiIDCondition]?.push({\n [path]: { [operatorKey]: new Types.ObjectId(formattedValue) },\n })\n } else {\n ;(Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]).forEach(\n (relationTo) => {\n const isRelatedToCustomNumberID =\n payload.collections[relationTo]?.customIDType === 'number'\n\n if (isRelatedToCustomNumberID) {\n hasNumberIDRelation = true\n }\n },\n )\n\n if (hasNumberIDRelation) {\n result.value[multiIDCondition]?.push({\n [path]: { [operatorKey]: parseFloat(formattedValue) },\n })\n }\n }\n }\n\n const length = result.value[multiIDCondition]?.length\n\n if (typeof length === 'number' && length > 1) {\n return result\n }\n }\n\n if (formattedOperator === 'like' && typeof formattedValue === 'string') {\n const words = formattedValue.split(' ')\n\n const result = {\n value: {\n $and: words.map((word) => ({\n [path]: {\n $options: 'i',\n $regex: escapeRegExp(word),\n },\n })),\n },\n }\n\n return result\n }\n\n if (formattedOperator === 'not_like' && typeof formattedValue === 'string') {\n const words = formattedValue.split(' ')\n\n const result = {\n value: {\n $and: words.map((word) => ({\n [path]: {\n $not: {\n $options: 'i',\n $regex: escapeRegExp(word),\n },\n },\n })),\n },\n }\n\n return result\n }\n\n // Some operators like 'near' need to define a full query\n // so if there is no operator key, just return the value\n if (!operatorKey) {\n return {\n path,\n value: formattedValue,\n }\n }\n\n return {\n path,\n value: { [operatorKey]: formattedValue },\n }\n }\n }\n return undefined\n}\n"],"names":["Types","APIError","escapeRegExp","getFieldByPath","getLocalizedPaths","isNestedRelationshipQuery","validOperatorSet","getCollection","isObjectID","operatorMap","sanitizeQueryValue","subQueryOptions","lean","buildHasManyRelationshipContainsSearchParam","field","locale","nestedWhere","path","payload","type","undefined","hasMany","relationTo","Model","RelatedModel","adapter","db","collectionSlug","pathLocale","config","localization","localeCodes","find","localeCode","split","at","matchingRelatedDocumentsQuery","buildQuery","where","matchingRelatedDocumentIDs","select","_id","map","document","value","$in","buildJoinContainsSearchParam","collection","collectionConfig","JoinedModel","relationshipField","fields","flattenedFields","on","joinPath","localizedPath","pathHasLocalized","replace","defaultLocale","subQuery","parentIDs","distinct","buildSearchParam","globalSlug","incomingPath","operator","parentIsLocalized","val","sanitizedPath","paths","hasCustomID","customIDFieldType","collections","customIDType","idFieldType","push","complete","name","length","Array","isArray","some","entry","sanitizedQueryValue","formattedOperator","rawQuery","formattedValue","pathsToQuery","slice","reverse","relationshipQuery","i","subPath","entries","SubModel","result","forEach","doc","ref","segment","item","flat","filter","stringID","toString","ObjectId","isValid","nextSubPath","has","operatorKey","hasNumberIDRelation","multiIDCondition","isRelatedToCustomNumberID","parseFloat","words","$and","word","$options","$regex","$not"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/queries/buildSearchParams.ts"],"sourcesContent":["import type { QueryFilter } from 'mongoose'\nimport type {\n FlattenedField,\n HasManyRelationshipOperator,\n Operator,\n PathToQuery,\n Payload,\n} from 'payload'\n\nimport { Types } from 'mongoose'\nimport { APIError, escapeRegExp, getFieldByPath, getLocalizedPaths } from 'payload'\nimport {\n hasManyRelationshipOperatorSet,\n isNestedRelationshipQuery,\n validOperatorSet,\n} from 'payload/shared'\n\nimport type { MongooseAdapter } from '../index.js'\nimport type { OperatorMapKey } from './operatorMap.js'\n\nimport { getCollection } from '../utilities/getEntity.js'\nimport { isObjectID } from '../utilities/isObjectID.js'\nimport { operatorMap } from './operatorMap.js'\nimport { sanitizeQueryValue } from './sanitizeQueryValue.js'\n\ntype SearchParam = {\n path?: string\n rawQuery?: unknown\n value?: unknown\n}\n\nconst subQueryOptions = {\n lean: true,\n}\n\n/**\n * Convert the Payload key / value / operator into a MongoDB query\n */\nexport async function buildSearchParam({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath,\n locale,\n operator,\n parentIsLocalized,\n payload,\n val,\n}: {\n collectionSlug?: string\n fields: FlattenedField[]\n globalSlug?: string\n incomingPath: string\n locale?: string\n operator: Operator\n parentIsLocalized: boolean\n payload: Payload\n val: unknown\n}): Promise<SearchParam | undefined> {\n // Replace GraphQL nested field double underscore formatting\n let sanitizedPath = incomingPath.replace(/__/g, '.')\n if (sanitizedPath === 'id') {\n sanitizedPath = '_id'\n }\n\n let paths: PathToQuery[] = []\n\n let hasCustomID = false\n\n if (sanitizedPath === '_id') {\n const customIDFieldType = collectionSlug\n ? payload.collections[collectionSlug]?.customIDType\n : undefined\n\n let idFieldType: 'number' | 'text' = 'text'\n\n if (customIDFieldType) {\n idFieldType = customIDFieldType\n hasCustomID = true\n }\n\n paths.push({\n collectionSlug,\n complete: true,\n field: {\n name: 'id',\n type: idFieldType,\n } as FlattenedField,\n parentIsLocalized: parentIsLocalized ?? false,\n path: '_id',\n })\n } else {\n paths = getLocalizedPaths({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: sanitizedPath,\n locale,\n parentIsLocalized,\n payload,\n })\n }\n\n if (!paths[0]) {\n return undefined\n }\n\n const [{ field, path }] = paths\n\n if (\n hasManyRelationshipOperatorSet.has(operator as HasManyRelationshipOperator) &&\n paths.length === 1 &&\n (field.type === 'relationship' || field.type === 'upload') &&\n field.hasMany &&\n typeof field.relationTo === 'string' &&\n isNestedRelationshipQuery(val)\n ) {\n return buildHasManyRelationshipSearchParam({\n field,\n locale,\n nestedWhere: val,\n operator: operator as HasManyRelationshipOperator,\n path,\n payload,\n })\n }\n\n if (\n operator === 'contains' &&\n paths.length === 1 &&\n field.type === 'join' &&\n typeof field.collection === 'string' &&\n isNestedRelationshipQuery(val)\n ) {\n return buildJoinContainsSearchParam({\n field,\n locale,\n nestedWhere: val,\n payload,\n })\n }\n\n if (\n (operator === 'contains' || operator === 'like' || operator === 'not_like') &&\n (isNestedRelationshipQuery(val) ||\n (Array.isArray(val) && val.some((entry) => isNestedRelationshipQuery(entry))))\n ) {\n throw new APIError(`Invalid value for \"${operator}\" on path \"${path}\": expected a string.`, 400)\n }\n\n if (path) {\n const sanitizedQueryValue = sanitizeQueryValue({\n field,\n hasCustomID,\n locale,\n operator,\n parentIsLocalized,\n path,\n payload,\n val,\n })\n\n if (!sanitizedQueryValue) {\n return undefined\n }\n\n const { operator: formattedOperator, rawQuery, val: formattedValue } = sanitizedQueryValue\n\n if (rawQuery && paths.length === 1) {\n return { value: rawQuery }\n }\n\n if (!formattedOperator) {\n return undefined\n }\n\n // If there are multiple collections to search through,\n // Recursively build up a list of query constraints\n if (paths.length > 1) {\n // Remove top collection and reverse array\n // to work backwards from top\n const pathsToQuery = paths.slice(1).reverse()\n const parentPaths = paths.slice(0, -1).reverse()\n\n let relationshipQuery: SearchParam = {\n value: {},\n }\n\n for (const [i, { collectionSlug, path: subPath }] of pathsToQuery.entries()) {\n // The arrays are reversed together, so both entries describe the same relationship hop.\n const parentField = parentPaths[i]?.field\n\n if (!parentField) {\n return undefined\n }\n\n if (!collectionSlug) {\n throw new APIError(`Collection with the slug ${collectionSlug} was not found.`)\n }\n\n const { collectionConfig, Model: SubModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug,\n })\n\n if (i === 0) {\n const subQuery = await SubModel.buildQuery({\n locale,\n payload,\n where: {\n [subPath]: {\n [formattedOperator]: val,\n },\n },\n })\n\n const select: Record<string, boolean> = {\n _id: true,\n }\n\n let joinPath: null | string = null\n\n if (parentField.type === 'join') {\n const relationshipField = getFieldByPath({\n fields: collectionConfig.flattenedFields,\n path: parentField.on,\n })\n if (!relationshipField) {\n throw new APIError('Relationship field was not found')\n }\n\n let path = relationshipField.localizedPath\n if (relationshipField.pathHasLocalized && payload.config.localization) {\n path = path.replace('<locale>', locale || payload.config.localization.defaultLocale)\n }\n select[path] = true\n\n joinPath = path\n }\n\n if (joinPath) {\n select[joinPath] = true\n }\n\n const result = await SubModel.find(subQuery).lean().select(select)\n\n const $in: unknown[] = []\n\n result.forEach((doc: any) => {\n if (joinPath) {\n let ref = doc\n\n for (const segment of joinPath.split('.')) {\n if (Array.isArray(ref)) {\n ref = ref\n .map((item) => (typeof item === 'object' && item ? item[segment] : undefined))\n .flat()\n .filter((item) => item != null)\n } else if (typeof ref === 'object' && ref) {\n ref = ref[segment]\n } else {\n ref = undefined\n break\n }\n }\n\n if (Array.isArray(ref)) {\n for (const item of ref) {\n if (isObjectID(item)) {\n $in.push(item)\n }\n }\n } else if (isObjectID(ref)) {\n $in.push(ref)\n }\n } else {\n const stringID = doc._id.toString()\n if (Types.ObjectId.isValid(stringID)) {\n $in.push(doc._id)\n } else {\n $in.push(stringID)\n }\n }\n })\n\n if (pathsToQuery.length === 1) {\n return {\n path: joinPath ? '_id' : path,\n value: { $in },\n }\n }\n\n const nextSubPath = pathsToQuery[i + 1]?.path\n\n if (nextSubPath) {\n relationshipQuery = {\n value: joinPath ? { _id: { $in } } : { [nextSubPath]: { $in } },\n }\n }\n\n continue\n }\n\n const subQuery = relationshipQuery.value as QueryFilter<any>\n\n /**\n * Follow this join back to its parent IDs.\n * For example, matching songs yield album IDs, then artist IDs.\n */\n if (parentField.type === 'join') {\n const relationshipField = getFieldByPath({\n fields: collectionConfig.flattenedFields,\n path: parentField.on,\n })\n if (!relationshipField) {\n throw new APIError('Relationship field was not found')\n }\n\n let joinPath = relationshipField.localizedPath\n if (relationshipField.pathHasLocalized && payload.config.localization) {\n joinPath = joinPath.replace(\n '<locale>',\n locale || payload.config.localization.defaultLocale,\n )\n }\n\n const $in = await SubModel.distinct(joinPath, subQuery)\n if (i + 1 === pathsToQuery.length) {\n return { path: '_id', value: { $in } }\n }\n\n relationshipQuery = { value: { _id: { $in } } }\n continue\n }\n\n const result = await SubModel.find(subQuery, subQueryOptions)\n\n const $in = result.map((doc) => doc._id)\n\n // If it is the last recursion\n // then pass through the search param\n if (i + 1 === pathsToQuery.length) {\n relationshipQuery = {\n path,\n value: { $in },\n }\n } else {\n const nextSubPath = pathsToQuery[i + 1]?.path\n if (nextSubPath) {\n relationshipQuery = {\n value: {\n [nextSubPath]: { $in },\n },\n }\n }\n }\n }\n\n return relationshipQuery\n }\n\n if (formattedOperator && validOperatorSet.has(formattedOperator as Operator)) {\n const operatorKey = operatorMap[formattedOperator as OperatorMapKey]\n\n if (field.type === 'relationship' || field.type === 'upload') {\n let hasNumberIDRelation\n let multiIDCondition = '$or'\n if (operatorKey === '$ne') {\n multiIDCondition = '$and'\n }\n\n const result = {\n value: {\n [multiIDCondition]: [{ [path]: { [operatorKey]: formattedValue } }],\n },\n }\n\n if (typeof formattedValue === 'string') {\n if (Types.ObjectId.isValid(formattedValue)) {\n result.value[multiIDCondition]?.push({\n [path]: { [operatorKey]: new Types.ObjectId(formattedValue) },\n })\n } else {\n ;(Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]).forEach(\n (relationTo) => {\n const isRelatedToCustomNumberID =\n payload.collections[relationTo]?.customIDType === 'number'\n\n if (isRelatedToCustomNumberID) {\n hasNumberIDRelation = true\n }\n },\n )\n\n if (hasNumberIDRelation) {\n result.value[multiIDCondition]?.push({\n [path]: { [operatorKey]: parseFloat(formattedValue) },\n })\n }\n }\n }\n\n const length = result.value[multiIDCondition]?.length\n\n if (typeof length === 'number' && length > 1) {\n return result\n }\n }\n\n if (formattedOperator === 'like' && typeof formattedValue === 'string') {\n const words = formattedValue.split(' ')\n\n const result = {\n value: {\n $and: words.map((word) => ({\n [path]: {\n $options: 'i',\n $regex: escapeRegExp(word),\n },\n })),\n },\n }\n\n return result\n }\n\n if (formattedOperator === 'not_like' && typeof formattedValue === 'string') {\n const words = formattedValue.split(' ')\n\n const result = {\n value: {\n $and: words.map((word) => ({\n [path]: {\n $not: {\n $options: 'i',\n $regex: escapeRegExp(word),\n },\n },\n })),\n },\n }\n\n return result\n }\n\n // Some operators like 'near' need to define a full query\n // so if there is no operator key, just return the value\n if (!operatorKey) {\n return {\n path,\n value: formattedValue,\n }\n }\n\n return {\n path,\n value: { [operatorKey]: formattedValue },\n }\n }\n }\n return undefined\n}\n\n/**\n * Builds a MongoDB condition for an operator containing a nested has-many relationship query.\n *\n * First, it finds IDs from the related collection that match the nested query. The parent\n * collection can then use `$in` or `$nin` against its stored relationship IDs.\n *\n * @example\n * ```ts\n * // Input\n * { ingredients: { not_equals: { isHealthy: { equals: false } } } }\n *\n * // Simplified MongoDB result, after finding the matching ingredient IDs\n * { ingredients: { $nin: [unhealthyIngredientID] } }\n * ```\n */\nasync function buildHasManyRelationshipSearchParam({\n field,\n locale,\n nestedWhere,\n operator,\n path,\n payload,\n}: {\n field: FlattenedField\n locale?: string\n nestedWhere: unknown\n operator: HasManyRelationshipOperator\n path: string\n payload: Payload\n}): Promise<SearchParam | undefined> {\n if (\n (field.type !== 'relationship' && field.type !== 'upload') ||\n !field.hasMany ||\n typeof field.relationTo !== 'string' ||\n !isNestedRelationshipQuery(nestedWhere)\n ) {\n return undefined\n }\n\n const { Model: RelatedModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug: field.relationTo,\n })\n const pathLocale = payload.config.localization\n ? payload.config.localization.localeCodes.find(\n (localeCode) => path.split('.').at(-1) === localeCode,\n )\n : undefined\n const matchingRelatedDocumentsQuery = await RelatedModel.buildQuery({\n locale: pathLocale ?? locale,\n payload,\n where: nestedWhere,\n })\n\n const findRelatedDocumentIDs = async (query: Record<string, unknown>) =>\n (await RelatedModel.find(query).lean().select({ _id: true })).map((document) => document._id)\n\n switch (operator) {\n case 'contains': {\n const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery)\n\n return {\n path,\n value: { $in: matchingRelatedDocumentIDs },\n }\n }\n\n case 'equals': {\n // Every related document satisfies an empty nested query.\n if (!Object.keys(matchingRelatedDocumentsQuery).length) {\n return {\n path,\n value: { $nin: [] },\n }\n }\n\n // MongoDB rejects `$near` and `$text` when they are inverted with `$nor`. Check the parent\n // instead: none of its IDs may fall outside the matching IDs.\n const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery)\n\n return {\n path,\n value: { $not: { $elemMatch: { $nin: matchingRelatedDocumentIDs } } },\n }\n }\n\n case 'not_equals': {\n const matchingRelatedDocumentIDs = await findRelatedDocumentIDs(matchingRelatedDocumentsQuery)\n\n return {\n path,\n value: { $nin: matchingRelatedDocumentIDs },\n }\n }\n }\n}\n\n/**\n * Builds a MongoDB condition for a `contains` query nested on a join field.\n *\n * Finds documents in the joined collection that match the nested query, then follows the join's\n * `on` relationship to collect the parent IDs those documents point back to. Because the nested\n * query resolves against a single joined document, the user's filter and any injected access\n * constraint must be satisfied by the same document.\n */\nasync function buildJoinContainsSearchParam({\n field,\n locale,\n nestedWhere,\n payload,\n}: {\n field: FlattenedField\n locale?: string\n nestedWhere: unknown\n payload: Payload\n}): Promise<SearchParam | undefined> {\n if (\n field.type !== 'join' ||\n typeof field.collection !== 'string' ||\n !isNestedRelationshipQuery(nestedWhere)\n ) {\n return undefined\n }\n\n const { collectionConfig, Model: JoinedModel } = getCollection({\n adapter: payload.db as MongooseAdapter,\n collectionSlug: field.collection,\n })\n\n const relationshipField = getFieldByPath({\n fields: collectionConfig.flattenedFields,\n path: field.on,\n })\n\n if (!relationshipField) {\n throw new APIError('Relationship field was not found')\n }\n\n let joinPath = relationshipField.localizedPath\n if (relationshipField.pathHasLocalized && payload.config.localization) {\n joinPath = joinPath.replace('<locale>', locale || payload.config.localization.defaultLocale)\n }\n\n const subQuery = await JoinedModel.buildQuery({\n locale,\n payload,\n where: nestedWhere,\n })\n\n const parentIDs = await JoinedModel.distinct(joinPath, subQuery)\n\n return {\n path: '_id',\n value: { $in: parentIDs },\n }\n}\n"],"names":["Types","APIError","escapeRegExp","getFieldByPath","getLocalizedPaths","hasManyRelationshipOperatorSet","isNestedRelationshipQuery","validOperatorSet","getCollection","isObjectID","operatorMap","sanitizeQueryValue","subQueryOptions","lean","buildSearchParam","collectionSlug","fields","globalSlug","incomingPath","locale","operator","parentIsLocalized","payload","val","sanitizedPath","replace","paths","hasCustomID","customIDFieldType","collections","customIDType","undefined","idFieldType","push","complete","field","name","type","path","has","length","hasMany","relationTo","buildHasManyRelationshipSearchParam","nestedWhere","collection","buildJoinContainsSearchParam","Array","isArray","some","entry","sanitizedQueryValue","formattedOperator","rawQuery","formattedValue","value","pathsToQuery","slice","reverse","parentPaths","relationshipQuery","i","subPath","entries","parentField","collectionConfig","Model","SubModel","adapter","db","subQuery","buildQuery","where","select","_id","joinPath","relationshipField","flattenedFields","on","localizedPath","pathHasLocalized","config","localization","defaultLocale","result","find","$in","forEach","doc","ref","segment","split","map","item","flat","filter","stringID","toString","ObjectId","isValid","nextSubPath","distinct","operatorKey","hasNumberIDRelation","multiIDCondition","isRelatedToCustomNumberID","parseFloat","words","$and","word","$options","$regex","$not","RelatedModel","pathLocale","localeCodes","localeCode","at","matchingRelatedDocumentsQuery","findRelatedDocumentIDs","query","document","matchingRelatedDocumentIDs","Object","keys","$nin","$elemMatch","JoinedModel","parentIDs"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getLocalizedSortProperty.d.ts","sourceRoot":"","sources":["../../src/queries/getLocalizedSortProperty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAI9D,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB,EAAE,OAAO,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,wBAAwB,uGAOlC,IAAI,KAAG,
|
|
1
|
+
{"version":3,"file":"getLocalizedSortProperty.d.ts","sourceRoot":"","sources":["../../src/queries/getLocalizedSortProperty.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAI9D,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB,EAAE,OAAO,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,wBAAwB,uGAOlC,IAAI,KAAG,MA8FT,CAAA"}
|
|
@@ -45,7 +45,7 @@ export const getLocalizedSortProperty = ({ config, fields, locale, parentIsLocal
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
if (matchedField.type === 'blocks') {
|
|
48
|
-
nextFields =
|
|
48
|
+
nextFields = matchedField.blocks.reduce((flattenedBlockFields, _block)=>{
|
|
49
49
|
// TODO: iterate over blocks mapped to block slug in v4, or pass through payload.blocks
|
|
50
50
|
const block = typeof _block === 'string' ? config.blocks?.find((b)=>b.slug === _block) : _block;
|
|
51
51
|
if (!block) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/queries/getLocalizedSortProperty.ts"],"sourcesContent":["import type { FlattenedField, SanitizedConfig } from 'payload'\n\nimport { fieldAffectsData, fieldIsPresentationalOnly, fieldShouldBeLocalized } from 'payload/shared'\n\ntype Args = {\n config: SanitizedConfig\n fields: FlattenedField[]\n locale?: string\n parentIsLocalized: boolean\n result?: string\n segments: string[]\n}\n\nexport const getLocalizedSortProperty = ({\n config,\n fields,\n locale,\n parentIsLocalized,\n result: incomingResult,\n segments: incomingSegments,\n}: Args): string => {\n // If localization is not enabled, accept exactly\n // what is sent in\n if (!config.localization) {\n return incomingSegments.join('.')\n }\n\n const segments = [...incomingSegments]\n\n // Retrieve first segment, and remove from segments\n const firstSegment = segments.shift()\n\n // Attempt to find a matched field\n const matchedField = fields.find(\n (field) => fieldAffectsData(field) && field.name === firstSegment,\n )\n\n if (matchedField && !fieldIsPresentationalOnly(matchedField)) {\n let nextFields: FlattenedField[] | null = null\n let nextParentIsLocalized = parentIsLocalized\n const remainingSegments = [...segments]\n let localizedSegment = matchedField.name\n\n if (\n fieldShouldBeLocalized({ field: matchedField, parentIsLocalized: parentIsLocalized ?? false })\n ) {\n // Check to see if next segment is a locale\n if (segments.length > 0 && remainingSegments[0]) {\n const nextSegmentIsLocale = config.localization.localeCodes.includes(remainingSegments[0])\n\n // If next segment is locale, remove it from remaining segments\n // and use it to localize the current segment\n if (nextSegmentIsLocale) {\n const nextSegment = remainingSegments.shift()\n localizedSegment = `${matchedField.name}.${nextSegment}`\n }\n } else {\n // If no more segments, but field is localized, use default locale\n localizedSegment = `${matchedField.name}.${locale}`\n }\n }\n\n // If there are subfields, pass them through\n if (\n matchedField.type === 'tab' ||\n matchedField.type === 'group' ||\n matchedField.type === 'array'\n ) {\n nextFields = matchedField.flattenedFields\n if (!nextParentIsLocalized) {\n nextParentIsLocalized = matchedField.localized ?? false\n }\n }\n\n if (matchedField.type === 'blocks') {\n nextFields =
|
|
1
|
+
{"version":3,"sources":["../../src/queries/getLocalizedSortProperty.ts"],"sourcesContent":["import type { FlattenedField, SanitizedConfig } from 'payload'\n\nimport { fieldAffectsData, fieldIsPresentationalOnly, fieldShouldBeLocalized } from 'payload/shared'\n\ntype Args = {\n config: SanitizedConfig\n fields: FlattenedField[]\n locale?: string\n parentIsLocalized: boolean\n result?: string\n segments: string[]\n}\n\nexport const getLocalizedSortProperty = ({\n config,\n fields,\n locale,\n parentIsLocalized,\n result: incomingResult,\n segments: incomingSegments,\n}: Args): string => {\n // If localization is not enabled, accept exactly\n // what is sent in\n if (!config.localization) {\n return incomingSegments.join('.')\n }\n\n const segments = [...incomingSegments]\n\n // Retrieve first segment, and remove from segments\n const firstSegment = segments.shift()\n\n // Attempt to find a matched field\n const matchedField = fields.find(\n (field) => fieldAffectsData(field) && field.name === firstSegment,\n )\n\n if (matchedField && !fieldIsPresentationalOnly(matchedField)) {\n let nextFields: FlattenedField[] | null = null\n let nextParentIsLocalized = parentIsLocalized\n const remainingSegments = [...segments]\n let localizedSegment = matchedField.name\n\n if (\n fieldShouldBeLocalized({ field: matchedField, parentIsLocalized: parentIsLocalized ?? false })\n ) {\n // Check to see if next segment is a locale\n if (segments.length > 0 && remainingSegments[0]) {\n const nextSegmentIsLocale = config.localization.localeCodes.includes(remainingSegments[0])\n\n // If next segment is locale, remove it from remaining segments\n // and use it to localize the current segment\n if (nextSegmentIsLocale) {\n const nextSegment = remainingSegments.shift()\n localizedSegment = `${matchedField.name}.${nextSegment}`\n }\n } else {\n // If no more segments, but field is localized, use default locale\n localizedSegment = `${matchedField.name}.${locale}`\n }\n }\n\n // If there are subfields, pass them through\n if (\n matchedField.type === 'tab' ||\n matchedField.type === 'group' ||\n matchedField.type === 'array'\n ) {\n nextFields = matchedField.flattenedFields\n if (!nextParentIsLocalized) {\n nextParentIsLocalized = matchedField.localized ?? false\n }\n }\n\n if (matchedField.type === 'blocks') {\n nextFields = matchedField.blocks.reduce<FlattenedField[]>((flattenedBlockFields, _block) => {\n // TODO: iterate over blocks mapped to block slug in v4, or pass through payload.blocks\n const block =\n typeof _block === 'string' ? config.blocks?.find((b) => b.slug === _block) : _block\n\n if (!block) {\n return [...flattenedBlockFields]\n }\n\n return [\n ...flattenedBlockFields,\n ...block.flattenedFields.filter(\n (blockField) =>\n (fieldAffectsData(blockField) &&\n blockField.name !== 'blockType' &&\n blockField.name !== 'blockName') ||\n !fieldAffectsData(blockField),\n ),\n ]\n }, [])\n }\n\n const result = incomingResult ? `${incomingResult}.${localizedSegment}` : localizedSegment\n\n if (nextFields !== null) {\n return getLocalizedSortProperty({\n config,\n fields: nextFields,\n locale,\n parentIsLocalized: nextParentIsLocalized,\n result,\n segments: remainingSegments,\n })\n }\n\n return result\n }\n\n return incomingSegments.join('.')\n}\n"],"names":["fieldAffectsData","fieldIsPresentationalOnly","fieldShouldBeLocalized","getLocalizedSortProperty","config","fields","locale","parentIsLocalized","result","incomingResult","segments","incomingSegments","localization","join","firstSegment","shift","matchedField","find","field","name","nextFields","nextParentIsLocalized","remainingSegments","localizedSegment","length","nextSegmentIsLocale","localeCodes","includes","nextSegment","type","flattenedFields","localized","blocks","reduce","flattenedBlockFields","_block","block","b","slug","filter","blockField"],"mappings":"AAEA,SAASA,gBAAgB,EAAEC,yBAAyB,EAAEC,sBAAsB,QAAQ,iBAAgB;AAWpG,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,MAAM,EACNC,MAAM,EACNC,MAAM,EACNC,iBAAiB,EACjBC,QAAQC,cAAc,EACtBC,UAAUC,gBAAgB,EACrB;IACL,iDAAiD;IACjD,kBAAkB;IAClB,IAAI,CAACP,OAAOQ,YAAY,EAAE;QACxB,OAAOD,iBAAiBE,IAAI,CAAC;IAC/B;IAEA,MAAMH,WAAW;WAAIC;KAAiB;IAEtC,mDAAmD;IACnD,MAAMG,eAAeJ,SAASK,KAAK;IAEnC,kCAAkC;IAClC,MAAMC,eAAeX,OAAOY,IAAI,CAC9B,CAACC,QAAUlB,iBAAiBkB,UAAUA,MAAMC,IAAI,KAAKL;IAGvD,IAAIE,gBAAgB,CAACf,0BAA0Be,eAAe;QAC5D,IAAII,aAAsC;QAC1C,IAAIC,wBAAwBd;QAC5B,MAAMe,oBAAoB;eAAIZ;SAAS;QACvC,IAAIa,mBAAmBP,aAAaG,IAAI;QAExC,IACEjB,uBAAuB;YAAEgB,OAAOF;YAAcT,mBAAmBA,qBAAqB;QAAM,IAC5F;YACA,2CAA2C;YAC3C,IAAIG,SAASc,MAAM,GAAG,KAAKF,iBAAiB,CAAC,EAAE,EAAE;gBAC/C,MAAMG,sBAAsBrB,OAAOQ,YAAY,CAACc,WAAW,CAACC,QAAQ,CAACL,iBAAiB,CAAC,EAAE;gBAEzF,+DAA+D;gBAC/D,6CAA6C;gBAC7C,IAAIG,qBAAqB;oBACvB,MAAMG,cAAcN,kBAAkBP,KAAK;oBAC3CQ,mBAAmB,GAAGP,aAAaG,IAAI,CAAC,CAAC,EAAES,aAAa;gBAC1D;YACF,OAAO;gBACL,kEAAkE;gBAClEL,mBAAmB,GAAGP,aAAaG,IAAI,CAAC,CAAC,EAAEb,QAAQ;YACrD;QACF;QAEA,4CAA4C;QAC5C,IACEU,aAAaa,IAAI,KAAK,SACtBb,aAAaa,IAAI,KAAK,WACtBb,aAAaa,IAAI,KAAK,SACtB;YACAT,aAAaJ,aAAac,eAAe;YACzC,IAAI,CAACT,uBAAuB;gBAC1BA,wBAAwBL,aAAae,SAAS,IAAI;YACpD;QACF;QAEA,IAAIf,aAAaa,IAAI,KAAK,UAAU;YAClCT,aAAaJ,aAAagB,MAAM,CAACC,MAAM,CAAmB,CAACC,sBAAsBC;gBAC/E,uFAAuF;gBACvF,MAAMC,QACJ,OAAOD,WAAW,WAAW/B,OAAO4B,MAAM,EAAEf,KAAK,CAACoB,IAAMA,EAAEC,IAAI,KAAKH,UAAUA;gBAE/E,IAAI,CAACC,OAAO;oBACV,OAAO;2BAAIF;qBAAqB;gBAClC;gBAEA,OAAO;uBACFA;uBACAE,MAAMN,eAAe,CAACS,MAAM,CAC7B,CAACC,aACC,AAACxC,iBAAiBwC,eAChBA,WAAWrB,IAAI,KAAK,eACpBqB,WAAWrB,IAAI,KAAK,eACtB,CAACnB,iBAAiBwC;iBAEvB;YACH,GAAG,EAAE;QACP;QAEA,MAAMhC,SAASC,iBAAiB,GAAGA,eAAe,CAAC,EAAEc,kBAAkB,GAAGA;QAE1E,IAAIH,eAAe,MAAM;YACvB,OAAOjB,yBAAyB;gBAC9BC;gBACAC,QAAQe;gBACRd;gBACAC,mBAAmBc;gBACnBb;gBACAE,UAAUY;YACZ;QACF;QAEA,OAAOd;IACT;IAEA,OAAOG,iBAAiBE,IAAI,CAAC;AAC/B,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operatorMap.d.ts","sourceRoot":"","sources":["../../src/queries/operatorMap.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,WAAW,CAAA;AAErD,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"operatorMap.d.ts","sourceRoot":"","sources":["../../src/queries/operatorMap.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,WAAW,CAAA;AAErD,eAAO,MAAM,WAAW;IACtB,GAAG;IACH,MAAM;IACN,MAAM;IACN,YAAY;IACZ,kBAAkB;IAClB,EAAE;IACF,UAAU;IACV,SAAS;IACT,eAAe;IACf,IAAI;IACJ,UAAU;IACV,MAAM;IACN,MAAM;CACP,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/queries/parseParams.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/queries/parseParams.ts"],"sourcesContent":["import type { QueryFilter } from 'mongoose'\nimport type { FlattenedField, Operator, Payload, Where } from 'payload'\n\nimport { deepMergeWithCombinedArrays } from 'payload'\nimport { validOperatorSet } from 'payload/shared'\n\nimport { buildAndOrConditions } from './buildAndOrConditions.js'\nimport { buildSearchParam } from './buildSearchParams.js'\n\nexport async function parseParams({\n collectionSlug,\n fields,\n globalSlug,\n locale,\n parentIsLocalized,\n payload,\n where,\n}: {\n collectionSlug?: string\n fields: FlattenedField[]\n globalSlug?: string\n locale?: string\n parentIsLocalized: boolean\n payload: Payload\n where: Where\n}): Promise<Record<string, unknown>> {\n let result = {} as QueryFilter<any>\n\n if (typeof where === 'object') {\n // We need to determine if the whereKey is an AND, OR, or a schema path\n for (const relationOrPath of Object.keys(where)) {\n const condition = where[relationOrPath]\n let conditionOperator: '$and' | '$or' | null = null\n if (relationOrPath.toLowerCase() === 'and') {\n conditionOperator = '$and'\n } else if (relationOrPath.toLowerCase() === 'or') {\n conditionOperator = '$or'\n }\n if (Array.isArray(condition)) {\n const builtConditions = await buildAndOrConditions({\n collectionSlug,\n fields,\n globalSlug,\n locale,\n parentIsLocalized,\n payload,\n where: condition,\n })\n if (builtConditions.length > 0 && conditionOperator !== null) {\n result[conditionOperator] = builtConditions\n }\n } else {\n // It's a path - and there can be multiple comparisons on a single path.\n // For example - title like 'test' and title not equal to 'tester'\n // So we need to loop on keys again here to handle each operator independently\n const pathOperators = where[relationOrPath]\n if (typeof pathOperators === 'object') {\n const validOperators: Operator[] = Object.keys(pathOperators).filter((operator) =>\n validOperatorSet.has(operator as Operator),\n ) as Operator[]\n\n for (const operator of validOperators) {\n const searchParam = await buildSearchParam({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: relationOrPath,\n locale,\n operator,\n parentIsLocalized,\n payload,\n val: (pathOperators as Record<string, Where>)[operator],\n })\n\n if (searchParam?.value && searchParam?.path) {\n if (validOperators.length > 1) {\n if (!result.$and) {\n result.$and = []\n }\n result.$and.push({\n [searchParam.path]: searchParam.value,\n })\n } else {\n if (result[searchParam.path]) {\n if (!result.$and) {\n result.$and = []\n }\n\n result.$and.push({ [searchParam.path]: result[searchParam.path] })\n result.$and.push({\n [searchParam.path]: searchParam.value,\n })\n delete result[searchParam.path]\n } else {\n result[searchParam.path] = searchParam.value\n }\n }\n } else if (typeof searchParam?.value === 'object') {\n result = deepMergeWithCombinedArrays(result, searchParam.value ?? {}, {\n // dont clone Types.ObjectIDs\n clone: false,\n })\n }\n }\n }\n }\n }\n }\n\n return result\n}\n"],"names":["deepMergeWithCombinedArrays","validOperatorSet","buildAndOrConditions","buildSearchParam","parseParams","collectionSlug","fields","globalSlug","locale","parentIsLocalized","payload","where","result","relationOrPath","Object","keys","condition","conditionOperator","toLowerCase","Array","isArray","builtConditions","length","pathOperators","validOperators","filter","operator","has","searchParam","incomingPath","val","value","path","$and","push","clone"],"mappings":"AAGA,SAASA,2BAA2B,QAAQ,UAAS;AACrD,SAASC,gBAAgB,QAAQ,iBAAgB;AAEjD,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SAASC,gBAAgB,QAAQ,yBAAwB;AAEzD,OAAO,eAAeC,YAAY,EAChCC,cAAc,EACdC,MAAM,EACNC,UAAU,EACVC,MAAM,EACNC,iBAAiB,EACjBC,OAAO,EACPC,KAAK,EASN;IACC,IAAIC,SAAS,CAAC;IAEd,IAAI,OAAOD,UAAU,UAAU;QAC7B,uEAAuE;QACvE,KAAK,MAAME,kBAAkBC,OAAOC,IAAI,CAACJ,OAAQ;YAC/C,MAAMK,YAAYL,KAAK,CAACE,eAAe;YACvC,IAAII,oBAA2C;YAC/C,IAAIJ,eAAeK,WAAW,OAAO,OAAO;gBAC1CD,oBAAoB;YACtB,OAAO,IAAIJ,eAAeK,WAAW,OAAO,MAAM;gBAChDD,oBAAoB;YACtB;YACA,IAAIE,MAAMC,OAAO,CAACJ,YAAY;gBAC5B,MAAMK,kBAAkB,MAAMnB,qBAAqB;oBACjDG;oBACAC;oBACAC;oBACAC;oBACAC;oBACAC;oBACAC,OAAOK;gBACT;gBACA,IAAIK,gBAAgBC,MAAM,GAAG,KAAKL,sBAAsB,MAAM;oBAC5DL,MAAM,CAACK,kBAAkB,GAAGI;gBAC9B;YACF,OAAO;gBACL,wEAAwE;gBACxE,kEAAkE;gBAClE,8EAA8E;gBAC9E,MAAME,gBAAgBZ,KAAK,CAACE,eAAe;gBAC3C,IAAI,OAAOU,kBAAkB,UAAU;oBACrC,MAAMC,iBAA6BV,OAAOC,IAAI,CAACQ,eAAeE,MAAM,CAAC,CAACC,WACpEzB,iBAAiB0B,GAAG,CAACD;oBAGvB,KAAK,MAAMA,YAAYF,eAAgB;wBACrC,MAAMI,cAAc,MAAMzB,iBAAiB;4BACzCE;4BACAC;4BACAC;4BACAsB,cAAchB;4BACdL;4BACAkB;4BACAjB;4BACAC;4BACAoB,KAAK,AAACP,aAAuC,CAACG,SAAS;wBACzD;wBAEA,IAAIE,aAAaG,SAASH,aAAaI,MAAM;4BAC3C,IAAIR,eAAeF,MAAM,GAAG,GAAG;gCAC7B,IAAI,CAACV,OAAOqB,IAAI,EAAE;oCAChBrB,OAAOqB,IAAI,GAAG,EAAE;gCAClB;gCACArB,OAAOqB,IAAI,CAACC,IAAI,CAAC;oCACf,CAACN,YAAYI,IAAI,CAAC,EAAEJ,YAAYG,KAAK;gCACvC;4BACF,OAAO;gCACL,IAAInB,MAAM,CAACgB,YAAYI,IAAI,CAAC,EAAE;oCAC5B,IAAI,CAACpB,OAAOqB,IAAI,EAAE;wCAChBrB,OAAOqB,IAAI,GAAG,EAAE;oCAClB;oCAEArB,OAAOqB,IAAI,CAACC,IAAI,CAAC;wCAAE,CAACN,YAAYI,IAAI,CAAC,EAAEpB,MAAM,CAACgB,YAAYI,IAAI,CAAC;oCAAC;oCAChEpB,OAAOqB,IAAI,CAACC,IAAI,CAAC;wCACf,CAACN,YAAYI,IAAI,CAAC,EAAEJ,YAAYG,KAAK;oCACvC;oCACA,OAAOnB,MAAM,CAACgB,YAAYI,IAAI,CAAC;gCACjC,OAAO;oCACLpB,MAAM,CAACgB,YAAYI,IAAI,CAAC,GAAGJ,YAAYG,KAAK;gCAC9C;4BACF;wBACF,OAAO,IAAI,OAAOH,aAAaG,UAAU,UAAU;4BACjDnB,SAASZ,4BAA4BY,QAAQgB,YAAYG,KAAK,IAAI,CAAC,GAAG;gCACpE,6BAA6B;gCAC7BI,OAAO;4BACT;wBACF;oBACF;gBACF;YACF;QACF;IACF;IAEA,OAAOvB;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizeQueryValue.d.ts","sourceRoot":"","sources":["../../src/queries/sanitizeQueryValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sanitizeQueryValue.d.ts","sourceRoot":"","sources":["../../src/queries/sanitizeQueryValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAA;AAMnG,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,cAAc,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,QAAQ,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;CACT,CAAA;AAmED,eAAO,MAAM,kBAAkB,qFAS5B,sBAAsB,KACrB;IACE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,GACD,SAycH,CAAA"}
|
|
@@ -54,9 +54,8 @@ const buildExistsQuery = (formattedValue, path, treatEmptyString = true)=>{
|
|
|
54
54
|
};
|
|
55
55
|
// returns nestedField Field object from blocks.nestedField path because getLocalizedPaths splits them only for relationships
|
|
56
56
|
const getFieldFromSegments = ({ field, payload, segments })=>{
|
|
57
|
-
if ('blocks' in field
|
|
58
|
-
const
|
|
59
|
-
for (const _block of _field.blockReferences ?? _field.blocks){
|
|
57
|
+
if ('blocks' in field) {
|
|
58
|
+
for (const _block of field.blocks){
|
|
60
59
|
const block = typeof _block === 'string' ? payload.blocks[_block] : _block;
|
|
61
60
|
if (block) {
|
|
62
61
|
const field = getFieldFromSegments({
|