@payloadcms/db-mongodb 4.0.0-internal.d1cc1d3 → 4.0.0-internal.d21c039
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/connect.d.ts.map +1 -1
- package/dist/connect.js +8 -2
- 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/find.js +1 -1
- package/dist/find.js.map +1 -1
- package/dist/findDistinct.d.ts.map +1 -1
- package/dist/findDistinct.js +52 -8
- package/dist/findDistinct.js.map +1 -1
- package/dist/findOne.js +1 -1
- package/dist/findOne.js.map +1 -1
- package/dist/migrateFresh.d.ts +4 -2
- package/dist/migrateFresh.d.ts.map +1 -1
- package/dist/migrateFresh.js +20 -6
- package/dist/migrateFresh.js.map +1 -1
- 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/queries/buildSearchParams.d.ts.map +1 -1
- package/dist/queries/buildSearchParams.js +189 -6
- package/dist/queries/buildSearchParams.js.map +1 -1
- package/dist/queries/parseParams.js.map +1 -1
- package/dist/queryDrafts.js +1 -1
- package/dist/queryDrafts.js.map +1 -1
- package/dist/utilities/buildJoinAggregation.d.ts +1 -1
- package/dist/utilities/buildJoinAggregation.d.ts.map +1 -1
- package/dist/utilities/buildJoinAggregation.js +2 -2
- package/dist/utilities/buildJoinAggregation.js.map +1 -1
- package/dist/utilities/transform.d.ts.map +1 -1
- package/dist/utilities/transform.js +15 -0
- package/dist/utilities/transform.js.map +1 -1
- package/package.json +5 -5
- 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 -479
- package/dist/utilities/transform.spec.js.map +0 -1
package/dist/migrateFresh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/migrateFresh.ts"],"sourcesContent":["import { commitTransaction, initTransaction, killTransaction, readMigrationFiles } from 'payload'\nimport prompts from 'prompts'\n\nimport type { MongooseAdapter } from './index.js'\n\n/**\n * Drop the current database and run all migrate up functions\n */\nexport async function migrateFresh(\n this: MongooseAdapter,\n {
|
|
1
|
+
{"version":3,"sources":["../src/migrateFresh.ts"],"sourcesContent":["import type { MigrationResult } from 'payload'\n\nimport { commitTransaction, initTransaction, killTransaction, readMigrationFiles } from 'payload'\nimport prompts from 'prompts'\n\nimport type { MongooseAdapter } from './index.js'\n\n/**\n * Drop the current database and run all migrate up functions\n */\nexport async function migrateFresh(\n this: MongooseAdapter,\n {\n forceAcceptWarning = false,\n shouldPrompt = true,\n }: { forceAcceptWarning?: boolean; shouldPrompt?: boolean },\n): Promise<MigrationResult> {\n const { payload } = this\n\n if (!forceAcceptWarning) {\n if (!shouldPrompt) {\n return { cancelled: true, migrated: [], rolledBack: [] }\n }\n\n const { confirm: acceptWarning } = await prompts({\n name: 'confirm',\n type: 'confirm',\n initial: false,\n message: `WARNING: This will drop your database and run all migrations. Are you sure you want to proceed?`,\n })\n\n if (!acceptWarning) {\n return { cancelled: true, migrated: [], rolledBack: [] }\n }\n }\n\n payload.logger.info({\n msg: `Dropping database.`,\n })\n\n await this.connection.dropDatabase()\n\n const migrationFiles = await readMigrationFiles({ payload })\n payload.logger.debug({\n msg: `Found ${migrationFiles.length} migration files.`,\n })\n\n const req = { payload }\n const migrated: string[] = []\n\n // Run all migrate up\n for (const migration of migrationFiles) {\n payload.logger.info({ msg: `Migrating: ${migration.name}` })\n try {\n const start = Date.now()\n await initTransaction(req)\n await migration.up({ payload, req })\n await payload.create({\n collection: 'payload-migrations',\n data: {\n name: migration.name,\n batch: 1,\n },\n req,\n })\n\n await commitTransaction(req)\n migrated.push(migration.name)\n\n payload.logger.info({ msg: `Migrated: ${migration.name} (${Date.now() - start}ms)` })\n } catch (err: unknown) {\n await killTransaction(req)\n payload.logger.error({\n err,\n msg: `Error running migration ${migration.name}. Rolling back.`,\n })\n throw err\n }\n }\n\n return { batch: 1, migrated, rolledBack: [] }\n}\n"],"names":["commitTransaction","initTransaction","killTransaction","readMigrationFiles","prompts","migrateFresh","forceAcceptWarning","shouldPrompt","payload","cancelled","migrated","rolledBack","confirm","acceptWarning","name","type","initial","message","logger","info","msg","connection","dropDatabase","migrationFiles","debug","length","req","migration","start","Date","now","up","create","collection","data","batch","push","err","error"],"mappings":"AAEA,SAASA,iBAAiB,EAAEC,eAAe,EAAEC,eAAe,EAAEC,kBAAkB,QAAQ,UAAS;AACjG,OAAOC,aAAa,UAAS;AAI7B;;CAEC,GACD,OAAO,eAAeC,aAEpB,EACEC,qBAAqB,KAAK,EAC1BC,eAAe,IAAI,EACsC;IAE3D,MAAM,EAAEC,OAAO,EAAE,GAAG,IAAI;IAExB,IAAI,CAACF,oBAAoB;QACvB,IAAI,CAACC,cAAc;YACjB,OAAO;gBAAEE,WAAW;gBAAMC,UAAU,EAAE;gBAAEC,YAAY,EAAE;YAAC;QACzD;QAEA,MAAM,EAAEC,SAASC,aAAa,EAAE,GAAG,MAAMT,QAAQ;YAC/CU,MAAM;YACNC,MAAM;YACNC,SAAS;YACTC,SAAS,CAAC,+FAA+F,CAAC;QAC5G;QAEA,IAAI,CAACJ,eAAe;YAClB,OAAO;gBAAEJ,WAAW;gBAAMC,UAAU,EAAE;gBAAEC,YAAY,EAAE;YAAC;QACzD;IACF;IAEAH,QAAQU,MAAM,CAACC,IAAI,CAAC;QAClBC,KAAK,CAAC,kBAAkB,CAAC;IAC3B;IAEA,MAAM,IAAI,CAACC,UAAU,CAACC,YAAY;IAElC,MAAMC,iBAAiB,MAAMpB,mBAAmB;QAAEK;IAAQ;IAC1DA,QAAQU,MAAM,CAACM,KAAK,CAAC;QACnBJ,KAAK,CAAC,MAAM,EAAEG,eAAeE,MAAM,CAAC,iBAAiB,CAAC;IACxD;IAEA,MAAMC,MAAM;QAAElB;IAAQ;IACtB,MAAME,WAAqB,EAAE;IAE7B,qBAAqB;IACrB,KAAK,MAAMiB,aAAaJ,eAAgB;QACtCf,QAAQU,MAAM,CAACC,IAAI,CAAC;YAAEC,KAAK,CAAC,WAAW,EAAEO,UAAUb,IAAI,EAAE;QAAC;QAC1D,IAAI;YACF,MAAMc,QAAQC,KAAKC,GAAG;YACtB,MAAM7B,gBAAgByB;YACtB,MAAMC,UAAUI,EAAE,CAAC;gBAAEvB;gBAASkB;YAAI;YAClC,MAAMlB,QAAQwB,MAAM,CAAC;gBACnBC,YAAY;gBACZC,MAAM;oBACJpB,MAAMa,UAAUb,IAAI;oBACpBqB,OAAO;gBACT;gBACAT;YACF;YAEA,MAAM1B,kBAAkB0B;YACxBhB,SAAS0B,IAAI,CAACT,UAAUb,IAAI;YAE5BN,QAAQU,MAAM,CAACC,IAAI,CAAC;gBAAEC,KAAK,CAAC,WAAW,EAAEO,UAAUb,IAAI,CAAC,EAAE,EAAEe,KAAKC,GAAG,KAAKF,MAAM,GAAG,CAAC;YAAC;QACtF,EAAE,OAAOS,KAAc;YACrB,MAAMnC,gBAAgBwB;YACtBlB,QAAQU,MAAM,CAACoB,KAAK,CAAC;gBACnBD;gBACAjB,KAAK,CAAC,wBAAwB,EAAEO,UAAUb,IAAI,CAAC,eAAe,CAAC;YACjE;YACA,MAAMuB;QACR;IACF;IAEA,OAAO;QAAEF,OAAO;QAAGzB;QAAUC,YAAY,EAAE;IAAC;AAC9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrateRelationshipsV2_V3.d.ts","sourceRoot":"","sources":["../../src/predefinedMigrations/migrateRelationshipsV2_V3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAS,cAAc,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"migrateRelationshipsV2_V3.d.ts","sourceRoot":"","sources":["../../src/predefinedMigrations/migrateRelationshipsV2_V3.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAS,cAAc,EAAE,MAAM,SAAS,CAAA;AA4GpD,wBAAsB,yBAAyB,CAAC,EAC9C,SAAS,EACT,GAAG,GACJ,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,cAAc,CAAA;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqGhB"}
|
|
@@ -28,8 +28,9 @@ const migrateModelWithBatching = async ({ batchSize, db, fields, Model, parentIs
|
|
|
28
28
|
parentIsLocalized
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// Writing through the driver collection skips Mongoose timestamps entirely,
|
|
32
|
+
// which is what we want here - timestamps are added by the write transform above
|
|
33
|
+
await Model.collection.bulkWrite(docs.map((doc)=>({
|
|
33
34
|
updateOne: {
|
|
34
35
|
filter: {
|
|
35
36
|
_id: doc._id
|
|
@@ -39,8 +40,7 @@ const migrateModelWithBatching = async ({ batchSize, db, fields, Model, parentIs
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
})), {
|
|
42
|
-
session
|
|
43
|
-
timestamps: false
|
|
43
|
+
session
|
|
44
44
|
});
|
|
45
45
|
skip += batchSize;
|
|
46
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/predefinedMigrations/migrateRelationshipsV2_V3.ts"],"sourcesContent":["import type { ClientSession, Model } from 'mongoose'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'\n\nimport type { MongooseAdapter } from '../index.js'\n\nimport { getCollection, getGlobal } from '../utilities/getEntity.js'\nimport { getSession } from '../utilities/getSession.js'\nimport { transform } from '../utilities/transform.js'\n\nconst migrateModelWithBatching = async ({\n batchSize,\n db,\n fields,\n Model,\n parentIsLocalized,\n session,\n}: {\n batchSize: number\n db: MongooseAdapter\n fields: Field[]\n Model: Model<any>\n parentIsLocalized: boolean\n session?: ClientSession\n}): Promise<void> => {\n let hasNext = true\n let skip = 0\n\n while (hasNext) {\n const docs = await Model.find(\n {},\n {},\n {\n lean: true,\n limit: batchSize + 1,\n session,\n skip,\n },\n )\n\n if (docs.length === 0) {\n break\n }\n\n hasNext = docs.length > batchSize\n\n if (hasNext) {\n docs.pop()\n }\n\n for (const doc of docs) {\n transform({ adapter: db, data: doc, fields, operation: 'write', parentIsLocalized })\n }\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/predefinedMigrations/migrateRelationshipsV2_V3.ts"],"sourcesContent":["import type { ClientSession, Model } from 'mongoose'\nimport type { Field, PayloadRequest } from 'payload'\n\nimport { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'\n\nimport type { MongooseAdapter } from '../index.js'\n\nimport { getCollection, getGlobal } from '../utilities/getEntity.js'\nimport { getSession } from '../utilities/getSession.js'\nimport { transform } from '../utilities/transform.js'\n\nconst migrateModelWithBatching = async ({\n batchSize,\n db,\n fields,\n Model,\n parentIsLocalized,\n session,\n}: {\n batchSize: number\n db: MongooseAdapter\n fields: Field[]\n Model: Model<any>\n parentIsLocalized: boolean\n session?: ClientSession\n}): Promise<void> => {\n let hasNext = true\n let skip = 0\n\n while (hasNext) {\n const docs = await Model.find(\n {},\n {},\n {\n lean: true,\n limit: batchSize + 1,\n session,\n skip,\n },\n )\n\n if (docs.length === 0) {\n break\n }\n\n hasNext = docs.length > batchSize\n\n if (hasNext) {\n docs.pop()\n }\n\n for (const doc of docs) {\n transform({ adapter: db, data: doc, fields, operation: 'write', parentIsLocalized })\n }\n\n // Writing through the driver collection skips Mongoose timestamps entirely,\n // which is what we want here - timestamps are added by the write transform above\n await Model.collection.bulkWrite(\n docs.map((doc) => ({\n updateOne: {\n filter: { _id: doc._id },\n update: {\n $set: doc,\n },\n },\n })),\n { session },\n )\n\n skip += batchSize\n }\n}\n\nconst hasRelationshipOrUploadField = ({ fields }: { fields: Field[] }): boolean => {\n for (const field of fields) {\n if (field.type === 'relationship' || field.type === 'upload') {\n return true\n }\n\n if ('fields' in field) {\n if (hasRelationshipOrUploadField({ fields: field.fields })) {\n return true\n }\n }\n\n if ('blocks' in field) {\n for (const block of field.blocks) {\n if (typeof block === 'string') {\n // Skip - string blocks have been added in v3 and thus don't need to be migrated\n continue\n }\n if (hasRelationshipOrUploadField({ fields: block.fields })) {\n return true\n }\n }\n }\n\n if ('tabs' in field) {\n for (const tab of field.tabs) {\n if (hasRelationshipOrUploadField({ fields: tab.fields })) {\n return true\n }\n }\n }\n }\n\n return false\n}\n\nexport async function migrateRelationshipsV2_V3({\n batchSize,\n req,\n}: {\n batchSize: number\n req: PayloadRequest\n}): Promise<void> {\n const { payload } = req\n const db = payload.db as MongooseAdapter\n const config = payload.config\n\n const session = await getSession(db, req)\n\n for (const collection of payload.config.collections) {\n if (hasRelationshipOrUploadField(collection)) {\n payload.logger.info(`Migrating collection \"${collection.slug}\"`)\n\n const { Model } = getCollection({ adapter: db, collectionSlug: collection.slug })\n\n await migrateModelWithBatching({\n batchSize,\n db,\n fields: collection.fields,\n Model,\n parentIsLocalized: false,\n session,\n })\n\n payload.logger.info(`Migrated collection \"${collection.slug}\"`)\n }\n\n if (collection.versions) {\n payload.logger.info(`Migrating collection versions \"${collection.slug}\"`)\n\n const { Model } = getCollection({\n adapter: db,\n collectionSlug: collection.slug,\n versions: true,\n })\n\n await migrateModelWithBatching({\n batchSize,\n db,\n fields: buildVersionCollectionFields(config, collection),\n Model,\n parentIsLocalized: false,\n session,\n })\n\n payload.logger.info(`Migrated collection versions \"${collection.slug}\"`)\n }\n }\n\n const { globals: GlobalsModel } = db\n\n for (const global of payload.config.globals) {\n if (hasRelationshipOrUploadField(global)) {\n payload.logger.info(`Migrating global \"${global.slug}\"`)\n\n const doc = (await GlobalsModel.findOne(\n {\n globalType: {\n $eq: global.slug,\n },\n },\n {},\n { lean: true, session },\n )) as null | Record<string, unknown>\n\n // in case if the global doesn't exist in the database yet (not saved)\n if (doc) {\n transform({\n adapter: db,\n data: doc,\n fields: global.fields,\n operation: 'write',\n })\n\n await GlobalsModel.collection.updateOne(\n {\n globalType: global.slug,\n },\n { $set: doc },\n { session },\n )\n }\n\n payload.logger.info(`Migrated global \"${global.slug}\"`)\n }\n\n if (global.versions) {\n payload.logger.info(`Migrating global versions \"${global.slug}\"`)\n\n const { Model } = getGlobal({ adapter: db, globalSlug: global.slug, versions: true })\n\n await migrateModelWithBatching({\n batchSize,\n db,\n fields: buildVersionGlobalFields(config, global),\n Model,\n parentIsLocalized: false,\n session,\n })\n\n payload.logger.info(`Migrated global versions \"${global.slug}\"`)\n }\n }\n}\n"],"names":["buildVersionCollectionFields","buildVersionGlobalFields","getCollection","getGlobal","getSession","transform","migrateModelWithBatching","batchSize","db","fields","Model","parentIsLocalized","session","hasNext","skip","docs","find","lean","limit","length","pop","doc","adapter","data","operation","collection","bulkWrite","map","updateOne","filter","_id","update","$set","hasRelationshipOrUploadField","field","type","block","blocks","tab","tabs","migrateRelationshipsV2_V3","req","payload","config","collections","logger","info","slug","collectionSlug","versions","globals","GlobalsModel","global","findOne","globalType","$eq","globalSlug"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildSearchParams.d.ts","sourceRoot":"","sources":["../../src/queries/buildSearchParams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"buildSearchParams.d.ts","sourceRoot":"","sources":["../../src/queries/buildSearchParams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAEd,QAAQ,EAER,OAAO,EACR,MAAM,SAAS,CAAA;AAkBhB,KAAK,WAAW,GAAG;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAMD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,cAAc,EACd,MAAM,EACN,UAAU,EACV,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,OAAO,EACP,GAAG,GACJ,EAAE;IACD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,QAAQ,CAAA;IAClB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,OAAO,CAAA;CACb,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAmZnC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Types } from 'mongoose';
|
|
2
2
|
import { APIError, escapeRegExp, getFieldByPath, getLocalizedPaths } from 'payload';
|
|
3
|
-
import { 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';
|
|
@@ -50,6 +50,27 @@ const subQueryOptions = {
|
|
|
50
50
|
return undefined;
|
|
51
51
|
}
|
|
52
52
|
const [{ field, path }] = paths;
|
|
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({
|
|
55
|
+
field,
|
|
56
|
+
locale,
|
|
57
|
+
nestedWhere: val,
|
|
58
|
+
operator: operator,
|
|
59
|
+
path,
|
|
60
|
+
payload
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (operator === 'contains' && paths.length === 1 && field.type === 'join' && typeof field.collection === 'string' && isNestedRelationshipQuery(val)) {
|
|
64
|
+
return buildJoinContainsSearchParam({
|
|
65
|
+
field,
|
|
66
|
+
locale,
|
|
67
|
+
nestedWhere: val,
|
|
68
|
+
payload
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if ((operator === 'contains' || operator === 'like' || operator === 'not_like') && (isNestedRelationshipQuery(val) || Array.isArray(val) && val.some((entry)=>isNestedRelationshipQuery(entry)))) {
|
|
72
|
+
throw new APIError(`Invalid value for "${operator}" on path "${path}": expected a string.`, 400);
|
|
73
|
+
}
|
|
53
74
|
if (path) {
|
|
54
75
|
const sanitizedQueryValue = sanitizeQueryValue({
|
|
55
76
|
field,
|
|
@@ -79,10 +100,16 @@ const subQueryOptions = {
|
|
|
79
100
|
// Remove top collection and reverse array
|
|
80
101
|
// to work backwards from top
|
|
81
102
|
const pathsToQuery = paths.slice(1).reverse();
|
|
103
|
+
const parentPaths = paths.slice(0, -1).reverse();
|
|
82
104
|
let relationshipQuery = {
|
|
83
105
|
value: {}
|
|
84
106
|
};
|
|
85
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
|
+
}
|
|
86
113
|
if (!collectionSlug) {
|
|
87
114
|
throw new APIError(`Collection with the slug ${collectionSlug} was not found.`);
|
|
88
115
|
}
|
|
@@ -100,15 +127,14 @@ const subQueryOptions = {
|
|
|
100
127
|
}
|
|
101
128
|
}
|
|
102
129
|
});
|
|
103
|
-
const field = paths[0].field;
|
|
104
130
|
const select = {
|
|
105
131
|
_id: true
|
|
106
132
|
};
|
|
107
133
|
let joinPath = null;
|
|
108
|
-
if (
|
|
134
|
+
if (parentField.type === 'join') {
|
|
109
135
|
const relationshipField = getFieldByPath({
|
|
110
136
|
fields: collectionConfig.flattenedFields,
|
|
111
|
-
path:
|
|
137
|
+
path: parentField.on
|
|
112
138
|
});
|
|
113
139
|
if (!relationshipField) {
|
|
114
140
|
throw new APIError('Relationship field was not found');
|
|
@@ -167,14 +193,53 @@ const subQueryOptions = {
|
|
|
167
193
|
const nextSubPath = pathsToQuery[i + 1]?.path;
|
|
168
194
|
if (nextSubPath) {
|
|
169
195
|
relationshipQuery = {
|
|
170
|
-
value: {
|
|
171
|
-
|
|
196
|
+
value: joinPath ? {
|
|
197
|
+
_id: {
|
|
198
|
+
$in
|
|
199
|
+
}
|
|
200
|
+
} : {
|
|
201
|
+
[nextSubPath]: {
|
|
202
|
+
$in
|
|
203
|
+
}
|
|
172
204
|
}
|
|
173
205
|
};
|
|
174
206
|
}
|
|
175
207
|
continue;
|
|
176
208
|
}
|
|
177
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
|
+
}
|
|
178
243
|
const result = await SubModel.find(subQuery, subQueryOptions);
|
|
179
244
|
const $in = result.map((doc)=>doc._id);
|
|
180
245
|
// If it is the last recursion
|
|
@@ -299,5 +364,123 @@ const subQueryOptions = {
|
|
|
299
364
|
}
|
|
300
365
|
return undefined;
|
|
301
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
|
+
}
|
|
302
485
|
|
|
303
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 { 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 * 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 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","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","sanitizedQueryValue","formattedOperator","rawQuery","formattedValue","length","value","pathsToQuery","slice","reverse","relationshipQuery","i","subPath","entries","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","Array","isArray","map","item","flat","filter","stringID","toString","ObjectId","isValid","nextSubPath","has","operatorKey","hasNumberIDRelation","multiIDCondition","relationTo","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,"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"}
|
package/dist/queryDrafts.js
CHANGED
|
@@ -105,7 +105,7 @@ export const queryDrafts = async function queryDrafts({ collection: collectionSl
|
|
|
105
105
|
query: versionQuery,
|
|
106
106
|
versions: true
|
|
107
107
|
});
|
|
108
|
-
if (aggregate || sortAggregation.length > 0) {
|
|
108
|
+
if (aggregate.length > 0 || sortAggregation.length > 0) {
|
|
109
109
|
result = await aggregatePaginate({
|
|
110
110
|
adapter: this,
|
|
111
111
|
collation: paginationOptions.collation,
|
package/dist/queryDrafts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/queryDrafts.ts"],"sourcesContent":["import type { PaginateOptions, PipelineStage, QueryOptions } from 'mongoose'\nimport type { QueryDrafts } from 'payload'\n\nimport { buildVersionCollectionFields, combineQueries, flattenWhereToOperators } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nimport { buildQuery } from './queries/buildQuery.js'\nimport { buildSortParam } from './queries/buildSortParam.js'\nimport { aggregatePaginate } from './utilities/aggregatePaginate.js'\nimport { buildJoinAggregation } from './utilities/buildJoinAggregation.js'\nimport { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'\nimport { getCollection } from './utilities/getEntity.js'\nimport { getSession } from './utilities/getSession.js'\nimport { resolveJoins } from './utilities/resolveJoins.js'\nimport { transform } from './utilities/transform.js'\n\nexport const queryDrafts: QueryDrafts = async function queryDrafts(\n this: MongooseAdapter,\n {\n collection: collectionSlug,\n joins,\n limit,\n locale,\n page,\n pagination,\n req,\n select,\n sort: sortArg,\n where = {},\n },\n) {\n const { collectionConfig, Model } = getCollection({\n adapter: this,\n collectionSlug,\n versions: true,\n })\n\n let hasNearConstraint\n let sort\n\n if (where) {\n const constraints = flattenWhereToOperators(where)\n hasNearConstraint = constraints.some((prop) => Object.keys(prop).some((key) => key === 'near'))\n }\n\n const fields = buildVersionCollectionFields(this.payload.config, collectionConfig, true)\n\n const sortAggregation: PipelineStage[] = []\n if (!hasNearConstraint) {\n sort = buildSortParam({\n adapter: this,\n config: this.payload.config,\n fields,\n locale,\n sort: sortArg || collectionConfig.defaultSort,\n sortAggregation,\n timestamps: true,\n versions: true,\n })\n }\n\n const combinedWhere = combineQueries({ latest: { equals: true } }, where)\n\n const versionQuery = await buildQuery({\n adapter: this,\n fields,\n locale,\n where: combinedWhere,\n })\n\n const projection = buildProjectionFromSelect({\n adapter: this,\n fields,\n select,\n })\n\n const session = await getSession(this, req)\n const options: QueryOptions = {\n session,\n }\n\n // useEstimatedCount is faster, but not accurate, as it ignores any filters. It is thus set to true if there are no filters.\n const useEstimatedCount =\n hasNearConstraint || !versionQuery || Object.keys(versionQuery).length === 0\n const paginationOptions: PaginateOptions = {\n lean: true,\n leanWithId: true,\n options,\n page,\n pagination,\n projection,\n sort,\n useEstimatedCount,\n }\n\n if (this.collation) {\n const localizationConfig = this.payload.config.localization\n const defaultLocale =\n (typeof localizationConfig === 'object' && localizationConfig?.defaultLocale) || 'en'\n\n paginationOptions.collation = {\n locale: locale && locale !== 'all' && locale !== '*' ? locale : defaultLocale,\n ...this.collation,\n }\n }\n\n if (\n !useEstimatedCount &&\n Object.keys(versionQuery).length === 0 &&\n this.disableIndexHints !== true\n ) {\n // Improve the performance of the countDocuments query which is used if useEstimatedCount is set to false by adding\n // a hint. By default, if no hint is provided, MongoDB does not use an indexed field to count the returned documents,\n // which makes queries very slow. This only happens when no query (filter) is provided. If one is provided, it uses\n // the correct indexed field\n paginationOptions.useCustomCountFn = () => {\n return Promise.resolve(\n Model.countDocuments(versionQuery, {\n collation: paginationOptions.collation,\n hint: { _id: 1 },\n session,\n }),\n )\n }\n }\n\n if (limit && limit > 0) {\n paginationOptions.limit = limit\n // limit must also be set here, it's ignored when pagination is false\n\n paginationOptions.options!.limit = limit\n }\n\n let result\n\n const aggregate = await buildJoinAggregation({\n adapter: this,\n collection: collectionSlug,\n collectionConfig,\n joins,\n locale,\n projection,\n query: versionQuery,\n versions: true,\n })\n\n if (aggregate || sortAggregation.length > 0) {\n result = await aggregatePaginate({\n adapter: this,\n collation: paginationOptions.collation,\n joinAggregation: aggregate,\n limit: paginationOptions.limit,\n Model,\n page: paginationOptions.page,\n pagination: paginationOptions.pagination,\n projection: paginationOptions.projection,\n query: versionQuery,\n session: paginationOptions.options?.session ?? undefined,\n sort: paginationOptions.sort as object,\n sortAggregation,\n useEstimatedCount: paginationOptions.useEstimatedCount,\n })\n } else {\n result = await Model.paginate(versionQuery, paginationOptions)\n }\n\n if (!this.useJoinAggregations) {\n await resolveJoins({\n adapter: this,\n collectionSlug,\n docs: result.docs as Record<string, unknown>[],\n joins,\n locale,\n versions: true,\n })\n }\n\n transform({\n adapter: this,\n data: result.docs,\n fields: buildVersionCollectionFields(this.payload.config, collectionConfig),\n operation: 'read',\n })\n\n for (let i = 0; i < result.docs.length; i++) {\n const id = result.docs[i].parent\n result.docs[i] = result.docs[i].version ?? {}\n result.docs[i].id = id\n }\n\n return result\n}\n"],"names":["buildVersionCollectionFields","combineQueries","flattenWhereToOperators","buildQuery","buildSortParam","aggregatePaginate","buildJoinAggregation","buildProjectionFromSelect","getCollection","getSession","resolveJoins","transform","queryDrafts","collection","collectionSlug","joins","limit","locale","page","pagination","req","select","sort","sortArg","where","collectionConfig","Model","adapter","versions","hasNearConstraint","constraints","some","prop","Object","keys","key","fields","payload","config","sortAggregation","defaultSort","timestamps","combinedWhere","latest","equals","versionQuery","projection","session","options","useEstimatedCount","length","paginationOptions","lean","leanWithId","collation","localizationConfig","localization","defaultLocale","disableIndexHints","useCustomCountFn","Promise","resolve","countDocuments","hint","_id","result","aggregate","query","joinAggregation","undefined","paginate","useJoinAggregations","docs","data","operation","i","id","parent","version"],"mappings":"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
|
|
1
|
+
{"version":3,"sources":["../src/queryDrafts.ts"],"sourcesContent":["import type { PaginateOptions, PipelineStage, QueryOptions } from 'mongoose'\nimport type { QueryDrafts } from 'payload'\n\nimport { buildVersionCollectionFields, combineQueries, flattenWhereToOperators } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nimport { buildQuery } from './queries/buildQuery.js'\nimport { buildSortParam } from './queries/buildSortParam.js'\nimport { aggregatePaginate } from './utilities/aggregatePaginate.js'\nimport { buildJoinAggregation } from './utilities/buildJoinAggregation.js'\nimport { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'\nimport { getCollection } from './utilities/getEntity.js'\nimport { getSession } from './utilities/getSession.js'\nimport { resolveJoins } from './utilities/resolveJoins.js'\nimport { transform } from './utilities/transform.js'\n\nexport const queryDrafts: QueryDrafts = async function queryDrafts(\n this: MongooseAdapter,\n {\n collection: collectionSlug,\n joins,\n limit,\n locale,\n page,\n pagination,\n req,\n select,\n sort: sortArg,\n where = {},\n },\n) {\n const { collectionConfig, Model } = getCollection({\n adapter: this,\n collectionSlug,\n versions: true,\n })\n\n let hasNearConstraint\n let sort\n\n if (where) {\n const constraints = flattenWhereToOperators(where)\n hasNearConstraint = constraints.some((prop) => Object.keys(prop).some((key) => key === 'near'))\n }\n\n const fields = buildVersionCollectionFields(this.payload.config, collectionConfig, true)\n\n const sortAggregation: PipelineStage[] = []\n if (!hasNearConstraint) {\n sort = buildSortParam({\n adapter: this,\n config: this.payload.config,\n fields,\n locale,\n sort: sortArg || collectionConfig.defaultSort,\n sortAggregation,\n timestamps: true,\n versions: true,\n })\n }\n\n const combinedWhere = combineQueries({ latest: { equals: true } }, where)\n\n const versionQuery = await buildQuery({\n adapter: this,\n fields,\n locale,\n where: combinedWhere,\n })\n\n const projection = buildProjectionFromSelect({\n adapter: this,\n fields,\n select,\n })\n\n const session = await getSession(this, req)\n const options: QueryOptions = {\n session,\n }\n\n // useEstimatedCount is faster, but not accurate, as it ignores any filters. It is thus set to true if there are no filters.\n const useEstimatedCount =\n hasNearConstraint || !versionQuery || Object.keys(versionQuery).length === 0\n const paginationOptions: PaginateOptions = {\n lean: true,\n leanWithId: true,\n options,\n page,\n pagination,\n projection,\n sort,\n useEstimatedCount,\n }\n\n if (this.collation) {\n const localizationConfig = this.payload.config.localization\n const defaultLocale =\n (typeof localizationConfig === 'object' && localizationConfig?.defaultLocale) || 'en'\n\n paginationOptions.collation = {\n locale: locale && locale !== 'all' && locale !== '*' ? locale : defaultLocale,\n ...this.collation,\n }\n }\n\n if (\n !useEstimatedCount &&\n Object.keys(versionQuery).length === 0 &&\n this.disableIndexHints !== true\n ) {\n // Improve the performance of the countDocuments query which is used if useEstimatedCount is set to false by adding\n // a hint. By default, if no hint is provided, MongoDB does not use an indexed field to count the returned documents,\n // which makes queries very slow. This only happens when no query (filter) is provided. If one is provided, it uses\n // the correct indexed field\n paginationOptions.useCustomCountFn = () => {\n return Promise.resolve(\n Model.countDocuments(versionQuery, {\n collation: paginationOptions.collation,\n hint: { _id: 1 },\n session,\n }),\n )\n }\n }\n\n if (limit && limit > 0) {\n paginationOptions.limit = limit\n // limit must also be set here, it's ignored when pagination is false\n\n paginationOptions.options!.limit = limit\n }\n\n let result\n\n const aggregate = await buildJoinAggregation({\n adapter: this,\n collection: collectionSlug,\n collectionConfig,\n joins,\n locale,\n projection,\n query: versionQuery,\n versions: true,\n })\n\n if (aggregate.length > 0 || sortAggregation.length > 0) {\n result = await aggregatePaginate({\n adapter: this,\n collation: paginationOptions.collation,\n joinAggregation: aggregate,\n limit: paginationOptions.limit,\n Model,\n page: paginationOptions.page,\n pagination: paginationOptions.pagination,\n projection: paginationOptions.projection,\n query: versionQuery,\n session: paginationOptions.options?.session ?? undefined,\n sort: paginationOptions.sort as object,\n sortAggregation,\n useEstimatedCount: paginationOptions.useEstimatedCount,\n })\n } else {\n result = await Model.paginate(versionQuery, paginationOptions)\n }\n\n if (!this.useJoinAggregations) {\n await resolveJoins({\n adapter: this,\n collectionSlug,\n docs: result.docs as Record<string, unknown>[],\n joins,\n locale,\n versions: true,\n })\n }\n\n transform({\n adapter: this,\n data: result.docs,\n fields: buildVersionCollectionFields(this.payload.config, collectionConfig),\n operation: 'read',\n })\n\n for (let i = 0; i < result.docs.length; i++) {\n const id = result.docs[i].parent\n result.docs[i] = result.docs[i].version ?? {}\n result.docs[i].id = id\n }\n\n return result\n}\n"],"names":["buildVersionCollectionFields","combineQueries","flattenWhereToOperators","buildQuery","buildSortParam","aggregatePaginate","buildJoinAggregation","buildProjectionFromSelect","getCollection","getSession","resolveJoins","transform","queryDrafts","collection","collectionSlug","joins","limit","locale","page","pagination","req","select","sort","sortArg","where","collectionConfig","Model","adapter","versions","hasNearConstraint","constraints","some","prop","Object","keys","key","fields","payload","config","sortAggregation","defaultSort","timestamps","combinedWhere","latest","equals","versionQuery","projection","session","options","useEstimatedCount","length","paginationOptions","lean","leanWithId","collation","localizationConfig","localization","defaultLocale","disableIndexHints","useCustomCountFn","Promise","resolve","countDocuments","hint","_id","result","aggregate","query","joinAggregation","undefined","paginate","useJoinAggregations","docs","data","operation","i","id","parent","version"],"mappings":"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"}
|
|
@@ -13,6 +13,6 @@ type BuildJoinAggregationArgs = {
|
|
|
13
13
|
/** whether the query is from drafts */
|
|
14
14
|
versions?: boolean;
|
|
15
15
|
};
|
|
16
|
-
export declare const buildJoinAggregation: ({ adapter, collection, collectionConfig, draftsEnabled, joins, locale, projection, versions, }: BuildJoinAggregationArgs) => Promise<PipelineStage[]
|
|
16
|
+
export declare const buildJoinAggregation: ({ adapter, collection, collectionConfig, draftsEnabled, joins, locale, projection, versions, }: BuildJoinAggregationArgs) => Promise<PipelineStage[]>;
|
|
17
17
|
export {};
|
|
18
18
|
//# sourceMappingURL=buildJoinAggregation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildJoinAggregation.d.ts","sourceRoot":"","sources":["../../src/utilities/buildJoinAggregation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,EAIL,KAAK,cAAc,EAInB,KAAK,SAAS,EACd,KAAK,yBAAyB,EAC/B,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAOlD,KAAK,wBAAwB,GAAG;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,UAAU,EAAE,cAAc,CAAA;IAC1B,gBAAgB,EAAE,yBAAyB,CAAA;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,oBAAoB,mGAS9B,wBAAwB,KAAG,OAAO,CAAC,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"buildJoinAggregation.d.ts","sourceRoot":"","sources":["../../src/utilities/buildJoinAggregation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,EAIL,KAAK,cAAc,EAInB,KAAK,SAAS,EACd,KAAK,yBAAyB,EAC/B,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAOlD,KAAK,wBAAwB,GAAG;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,UAAU,EAAE,cAAc,CAAA;IAC1B,gBAAgB,EAAE,yBAAyB,CAAA;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAEjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,eAAO,MAAM,oBAAoB,mGAS9B,wBAAwB,KAAG,OAAO,CAAC,aAAa,EAAE,CA0cpD,CAAA"}
|
|
@@ -5,10 +5,10 @@ import { buildSortParam } from '../queries/buildSortParam.js';
|
|
|
5
5
|
import { getCollection } from './getEntity.js';
|
|
6
6
|
export const buildJoinAggregation = async ({ adapter, collection, collectionConfig, draftsEnabled, joins, locale, projection, versions })=>{
|
|
7
7
|
if (!adapter.useJoinAggregations) {
|
|
8
|
-
return;
|
|
8
|
+
return [];
|
|
9
9
|
}
|
|
10
10
|
if (Object.keys(collectionConfig.joins).length === 0 && collectionConfig.polymorphicJoins.length == 0 || joins === false) {
|
|
11
|
-
return;
|
|
11
|
+
return [];
|
|
12
12
|
}
|
|
13
13
|
const joinConfig = adapter.payload.collections[collection]?.config?.joins;
|
|
14
14
|
if (!joinConfig) {
|