@payloadcms/db-mongodb 4.0.0-canary.33 → 4.0.0-canary.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,SAAS,CAAA;AAOjD,eAAO,MAAM,OAAO,EAAE,OA4GrB,CAAA"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,SAAS,CAAA;AAOjD,eAAO,MAAM,OAAO,EAAE,OAkHrB,CAAA"}
package/dist/connect.js CHANGED
@@ -64,8 +64,14 @@ export const connect = async function connect(options = {
64
64
  }
65
65
  }
66
66
  if (this.ensureIndexes) {
67
- await Promise.all(this.payload.config.collections.map(async (coll)=>{
68
- await this.collections[coll.slug]?.ensureIndexes();
67
+ await Promise.all([
68
+ ...this.payload.config.collections.flatMap((collection)=>[
69
+ this.collections[collection.slug],
70
+ this.versions[collection.slug]
71
+ ]),
72
+ ...this.payload.config.globals.map((global)=>this.versions[global.slug])
73
+ ].map(async (model)=>{
74
+ await model?.ensureIndexes();
69
75
  }));
70
76
  }
71
77
  if (process.env.NODE_ENV === 'production' && this.prodMigrations) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/connect.ts"],"sourcesContent":["import type { ConnectOptions } from 'mongoose'\nimport type { Connect, Migration } from 'payload'\n\nimport mongoose from 'mongoose'\nimport { defaultBeginTransaction } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nexport const connect: Connect = async function connect(\n this: MongooseAdapter,\n options = {\n hotReload: false,\n },\n) {\n const { hotReload } = options\n\n if (this.url === false) {\n return\n }\n\n if (typeof this.url !== 'string') {\n throw new Error('Error: missing MongoDB connection URL.')\n }\n\n const urlToConnect = this.url\n\n const connectionOptions: ConnectOptions = {\n autoIndex: true,\n ...this.connectOptions,\n }\n\n if (hotReload) {\n connectionOptions.autoIndex = false\n }\n\n try {\n if (!this.connection) {\n this.connection = await mongoose.createConnection(urlToConnect, connectionOptions).asPromise()\n if (this.afterCreateConnection) {\n await this.afterCreateConnection(this)\n }\n }\n\n await this.connection.openUri(urlToConnect, connectionOptions)\n\n if (this.afterOpenConnection) {\n await this.afterOpenConnection(this)\n }\n\n if (this.useAlternativeDropDatabase) {\n if (this.connection.db) {\n // Firestore doesn't support dropDatabase, so we monkey patch\n // dropDatabase to delete all documents from all collections instead\n this.connection.db.dropDatabase = async function (): Promise<boolean> {\n const existingCollections = await this.listCollections().toArray()\n await Promise.all(\n existingCollections.map(async (collectionInfo) => {\n const collection = this.collection(collectionInfo.name)\n await collection.deleteMany({})\n }),\n )\n return true\n }\n this.connection.dropDatabase = async function () {\n await this.db?.dropDatabase()\n }\n }\n }\n\n // If we are running a replica set with MongoDB Memory Server,\n // wait until the replica set elects a primary before proceeding\n if (this.mongoMemoryServer) {\n this.payload.logger.info(\n 'Waiting for MongoDB Memory Server replica set to elect a primary...',\n )\n await new Promise((resolve) => setTimeout(resolve, 2000))\n }\n\n if (!this.connection.getClient().options.replicaSet) {\n this.transactionOptions = false\n this.beginTransaction = defaultBeginTransaction()\n }\n\n if (!hotReload) {\n if (process.env.PAYLOAD_DROP_DATABASE === 'true') {\n this.payload.logger.info('---- DROPPING DATABASE ----')\n await this.connection.dropDatabase()\n\n this.payload.logger.info('---- DROPPED DATABASE ----')\n }\n }\n\n if (this.ensureIndexes) {\n await Promise.all(\n this.payload.config.collections.map(async (coll) => {\n await this.collections[coll.slug]?.ensureIndexes()\n }),\n )\n }\n\n if (process.env.NODE_ENV === 'production' && this.prodMigrations) {\n await this.migrate({ migrations: this.prodMigrations as unknown as Migration[] })\n }\n } catch (err) {\n let msg = `Error: cannot connect to MongoDB.`\n\n if (typeof err === 'object' && err && 'message' in err && typeof err.message === 'string') {\n msg = `${msg} Details: ${err.message}`\n }\n\n this.payload.logger.error({\n err,\n msg,\n })\n throw new Error(`Error: cannot connect to MongoDB: ${msg}`)\n }\n}\n"],"names":["mongoose","defaultBeginTransaction","connect","options","hotReload","url","Error","urlToConnect","connectionOptions","autoIndex","connectOptions","connection","createConnection","asPromise","afterCreateConnection","openUri","afterOpenConnection","useAlternativeDropDatabase","db","dropDatabase","existingCollections","listCollections","toArray","Promise","all","map","collectionInfo","collection","name","deleteMany","mongoMemoryServer","payload","logger","info","resolve","setTimeout","getClient","replicaSet","transactionOptions","beginTransaction","process","env","PAYLOAD_DROP_DATABASE","ensureIndexes","config","collections","coll","slug","NODE_ENV","prodMigrations","migrate","migrations","err","msg","message","error"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/connect.ts"],"sourcesContent":["import type { ConnectOptions } from 'mongoose'\nimport type { Connect, Migration } from 'payload'\n\nimport mongoose from 'mongoose'\nimport { defaultBeginTransaction } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nexport const connect: Connect = async function connect(\n this: MongooseAdapter,\n options = {\n hotReload: false,\n },\n) {\n const { hotReload } = options\n\n if (this.url === false) {\n return\n }\n\n if (typeof this.url !== 'string') {\n throw new Error('Error: missing MongoDB connection URL.')\n }\n\n const urlToConnect = this.url\n\n const connectionOptions: ConnectOptions = {\n autoIndex: true,\n ...this.connectOptions,\n }\n\n if (hotReload) {\n connectionOptions.autoIndex = false\n }\n\n try {\n if (!this.connection) {\n this.connection = await mongoose.createConnection(urlToConnect, connectionOptions).asPromise()\n if (this.afterCreateConnection) {\n await this.afterCreateConnection(this)\n }\n }\n\n await this.connection.openUri(urlToConnect, connectionOptions)\n\n if (this.afterOpenConnection) {\n await this.afterOpenConnection(this)\n }\n\n if (this.useAlternativeDropDatabase) {\n if (this.connection.db) {\n // Firestore doesn't support dropDatabase, so we monkey patch\n // dropDatabase to delete all documents from all collections instead\n this.connection.db.dropDatabase = async function (): Promise<boolean> {\n const existingCollections = await this.listCollections().toArray()\n await Promise.all(\n existingCollections.map(async (collectionInfo) => {\n const collection = this.collection(collectionInfo.name)\n await collection.deleteMany({})\n }),\n )\n return true\n }\n this.connection.dropDatabase = async function () {\n await this.db?.dropDatabase()\n }\n }\n }\n\n // If we are running a replica set with MongoDB Memory Server,\n // wait until the replica set elects a primary before proceeding\n if (this.mongoMemoryServer) {\n this.payload.logger.info(\n 'Waiting for MongoDB Memory Server replica set to elect a primary...',\n )\n await new Promise((resolve) => setTimeout(resolve, 2000))\n }\n\n if (!this.connection.getClient().options.replicaSet) {\n this.transactionOptions = false\n this.beginTransaction = defaultBeginTransaction()\n }\n\n if (!hotReload) {\n if (process.env.PAYLOAD_DROP_DATABASE === 'true') {\n this.payload.logger.info('---- DROPPING DATABASE ----')\n await this.connection.dropDatabase()\n\n this.payload.logger.info('---- DROPPED DATABASE ----')\n }\n }\n\n if (this.ensureIndexes) {\n await Promise.all(\n [\n ...this.payload.config.collections.flatMap((collection) => [\n this.collections[collection.slug],\n this.versions[collection.slug],\n ]),\n ...this.payload.config.globals.map((global) => this.versions[global.slug]),\n ].map(async (model) => {\n await model?.ensureIndexes()\n }),\n )\n }\n\n if (process.env.NODE_ENV === 'production' && this.prodMigrations) {\n await this.migrate({ migrations: this.prodMigrations as unknown as Migration[] })\n }\n } catch (err) {\n let msg = `Error: cannot connect to MongoDB.`\n\n if (typeof err === 'object' && err && 'message' in err && typeof err.message === 'string') {\n msg = `${msg} Details: ${err.message}`\n }\n\n this.payload.logger.error({\n err,\n msg,\n })\n throw new Error(`Error: cannot connect to MongoDB: ${msg}`)\n }\n}\n"],"names":["mongoose","defaultBeginTransaction","connect","options","hotReload","url","Error","urlToConnect","connectionOptions","autoIndex","connectOptions","connection","createConnection","asPromise","afterCreateConnection","openUri","afterOpenConnection","useAlternativeDropDatabase","db","dropDatabase","existingCollections","listCollections","toArray","Promise","all","map","collectionInfo","collection","name","deleteMany","mongoMemoryServer","payload","logger","info","resolve","setTimeout","getClient","replicaSet","transactionOptions","beginTransaction","process","env","PAYLOAD_DROP_DATABASE","ensureIndexes","config","collections","flatMap","slug","versions","globals","global","model","NODE_ENV","prodMigrations","migrate","migrations","err","msg","message","error"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"findDistinct.d.ts","sourceRoot":"","sources":["../src/findDistinct.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,SAAS,CAAA;AA6C3D,eAAO,MAAM,YAAY,EAAE,YAsQ1B,CAAA"}
1
+ {"version":3,"file":"findDistinct.d.ts","sourceRoot":"","sources":["../src/findDistinct.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAkB,MAAM,SAAS,CAAA;AA6C3D,eAAO,MAAM,YAAY,EAAE,YA4S1B,CAAA"}
@@ -114,30 +114,74 @@ export const findDistinct = async function(args) {
114
114
  sortProperty = sortWithoutRelationPrefix;
115
115
  }
116
116
  }
117
- relationLookup = rels.reduce((acc, { fieldPath, relationTo })=>{
117
+ relationLookup = [];
118
+ for (const { fieldPath, relationTo } of rels){
118
119
  sortAggregation = sortAggregation.filter((each)=>{
119
120
  if ('$lookup' in each && each.$lookup.as.replace(/^_+/, '') === fieldPath) {
120
121
  return false;
121
122
  }
122
123
  return true;
123
124
  });
124
- const { Model: foreignModel } = getCollection({
125
+ const { collectionConfig: foreignCollectionConfig, Model: foreignModel } = getCollection({
125
126
  adapter: this,
126
127
  collectionSlug: relationTo
127
128
  });
128
- acc.push({
129
+ const relatedAccess = args.relatedAccess?.[fieldPath];
130
+ const relatedAccessQuery = relatedAccess ? await buildQuery({
131
+ adapter: this,
132
+ collectionSlug: relationTo,
133
+ fields: foreignCollectionConfig.flattenedFields,
134
+ locale: args.locale,
135
+ where: relatedAccess
136
+ }) : null;
137
+ relationLookup.push({
129
138
  $lookup: {
130
139
  as: fieldPath,
131
- foreignField: '_id',
132
140
  from: foreignModel.collection.name,
133
- localField: fieldPath
141
+ ...relatedAccessQuery ? {
142
+ let: {
143
+ relatedIDs: `$${fieldPath}`
144
+ },
145
+ pipeline: [
146
+ {
147
+ $match: {
148
+ $and: [
149
+ {
150
+ $expr: {
151
+ $cond: {
152
+ else: {
153
+ $eq: [
154
+ '$_id',
155
+ '$$relatedIDs'
156
+ ]
157
+ },
158
+ if: {
159
+ $isArray: '$$relatedIDs'
160
+ },
161
+ then: {
162
+ $in: [
163
+ '$_id',
164
+ '$$relatedIDs'
165
+ ]
166
+ }
167
+ }
168
+ }
169
+ },
170
+ relatedAccessQuery
171
+ ]
172
+ }
173
+ }
174
+ ]
175
+ } : {
176
+ foreignField: '_id',
177
+ localField: fieldPath
178
+ }
134
179
  }
135
180
  });
136
- acc.push({
181
+ relationLookup.push({
137
182
  $unwind: `$${fieldPath}`
138
183
  });
139
- return acc;
140
- }, []);
184
+ }
141
185
  }
142
186
  let $unwind = '';
143
187
  let $group = null;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/findDistinct.ts"],"sourcesContent":["import type { PipelineStage } from 'mongoose'\nimport type { FindDistinct, FlattenedField } from 'payload'\n\nimport { getFieldByPath } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nimport { buildQuery } from './queries/buildQuery.js'\nimport { buildSortParam } from './queries/buildSortParam.js'\nimport { getCollection } from './utilities/getEntity.js'\nimport { getSession } from './utilities/getSession.js'\n\nconst sanitizeGroupID = (id: any) => {\n if (id && typeof id === 'object' && '_field' in id) {\n return id._field\n }\n\n return id\n}\n\nconst getSortAggregation = ({\n fieldPath,\n hasSortAggregationAndHasMany,\n sortDirection,\n sortProperty,\n}: {\n fieldPath: string\n hasSortAggregationAndHasMany: boolean\n sortDirection: -1 | 1\n sortProperty: string\n}): Record<string, -1 | 1> => {\n let resolvedSortProperty: string\n\n if (hasSortAggregationAndHasMany) {\n if (sortProperty === fieldPath) {\n resolvedSortProperty = `_id._field`\n } else {\n resolvedSortProperty = `_id._sort`\n }\n } else {\n resolvedSortProperty = sortProperty === fieldPath ? '_id' : '_sort'\n }\n\n return { [`${resolvedSortProperty}`]: sortDirection }\n}\n\nexport const findDistinct: FindDistinct = async function (this: MongooseAdapter, args) {\n const { collectionConfig, Model } = getCollection({\n adapter: this,\n collectionSlug: args.collection,\n })\n\n const { where = {} } = args\n\n let sortAggregation: PipelineStage[] = []\n\n const sort = buildSortParam({\n adapter: this,\n config: this.payload.config,\n fields: collectionConfig.flattenedFields,\n locale: args.locale,\n sort: args.sort ?? args.field,\n sortAggregation,\n timestamps: true,\n })\n\n const query = await buildQuery({\n adapter: this,\n collectionSlug: args.collection,\n fields: collectionConfig.flattenedFields,\n locale: args.locale,\n where,\n })\n\n const fieldPathResult = getFieldByPath({\n config: this.payload.config,\n fields: collectionConfig.flattenedFields,\n includeRelationships: true,\n path: args.field,\n })\n let fieldPath = args.field\n if (fieldPathResult?.pathHasLocalized && args.locale) {\n fieldPath = fieldPathResult.localizedPath.replace('<locale>', args.locale)\n }\n\n const page = args.page || 1\n\n let sortProperty = Object.keys(sort)[0]! // assert because buildSortParam always returns at least 1 key.\n const sortDirection = sort[sortProperty] === 'asc' ? 1 : -1\n\n let currentFields = collectionConfig.flattenedFields\n let foundField: FlattenedField | null = null\n\n let rels: {\n fieldPath: string\n relationTo: string\n }[] = []\n\n let tempPath = ''\n let insideRelation = false\n\n const segments = args.field.split('.')\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n const field = currentFields.find((e) => e.name === segment)\n if (rels.length) {\n insideRelation = true\n }\n\n if (!field) {\n break\n }\n\n if (tempPath) {\n tempPath = `${tempPath}.${field.name}`\n } else {\n tempPath = field.name\n }\n\n if ('flattenedFields' in field) {\n currentFields = field.flattenedFields\n continue\n }\n\n if (\n (field.type === 'relationship' || field.type === 'upload') &&\n typeof field.relationTo === 'string'\n ) {\n if (i === segments.length - 2 && segments[i + 1] === 'id') {\n foundField = field\n fieldPath = tempPath\n break\n }\n rels.push({ fieldPath: tempPath, relationTo: field.relationTo })\n currentFields = this.payload.collections[field.relationTo]?.config\n .flattenedFields as FlattenedField[]\n continue\n }\n foundField = field\n }\n\n const resolvedField = foundField || fieldPathResult?.field\n const isHasManyValue = resolvedField && 'hasMany' in resolvedField && resolvedField\n\n let relationLookup: null | PipelineStage[] = null\n\n if (!insideRelation) {\n rels = []\n }\n\n if (rels.length) {\n if (sortProperty.startsWith('_')) {\n const sortWithoutRelationPrefix = sortProperty.replace(/^_+/, '')\n const lastFieldPath = rels.at(-1)?.fieldPath as string\n if (sortWithoutRelationPrefix.startsWith(lastFieldPath)) {\n sortProperty = sortWithoutRelationPrefix\n }\n }\n relationLookup = rels.reduce<PipelineStage[]>((acc, { fieldPath, relationTo }) => {\n sortAggregation = sortAggregation.filter((each) => {\n if ('$lookup' in each && each.$lookup.as.replace(/^_+/, '') === fieldPath) {\n return false\n }\n\n return true\n })\n const { Model: foreignModel } = getCollection({ adapter: this, collectionSlug: relationTo })\n acc.push({\n $lookup: {\n as: fieldPath,\n foreignField: '_id',\n from: foreignModel.collection.name,\n localField: fieldPath,\n },\n })\n acc.push({ $unwind: `$${fieldPath}` })\n return acc\n }, [])\n }\n\n let $unwind: any = ''\n let $group: any = null\n if (\n isHasManyValue &&\n sortAggregation.length &&\n sortAggregation[0] &&\n '$lookup' in sortAggregation[0]\n ) {\n $unwind = { path: `$${sortAggregation[0].$lookup.as}`, preserveNullAndEmptyArrays: true }\n $group = {\n _id: {\n _field: `$${sortAggregation[0].$lookup.as}._id`,\n _sort: `$${sortProperty}`,\n },\n }\n } else if (isHasManyValue) {\n $unwind = { path: `$${args.field}`, preserveNullAndEmptyArrays: true }\n }\n\n if (!$group) {\n $group = {\n _id: `$${fieldPath}`,\n ...(sortProperty === fieldPath\n ? {}\n : {\n _sort: { $max: `$${sortProperty}` },\n }),\n }\n }\n\n const pipeline: PipelineStage[] = [\n {\n $match: query,\n },\n ...(sortAggregation.length > 0 ? sortAggregation : []),\n ...(relationLookup?.length ? relationLookup : []),\n ...($unwind\n ? [\n {\n $unwind,\n },\n ]\n : []),\n {\n $group,\n },\n {\n $sort: getSortAggregation({\n fieldPath,\n hasSortAggregationAndHasMany: Boolean(isHasManyValue) && Boolean(sortAggregation.length),\n sortDirection,\n sortProperty,\n }),\n },\n ]\n\n const session = await getSession(this, args.req)\n\n const getValues = async () => {\n return Model.aggregate(pipeline, { session }).then((res) =>\n res.map((each) => ({\n [args.field]: JSON.parse(JSON.stringify(sanitizeGroupID(each._id))),\n })),\n )\n }\n\n if (args.limit) {\n pipeline.push({\n $skip: (page - 1) * args.limit,\n })\n pipeline.push({ $limit: args.limit })\n\n // Build count pipeline with the same structure as the main pipeline\n // to ensure relationship lookups are included\n const countPipeline: PipelineStage[] = [\n {\n $match: query,\n },\n ...(sortAggregation.length > 0 ? sortAggregation : []),\n ...(relationLookup?.length ? relationLookup : []),\n ...($unwind\n ? [\n {\n $unwind,\n },\n ]\n : []),\n {\n $group,\n },\n { $count: 'count' },\n ]\n\n const totalDocs = await Model.aggregate(countPipeline, {\n session,\n }).then((res) => res[0]?.count ?? 0)\n const totalPages = Math.ceil(totalDocs / args.limit)\n const hasPrevPage = page > 1\n const hasNextPage = totalPages > page\n const pagingCounter = (page - 1) * args.limit + 1\n\n return {\n hasNextPage,\n hasPrevPage,\n limit: args.limit,\n nextPage: hasNextPage ? page + 1 : null,\n page,\n pagingCounter,\n prevPage: hasPrevPage ? page - 1 : null,\n totalDocs,\n totalPages,\n values: await getValues(),\n }\n }\n\n const values = await getValues()\n\n return {\n hasNextPage: false,\n hasPrevPage: false,\n limit: 0,\n page: 1,\n pagingCounter: 1,\n totalDocs: values.length,\n totalPages: 1,\n values,\n }\n}\n"],"names":["getFieldByPath","buildQuery","buildSortParam","getCollection","getSession","sanitizeGroupID","id","_field","getSortAggregation","fieldPath","hasSortAggregationAndHasMany","sortDirection","sortProperty","resolvedSortProperty","findDistinct","args","collectionConfig","Model","adapter","collectionSlug","collection","where","sortAggregation","sort","config","payload","fields","flattenedFields","locale","field","timestamps","query","fieldPathResult","includeRelationships","path","pathHasLocalized","localizedPath","replace","page","Object","keys","currentFields","foundField","rels","tempPath","insideRelation","segments","split","i","length","segment","find","e","name","type","relationTo","push","collections","resolvedField","isHasManyValue","relationLookup","startsWith","sortWithoutRelationPrefix","lastFieldPath","at","reduce","acc","filter","each","$lookup","as","foreignModel","foreignField","from","localField","$unwind","$group","preserveNullAndEmptyArrays","_id","_sort","$max","pipeline","$match","$sort","Boolean","session","req","getValues","aggregate","then","res","map","JSON","parse","stringify","limit","$skip","$limit","countPipeline","$count","totalDocs","count","totalPages","Math","ceil","hasPrevPage","hasNextPage","pagingCounter","nextPage","prevPage","values"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/findDistinct.ts"],"sourcesContent":["import type { PipelineStage } from 'mongoose'\nimport type { FindDistinct, FlattenedField } from 'payload'\n\nimport { getFieldByPath } from 'payload'\n\nimport type { MongooseAdapter } from './index.js'\n\nimport { buildQuery } from './queries/buildQuery.js'\nimport { buildSortParam } from './queries/buildSortParam.js'\nimport { getCollection } from './utilities/getEntity.js'\nimport { getSession } from './utilities/getSession.js'\n\nconst sanitizeGroupID = (id: any) => {\n if (id && typeof id === 'object' && '_field' in id) {\n return id._field\n }\n\n return id\n}\n\nconst getSortAggregation = ({\n fieldPath,\n hasSortAggregationAndHasMany,\n sortDirection,\n sortProperty,\n}: {\n fieldPath: string\n hasSortAggregationAndHasMany: boolean\n sortDirection: -1 | 1\n sortProperty: string\n}): Record<string, -1 | 1> => {\n let resolvedSortProperty: string\n\n if (hasSortAggregationAndHasMany) {\n if (sortProperty === fieldPath) {\n resolvedSortProperty = `_id._field`\n } else {\n resolvedSortProperty = `_id._sort`\n }\n } else {\n resolvedSortProperty = sortProperty === fieldPath ? '_id' : '_sort'\n }\n\n return { [`${resolvedSortProperty}`]: sortDirection }\n}\n\nexport const findDistinct: FindDistinct = async function (this: MongooseAdapter, args) {\n const { collectionConfig, Model } = getCollection({\n adapter: this,\n collectionSlug: args.collection,\n })\n\n const { where = {} } = args\n\n let sortAggregation: PipelineStage[] = []\n\n const sort = buildSortParam({\n adapter: this,\n config: this.payload.config,\n fields: collectionConfig.flattenedFields,\n locale: args.locale,\n sort: args.sort ?? args.field,\n sortAggregation,\n timestamps: true,\n })\n\n const query = await buildQuery({\n adapter: this,\n collectionSlug: args.collection,\n fields: collectionConfig.flattenedFields,\n locale: args.locale,\n where,\n })\n\n const fieldPathResult = getFieldByPath({\n config: this.payload.config,\n fields: collectionConfig.flattenedFields,\n includeRelationships: true,\n path: args.field,\n })\n let fieldPath = args.field\n if (fieldPathResult?.pathHasLocalized && args.locale) {\n fieldPath = fieldPathResult.localizedPath.replace('<locale>', args.locale)\n }\n\n const page = args.page || 1\n\n let sortProperty = Object.keys(sort)[0]! // assert because buildSortParam always returns at least 1 key.\n const sortDirection = sort[sortProperty] === 'asc' ? 1 : -1\n\n let currentFields = collectionConfig.flattenedFields\n let foundField: FlattenedField | null = null\n\n let rels: {\n fieldPath: string\n relationTo: string\n }[] = []\n\n let tempPath = ''\n let insideRelation = false\n\n const segments = args.field.split('.')\n\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i]\n const field = currentFields.find((e) => e.name === segment)\n if (rels.length) {\n insideRelation = true\n }\n\n if (!field) {\n break\n }\n\n if (tempPath) {\n tempPath = `${tempPath}.${field.name}`\n } else {\n tempPath = field.name\n }\n\n if ('flattenedFields' in field) {\n currentFields = field.flattenedFields\n continue\n }\n\n if (\n (field.type === 'relationship' || field.type === 'upload') &&\n typeof field.relationTo === 'string'\n ) {\n if (i === segments.length - 2 && segments[i + 1] === 'id') {\n foundField = field\n fieldPath = tempPath\n break\n }\n rels.push({ fieldPath: tempPath, relationTo: field.relationTo })\n currentFields = this.payload.collections[field.relationTo]?.config\n .flattenedFields as FlattenedField[]\n continue\n }\n foundField = field\n }\n\n const resolvedField = foundField || fieldPathResult?.field\n const isHasManyValue = resolvedField && 'hasMany' in resolvedField && resolvedField\n\n let relationLookup: null | PipelineStage[] = null\n\n if (!insideRelation) {\n rels = []\n }\n\n if (rels.length) {\n if (sortProperty.startsWith('_')) {\n const sortWithoutRelationPrefix = sortProperty.replace(/^_+/, '')\n const lastFieldPath = rels.at(-1)?.fieldPath as string\n if (sortWithoutRelationPrefix.startsWith(lastFieldPath)) {\n sortProperty = sortWithoutRelationPrefix\n }\n }\n relationLookup = []\n for (const { fieldPath, relationTo } of rels) {\n sortAggregation = sortAggregation.filter((each) => {\n if ('$lookup' in each && each.$lookup.as.replace(/^_+/, '') === fieldPath) {\n return false\n }\n\n return true\n })\n const { collectionConfig: foreignCollectionConfig, Model: foreignModel } = getCollection({\n adapter: this,\n collectionSlug: relationTo,\n })\n const relatedAccess = args.relatedAccess?.[fieldPath]\n const relatedAccessQuery = relatedAccess\n ? await buildQuery({\n adapter: this,\n collectionSlug: relationTo,\n fields: foreignCollectionConfig.flattenedFields,\n locale: args.locale,\n where: relatedAccess,\n })\n : null\n\n relationLookup.push({\n $lookup: {\n as: fieldPath,\n from: foreignModel.collection.name,\n ...(relatedAccessQuery\n ? {\n let: { relatedIDs: `$${fieldPath}` },\n pipeline: [\n {\n $match: {\n $and: [\n {\n $expr: {\n $cond: {\n else: { $eq: ['$_id', '$$relatedIDs'] },\n if: { $isArray: '$$relatedIDs' },\n then: { $in: ['$_id', '$$relatedIDs'] },\n },\n },\n },\n relatedAccessQuery,\n ],\n },\n },\n ],\n }\n : {\n foreignField: '_id',\n localField: fieldPath,\n }),\n },\n })\n relationLookup.push({ $unwind: `$${fieldPath}` })\n }\n }\n\n let $unwind: any = ''\n let $group: any = null\n if (\n isHasManyValue &&\n sortAggregation.length &&\n sortAggregation[0] &&\n '$lookup' in sortAggregation[0]\n ) {\n $unwind = { path: `$${sortAggregation[0].$lookup.as}`, preserveNullAndEmptyArrays: true }\n $group = {\n _id: {\n _field: `$${sortAggregation[0].$lookup.as}._id`,\n _sort: `$${sortProperty}`,\n },\n }\n } else if (isHasManyValue) {\n $unwind = { path: `$${args.field}`, preserveNullAndEmptyArrays: true }\n }\n\n if (!$group) {\n $group = {\n _id: `$${fieldPath}`,\n ...(sortProperty === fieldPath\n ? {}\n : {\n _sort: { $max: `$${sortProperty}` },\n }),\n }\n }\n\n const pipeline: PipelineStage[] = [\n {\n $match: query,\n },\n ...(sortAggregation.length > 0 ? sortAggregation : []),\n ...(relationLookup?.length ? relationLookup : []),\n ...($unwind\n ? [\n {\n $unwind,\n },\n ]\n : []),\n {\n $group,\n },\n {\n $sort: getSortAggregation({\n fieldPath,\n hasSortAggregationAndHasMany: Boolean(isHasManyValue) && Boolean(sortAggregation.length),\n sortDirection,\n sortProperty,\n }),\n },\n ]\n\n const session = await getSession(this, args.req)\n\n const getValues = async () => {\n return Model.aggregate(pipeline, { session }).then((res) =>\n res.map((each) => ({\n [args.field]: JSON.parse(JSON.stringify(sanitizeGroupID(each._id))),\n })),\n )\n }\n\n if (args.limit) {\n pipeline.push({\n $skip: (page - 1) * args.limit,\n })\n pipeline.push({ $limit: args.limit })\n\n // Build count pipeline with the same structure as the main pipeline\n // to ensure relationship lookups are included\n const countPipeline: PipelineStage[] = [\n {\n $match: query,\n },\n ...(sortAggregation.length > 0 ? sortAggregation : []),\n ...(relationLookup?.length ? relationLookup : []),\n ...($unwind\n ? [\n {\n $unwind,\n },\n ]\n : []),\n {\n $group,\n },\n { $count: 'count' },\n ]\n\n const totalDocs = await Model.aggregate(countPipeline, {\n session,\n }).then((res) => res[0]?.count ?? 0)\n const totalPages = Math.ceil(totalDocs / args.limit)\n const hasPrevPage = page > 1\n const hasNextPage = totalPages > page\n const pagingCounter = (page - 1) * args.limit + 1\n\n return {\n hasNextPage,\n hasPrevPage,\n limit: args.limit,\n nextPage: hasNextPage ? page + 1 : null,\n page,\n pagingCounter,\n prevPage: hasPrevPage ? page - 1 : null,\n totalDocs,\n totalPages,\n values: await getValues(),\n }\n }\n\n const values = await getValues()\n\n return {\n hasNextPage: false,\n hasPrevPage: false,\n limit: 0,\n page: 1,\n pagingCounter: 1,\n totalDocs: values.length,\n totalPages: 1,\n values,\n }\n}\n"],"names":["getFieldByPath","buildQuery","buildSortParam","getCollection","getSession","sanitizeGroupID","id","_field","getSortAggregation","fieldPath","hasSortAggregationAndHasMany","sortDirection","sortProperty","resolvedSortProperty","findDistinct","args","collectionConfig","Model","adapter","collectionSlug","collection","where","sortAggregation","sort","config","payload","fields","flattenedFields","locale","field","timestamps","query","fieldPathResult","includeRelationships","path","pathHasLocalized","localizedPath","replace","page","Object","keys","currentFields","foundField","rels","tempPath","insideRelation","segments","split","i","length","segment","find","e","name","type","relationTo","push","collections","resolvedField","isHasManyValue","relationLookup","startsWith","sortWithoutRelationPrefix","lastFieldPath","at","filter","each","$lookup","as","foreignCollectionConfig","foreignModel","relatedAccess","relatedAccessQuery","from","let","relatedIDs","pipeline","$match","$and","$expr","$cond","else","$eq","if","$isArray","then","$in","foreignField","localField","$unwind","$group","preserveNullAndEmptyArrays","_id","_sort","$max","$sort","Boolean","session","req","getValues","aggregate","res","map","JSON","parse","stringify","limit","$skip","$limit","countPipeline","$count","totalDocs","count","totalPages","Math","ceil","hasPrevPage","hasNextPage","pagingCounter","nextPage","prevPage","values"],"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,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,CA4XnC"}
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"}
@@ -60,6 +60,17 @@ const subQueryOptions = {
60
60
  payload
61
61
  });
62
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
+ }
63
74
  if (path) {
64
75
  const sanitizedQueryValue = sanitizeQueryValue({
65
76
  field,
@@ -432,5 +443,44 @@ const subQueryOptions = {
432
443
  }
433
444
  }
434
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
+ }
435
485
 
436
486
  //# sourceMappingURL=buildSearchParams.js.map
@@ -1 +1 @@
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 (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"],"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","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","Array","isArray","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"],"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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"}
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildSearchParam } from './buildSearchParams.js';
3
+ const fields = [
4
+ {
5
+ name: 'title',
6
+ type: 'text'
7
+ }
8
+ ];
9
+ const payload = {
10
+ config: {},
11
+ collections: {},
12
+ globals: {}
13
+ };
14
+ describe('buildSearchParam', ()=>{
15
+ for (const operator of [
16
+ 'contains',
17
+ 'like',
18
+ 'not_like'
19
+ ]){
20
+ it(`rejects object values for ${operator}`, async ()=>{
21
+ await expect(buildSearchParam({
22
+ fields,
23
+ incomingPath: 'title',
24
+ operator,
25
+ parentIsLocalized: false,
26
+ payload,
27
+ val: {
28
+ pattern: 'title'
29
+ }
30
+ })).rejects.toThrow(`Invalid value for "${operator}"`);
31
+ });
32
+ }
33
+ it('rejects arrays containing object values', async ()=>{
34
+ await expect(buildSearchParam({
35
+ fields,
36
+ incomingPath: 'title',
37
+ operator: 'like',
38
+ parentIsLocalized: false,
39
+ payload,
40
+ val: [
41
+ {
42
+ pattern: 'title'
43
+ }
44
+ ]
45
+ })).rejects.toThrow('Invalid value for "like"');
46
+ });
47
+ });
48
+
49
+ //# sourceMappingURL=buildSearchParams.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/queries/buildSearchParams.spec.ts"],"sourcesContent":["import type { FlattenedField, Payload } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { buildSearchParam } from './buildSearchParams.js'\n\nconst fields = [{ name: 'title', type: 'text' }] as FlattenedField[]\n\nconst payload = {\n config: {},\n collections: {},\n globals: {},\n} as Payload\n\ndescribe('buildSearchParam', () => {\n for (const operator of ['contains', 'like', 'not_like'] as const) {\n it(`rejects object values for ${operator}`, async () => {\n await expect(\n buildSearchParam({\n fields,\n incomingPath: 'title',\n operator,\n parentIsLocalized: false,\n payload,\n val: { pattern: 'title' },\n }),\n ).rejects.toThrow(`Invalid value for \"${operator}\"`)\n })\n }\n\n it('rejects arrays containing object values', async () => {\n await expect(\n buildSearchParam({\n fields,\n incomingPath: 'title',\n operator: 'like',\n parentIsLocalized: false,\n payload,\n val: [{ pattern: 'title' }],\n }),\n ).rejects.toThrow('Invalid value for \"like\"')\n })\n})\n"],"names":["describe","expect","it","buildSearchParam","fields","name","type","payload","config","collections","globals","operator","incomingPath","parentIsLocalized","val","pattern","rejects","toThrow"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,gBAAgB,QAAQ,yBAAwB;AAEzD,MAAMC,SAAS;IAAC;QAAEC,MAAM;QAASC,MAAM;IAAO;CAAE;AAEhD,MAAMC,UAAU;IACdC,QAAQ,CAAC;IACTC,aAAa,CAAC;IACdC,SAAS,CAAC;AACZ;AAEAV,SAAS,oBAAoB;IAC3B,KAAK,MAAMW,YAAY;QAAC;QAAY;QAAQ;KAAW,CAAW;QAChET,GAAG,CAAC,0BAA0B,EAAES,UAAU,EAAE;YAC1C,MAAMV,OACJE,iBAAiB;gBACfC;gBACAQ,cAAc;gBACdD;gBACAE,mBAAmB;gBACnBN;gBACAO,KAAK;oBAAEC,SAAS;gBAAQ;YAC1B,IACAC,OAAO,CAACC,OAAO,CAAC,CAAC,mBAAmB,EAAEN,SAAS,CAAC,CAAC;QACrD;IACF;IAEAT,GAAG,2CAA2C;QAC5C,MAAMD,OACJE,iBAAiB;YACfC;YACAQ,cAAc;YACdD,UAAU;YACVE,mBAAmB;YACnBN;YACAO,KAAK;gBAAC;oBAAEC,SAAS;gBAAQ;aAAE;QAC7B,IACAC,OAAO,CAACC,OAAO,CAAC;IACpB;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/db-mongodb",
3
- "version": "4.0.0-canary.33",
3
+ "version": "4.0.0-canary.34",
4
4
  "description": "The officially supported MongoDB database adapter for Payload",
5
5
  "homepage": "https://payloadcms.com",
6
6
  "repository": {
@@ -54,10 +54,10 @@
54
54
  "mongodb": "7.5.0",
55
55
  "mongodb-memory-server": "10.1.4",
56
56
  "@payloadcms/eslint-config": "3.28.0",
57
- "payload": "4.0.0-canary.33"
57
+ "payload": "4.0.0-canary.34"
58
58
  },
59
59
  "peerDependencies": {
60
- "payload": "4.0.0-canary.33"
60
+ "payload": "4.0.0-canary.34"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "pnpm build:types && pnpm build:swc",