@payloadcms/db-mongodb 3.0.0-canary.ff8c8fd → 3.0.1-canary.34c6cc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. package/dist/connect.d.ts.map +1 -1
  2. package/dist/connect.js +12 -3
  3. package/dist/connect.js.map +1 -1
  4. package/dist/count.d.ts.map +1 -1
  5. package/dist/count.js +8 -1
  6. package/dist/count.js.map +1 -1
  7. package/dist/countGlobalVersions.d.ts +3 -0
  8. package/dist/countGlobalVersions.d.ts.map +1 -0
  9. package/dist/countGlobalVersions.js +40 -0
  10. package/dist/countGlobalVersions.js.map +1 -0
  11. package/dist/countVersions.d.ts +3 -0
  12. package/dist/countVersions.d.ts.map +1 -0
  13. package/dist/countVersions.js +40 -0
  14. package/dist/countVersions.js.map +1 -0
  15. package/dist/create.d.ts.map +1 -1
  16. package/dist/create.js +10 -1
  17. package/dist/create.js.map +1 -1
  18. package/dist/createGlobal.d.ts.map +1 -1
  19. package/dist/createGlobal.js +10 -5
  20. package/dist/createGlobal.js.map +1 -1
  21. package/dist/createGlobalVersion.d.ts +1 -1
  22. package/dist/createGlobalVersion.d.ts.map +1 -1
  23. package/dist/createGlobalVersion.js +13 -4
  24. package/dist/createGlobalVersion.js.map +1 -1
  25. package/dist/createMigration.d.ts.map +1 -1
  26. package/dist/createMigration.js +8 -6
  27. package/dist/createMigration.js.map +1 -1
  28. package/dist/createVersion.d.ts +1 -1
  29. package/dist/createVersion.d.ts.map +1 -1
  30. package/dist/createVersion.js +31 -9
  31. package/dist/createVersion.js.map +1 -1
  32. package/dist/deleteOne.d.ts.map +1 -1
  33. package/dist/deleteOne.js +11 -3
  34. package/dist/deleteOne.js.map +1 -1
  35. package/dist/exports/migration-utils.d.ts +3 -0
  36. package/dist/exports/migration-utils.d.ts.map +1 -0
  37. package/dist/exports/migration-utils.js +4 -0
  38. package/dist/exports/migration-utils.js.map +1 -0
  39. package/dist/find.d.ts.map +1 -1
  40. package/dist/find.js +27 -4
  41. package/dist/find.js.map +1 -1
  42. package/dist/findGlobal.d.ts.map +1 -1
  43. package/dist/findGlobal.js +9 -3
  44. package/dist/findGlobal.js.map +1 -1
  45. package/dist/findGlobalVersions.d.ts.map +1 -1
  46. package/dist/findGlobalVersions.js +9 -4
  47. package/dist/findGlobalVersions.js.map +1 -1
  48. package/dist/findOne.d.ts.map +1 -1
  49. package/dist/findOne.js +27 -3
  50. package/dist/findOne.js.map +1 -1
  51. package/dist/findVersions.d.ts.map +1 -1
  52. package/dist/findVersions.js +9 -4
  53. package/dist/findVersions.js.map +1 -1
  54. package/dist/index.d.ts +23 -4
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +16 -7
  57. package/dist/index.js.map +1 -1
  58. package/dist/init.d.ts.map +1 -1
  59. package/dist/init.js +20 -18
  60. package/dist/init.js.map +1 -1
  61. package/dist/models/buildCollectionSchema.d.ts +2 -3
  62. package/dist/models/buildCollectionSchema.d.ts.map +1 -1
  63. package/dist/models/buildCollectionSchema.js +10 -7
  64. package/dist/models/buildCollectionSchema.js.map +1 -1
  65. package/dist/models/buildGlobalModel.d.ts +2 -2
  66. package/dist/models/buildGlobalModel.d.ts.map +1 -1
  67. package/dist/models/buildGlobalModel.js +6 -6
  68. package/dist/models/buildGlobalModel.js.map +1 -1
  69. package/dist/models/buildSchema.d.ts +2 -3
  70. package/dist/models/buildSchema.d.ts.map +1 -1
  71. package/dist/models/buildSchema.js +108 -66
  72. package/dist/models/buildSchema.js.map +1 -1
  73. package/dist/predefinedMigrations/migrateRelationshipsV2_V3.d.ts +6 -0
  74. package/dist/predefinedMigrations/migrateRelationshipsV2_V3.d.ts.map +1 -0
  75. package/dist/predefinedMigrations/migrateRelationshipsV2_V3.js +141 -0
  76. package/dist/predefinedMigrations/migrateRelationshipsV2_V3.js.map +1 -0
  77. package/dist/predefinedMigrations/migrateVersionsV1_V2.d.ts +5 -0
  78. package/dist/predefinedMigrations/migrateVersionsV1_V2.d.ts.map +1 -0
  79. package/dist/predefinedMigrations/migrateVersionsV1_V2.js +107 -0
  80. package/dist/predefinedMigrations/migrateVersionsV1_V2.js.map +1 -0
  81. package/dist/predefinedMigrations/relationships-v2-v3.d.ts +4 -0
  82. package/dist/predefinedMigrations/relationships-v2-v3.d.ts.map +1 -0
  83. package/dist/predefinedMigrations/relationships-v2-v3.js +9 -0
  84. package/dist/predefinedMigrations/relationships-v2-v3.js.map +1 -0
  85. package/dist/predefinedMigrations/versions-v1-v2.d.ts +4 -0
  86. package/dist/predefinedMigrations/versions-v1-v2.d.ts.map +1 -0
  87. package/dist/predefinedMigrations/versions-v1-v2.js +5 -95
  88. package/dist/predefinedMigrations/versions-v1-v2.js.map +1 -1
  89. package/dist/queries/buildQuery.d.ts +2 -2
  90. package/dist/queries/buildQuery.d.ts.map +1 -1
  91. package/dist/queries/buildQuery.js +1 -2
  92. package/dist/queries/buildQuery.js.map +1 -1
  93. package/dist/queries/buildSearchParams.d.ts.map +1 -1
  94. package/dist/queries/buildSearchParams.js +29 -18
  95. package/dist/queries/buildSearchParams.js.map +1 -1
  96. package/dist/queries/buildSortParam.d.ts +2 -2
  97. package/dist/queries/buildSortParam.d.ts.map +1 -1
  98. package/dist/queries/buildSortParam.js +26 -17
  99. package/dist/queries/buildSortParam.js.map +1 -1
  100. package/dist/queries/getLocalizedSortProperty.spec.js +1 -1
  101. package/dist/queries/getLocalizedSortProperty.spec.js.map +1 -1
  102. package/dist/queries/parseParams.d.ts.map +1 -1
  103. package/dist/queries/parseParams.js +7 -2
  104. package/dist/queries/parseParams.js.map +1 -1
  105. package/dist/queries/sanitizeQueryValue.d.ts +3 -2
  106. package/dist/queries/sanitizeQueryValue.d.ts.map +1 -1
  107. package/dist/queries/sanitizeQueryValue.js +263 -37
  108. package/dist/queries/sanitizeQueryValue.js.map +1 -1
  109. package/dist/queryDrafts.d.ts.map +1 -1
  110. package/dist/queryDrafts.js +29 -8
  111. package/dist/queryDrafts.js.map +1 -1
  112. package/dist/transactions/beginTransaction.d.ts.map +1 -1
  113. package/dist/transactions/beginTransaction.js +2 -0
  114. package/dist/transactions/beginTransaction.js.map +1 -1
  115. package/dist/transactions/commitTransaction.d.ts.map +1 -1
  116. package/dist/transactions/commitTransaction.js +3 -1
  117. package/dist/transactions/commitTransaction.js.map +1 -1
  118. package/dist/types.d.ts +7 -4
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/types.js.map +1 -1
  121. package/dist/updateGlobal.d.ts.map +1 -1
  122. package/dist/updateGlobal.js +18 -4
  123. package/dist/updateGlobal.js.map +1 -1
  124. package/dist/updateGlobalVersion.d.ts +2 -2
  125. package/dist/updateGlobalVersion.d.ts.map +1 -1
  126. package/dist/updateGlobalVersion.js +19 -4
  127. package/dist/updateGlobalVersion.js.map +1 -1
  128. package/dist/updateOne.d.ts.map +1 -1
  129. package/dist/updateOne.js +18 -4
  130. package/dist/updateOne.js.map +1 -1
  131. package/dist/updateVersion.d.ts +1 -1
  132. package/dist/updateVersion.d.ts.map +1 -1
  133. package/dist/updateVersion.js +18 -3
  134. package/dist/updateVersion.js.map +1 -1
  135. package/dist/upsert.d.ts +3 -0
  136. package/dist/upsert.d.ts.map +1 -0
  137. package/dist/upsert.js +15 -0
  138. package/dist/upsert.js.map +1 -0
  139. package/dist/utilities/buildJoinAggregation.d.ts +18 -0
  140. package/dist/utilities/buildJoinAggregation.d.ts.map +1 -0
  141. package/dist/utilities/buildJoinAggregation.js +159 -0
  142. package/dist/utilities/buildJoinAggregation.js.map +1 -0
  143. package/dist/utilities/buildProjectionFromSelect.d.ts +8 -0
  144. package/dist/utilities/buildProjectionFromSelect.d.ts.map +1 -0
  145. package/dist/utilities/buildProjectionFromSelect.js +171 -0
  146. package/dist/utilities/buildProjectionFromSelect.js.map +1 -0
  147. package/dist/utilities/getDBName.d.ts.map +1 -1
  148. package/dist/utilities/getDBName.js +3 -1
  149. package/dist/utilities/getDBName.js.map +1 -1
  150. package/dist/utilities/handleError.js +2 -2
  151. package/dist/utilities/handleError.js.map +1 -1
  152. package/dist/utilities/sanitizeInternalFields.d.ts +1 -2
  153. package/dist/utilities/sanitizeInternalFields.d.ts.map +1 -1
  154. package/dist/utilities/sanitizeInternalFields.js +1 -2
  155. package/dist/utilities/sanitizeInternalFields.js.map +1 -1
  156. package/dist/utilities/sanitizeRelationshipIDs.d.ts +9 -0
  157. package/dist/utilities/sanitizeRelationshipIDs.d.ts.map +1 -0
  158. package/dist/utilities/sanitizeRelationshipIDs.js +125 -0
  159. package/dist/utilities/sanitizeRelationshipIDs.js.map +1 -0
  160. package/dist/utilities/sanitizeRelationshipIDs.spec.js +408 -0
  161. package/dist/utilities/sanitizeRelationshipIDs.spec.js.map +1 -0
  162. package/dist/withSession.d.ts +1 -1
  163. package/dist/withSession.d.ts.map +1 -1
  164. package/dist/withSession.js +5 -3
  165. package/dist/withSession.js.map +1 -1
  166. package/license.md +22 -0
  167. package/package.json +24 -11
  168. package/dist/queries/mock.js +0 -2
  169. package/dist/queries/mock.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/queries/buildSearchParams.ts"],"sourcesContent":["import type { Field, Operator, PathToQuery, Payload } from 'payload'\n\nimport ObjectIdImport from 'bson-objectid'\nimport mongoose from 'mongoose'\nimport { getLocalizedPaths } from 'payload'\nimport { validOperators } from 'payload/shared'\n\nimport type { MongooseAdapter } from '../index.js'\n\nimport { operatorMap } from './operatorMap.js'\nimport { sanitizeQueryValue } from './sanitizeQueryValue.js'\n\nconst ObjectId = (ObjectIdImport.default ||\n ObjectIdImport) as unknown as typeof ObjectIdImport.default\n\ntype SearchParam = {\n path?: string\n rawQuery?: unknown\n value?: unknown\n}\n\nconst subQueryOptions = {\n lean: true,\n limit: 50,\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 payload,\n val,\n}: {\n collectionSlug?: string\n fields: Field[]\n globalSlug?: string\n incomingPath: string\n locale?: string\n operator: string\n payload: Payload\n val: unknown\n}): Promise<SearchParam> {\n // Replace GraphQL nested field double underscore formatting\n let sanitizedPath = incomingPath.replace(/__/g, '.')\n if (sanitizedPath === 'id') sanitizedPath = '_id'\n\n let paths: PathToQuery[] = []\n\n let hasCustomID = false\n\n if (sanitizedPath === '_id') {\n const customIDFieldType = payload.collections[collectionSlug]?.customIDType\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 Field,\n path: '_id',\n })\n } else {\n paths = await getLocalizedPaths({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: sanitizedPath,\n locale,\n payload,\n })\n }\n\n const [{ field, path }] = paths\n\n if (path) {\n const {\n operator: formattedOperator,\n rawQuery,\n val: formattedValue,\n } = sanitizeQueryValue({\n field,\n hasCustomID,\n operator,\n path,\n val,\n })\n\n if (rawQuery) return { value: rawQuery }\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 const initialRelationshipQuery = {\n value: {},\n } as SearchParam\n\n const relationshipQuery = await pathsToQuery.reduce(\n async (priorQuery, { collectionSlug: slug, path: subPath }, i) => {\n const priorQueryResult = await priorQuery\n\n const SubModel = (payload.db as MongooseAdapter).collections[slug]\n\n // On the \"deepest\" collection,\n // Search on the value passed through the query\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 result = await SubModel.find(subQuery, subQueryOptions)\n\n const $in: unknown[] = []\n\n result.forEach((doc) => {\n const stringID = doc._id.toString()\n $in.push(stringID)\n\n if (mongoose.Types.ObjectId.isValid(stringID)) {\n $in.push(doc._id)\n }\n })\n\n if (pathsToQuery.length === 1) {\n return {\n path,\n value: { $in },\n }\n }\n\n const nextSubPath = pathsToQuery[i + 1].path\n\n return {\n value: { [nextSubPath]: { $in } },\n }\n }\n\n const subQuery = priorQueryResult.value\n const result = await SubModel.find(subQuery, subQueryOptions)\n\n const $in = result.map((doc) => doc._id.toString())\n\n // If it is the last recursion\n // then pass through the search param\n if (i + 1 === pathsToQuery.length) {\n return {\n path,\n value: { $in },\n }\n }\n\n return {\n value: {\n _id: { $in },\n },\n }\n },\n Promise.resolve(initialRelationshipQuery),\n )\n\n return relationshipQuery\n }\n\n if (formattedOperator && validOperators.includes(formattedOperator as Operator)) {\n const operatorKey = operatorMap[formattedOperator]\n\n if (field.type === 'relationship' || field.type === 'upload') {\n let hasNumberIDRelation\n let multiIDCondition = '$or'\n if (operatorKey === '$ne') multiIDCondition = '$and'\n\n const result = {\n value: {\n [multiIDCondition]: [{ [path]: { [operatorKey]: formattedValue } }],\n },\n }\n\n if (typeof formattedValue === 'string') {\n if (mongoose.Types.ObjectId.isValid(formattedValue)) {\n result.value[multiIDCondition].push({\n [path]: { [operatorKey]: 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 if (result.value[multiIDCondition].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: word.replace(/[\\\\^$*+?.()|[\\]{}]/g, '\\\\$&'),\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":["ObjectIdImport","mongoose","getLocalizedPaths","validOperators","operatorMap","sanitizeQueryValue","ObjectId","default","subQueryOptions","lean","limit","buildSearchParam","collectionSlug","fields","globalSlug","incomingPath","locale","operator","payload","val","sanitizedPath","replace","paths","hasCustomID","customIDFieldType","collections","customIDType","idFieldType","push","complete","field","name","type","path","formattedOperator","rawQuery","formattedValue","value","length","pathsToQuery","slice","reverse","initialRelationshipQuery","relationshipQuery","reduce","priorQuery","slug","subPath","i","priorQueryResult","SubModel","db","subQuery","buildQuery","where","result","find","$in","forEach","doc","stringID","_id","toString","Types","isValid","nextSubPath","map","Promise","resolve","includes","operatorKey","hasNumberIDRelation","multiIDCondition","Array","isArray","relationTo","isRelatedToCustomNumberID","parseFloat","words","split","$and","word","$options","$regex","undefined"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/queries/buildSearchParams.ts"],"sourcesContent":["import type { Field, Operator, PathToQuery, Payload } from 'payload'\n\nimport { Types } from 'mongoose'\nimport { getLocalizedPaths } from 'payload'\nimport { validOperators } from 'payload/shared'\n\nimport type { MongooseAdapter } from '../index.js'\n\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 limit: 50,\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 payload,\n val,\n}: {\n collectionSlug?: string\n fields: Field[]\n globalSlug?: string\n incomingPath: string\n locale?: string\n operator: string\n payload: Payload\n val: unknown\n}): Promise<SearchParam> {\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 = payload.collections[collectionSlug]?.customIDType\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 Field,\n path: '_id',\n })\n } else {\n paths = await getLocalizedPaths({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: sanitizedPath,\n locale,\n payload,\n })\n }\n\n const [{ field, path }] = paths\n if (path) {\n const sanitizedQueryValue = sanitizeQueryValue({\n field,\n hasCustomID,\n operator,\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) {\n return { value: rawQuery }\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 const initialRelationshipQuery = {\n value: {},\n } as SearchParam\n\n const relationshipQuery = await pathsToQuery.reduce(\n async (priorQuery, { collectionSlug: slug, path: subPath }, i) => {\n const priorQueryResult = await priorQuery\n\n const SubModel = (payload.db as MongooseAdapter).collections[slug]\n\n // On the \"deepest\" collection,\n // Search on the value passed through the query\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 result = await SubModel.find(subQuery, subQueryOptions)\n\n const $in: unknown[] = []\n\n result.forEach((doc) => {\n const stringID = doc._id.toString()\n $in.push(stringID)\n\n if (Types.ObjectId.isValid(stringID)) {\n $in.push(doc._id)\n }\n })\n\n if (pathsToQuery.length === 1) {\n return {\n path,\n value: { $in },\n }\n }\n\n const nextSubPath = pathsToQuery[i + 1].path\n\n return {\n value: { [nextSubPath]: { $in } },\n }\n }\n\n const subQuery = priorQueryResult.value\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 return {\n path,\n value: { $in },\n }\n }\n\n return {\n value: {\n _id: { $in },\n },\n }\n },\n Promise.resolve(initialRelationshipQuery),\n )\n\n return relationshipQuery\n }\n\n if (formattedOperator && validOperators.includes(formattedOperator as Operator)) {\n const operatorKey = operatorMap[formattedOperator]\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 if (result.value[multiIDCondition].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: word.replace(/[\\\\^$*+?.()|[\\]{}]/g, '\\\\$&'),\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","getLocalizedPaths","validOperators","operatorMap","sanitizeQueryValue","subQueryOptions","lean","limit","buildSearchParam","collectionSlug","fields","globalSlug","incomingPath","locale","operator","payload","val","sanitizedPath","replace","paths","hasCustomID","customIDFieldType","collections","customIDType","idFieldType","push","complete","field","name","type","path","sanitizedQueryValue","undefined","formattedOperator","rawQuery","formattedValue","value","length","pathsToQuery","slice","reverse","initialRelationshipQuery","relationshipQuery","reduce","priorQuery","slug","subPath","i","priorQueryResult","SubModel","db","subQuery","buildQuery","where","result","find","$in","forEach","doc","stringID","_id","toString","ObjectId","isValid","nextSubPath","map","Promise","resolve","includes","operatorKey","hasNumberIDRelation","multiIDCondition","Array","isArray","relationTo","isRelatedToCustomNumberID","parseFloat","words","split","$and","word","$options","$regex"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import type { PaginateOptions } from 'mongoose';
2
- import type { Field, SanitizedConfig } from 'payload';
2
+ import type { Field, SanitizedConfig, Sort } from 'payload';
3
3
  type Args = {
4
4
  config: SanitizedConfig;
5
5
  fields: Field[];
6
6
  locale: string;
7
- sort: string;
7
+ sort: Sort;
8
8
  timestamps: boolean;
9
9
  };
10
10
  export type SortArgs = {
@@ -1 +1 @@
1
- {"version":3,"file":"buildSortParam.d.ts","sourceRoot":"","sources":["../../src/queries/buildSortParam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAIrD,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,aAAa,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;CACjB,EAAE,CAAA;AAEH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C,eAAO,MAAM,cAAc,kDAMxB,IAAI,KAAG,eAAe,CAAC,MAAM,CA6B/B,CAAA"}
1
+ {"version":3,"file":"buildSortParam.d.ts","sourceRoot":"","sources":["../../src/queries/buildSortParam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAI3D,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,IAAI,CAAA;IACV,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,SAAS,EAAE,aAAa,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;CACjB,EAAE,CAAA;AAEH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C,eAAO,MAAM,cAAc,kDAMxB,IAAI,KAAG,eAAe,CAAC,MAAM,CAsC/B,CAAA"}
@@ -1,32 +1,41 @@
1
1
  import { getLocalizedSortProperty } from './getLocalizedSortProperty.js';
2
2
  export const buildSortParam = ({ config, fields, locale, sort, timestamps })=>{
3
- let sortProperty;
4
- let sortDirection = 'desc';
5
3
  if (!sort) {
6
4
  if (timestamps) {
7
- sortProperty = 'createdAt';
5
+ sort = '-createdAt';
8
6
  } else {
9
- sortProperty = '_id';
7
+ sort = '-id';
10
8
  }
11
- } else if (sort.indexOf('-') === 0) {
12
- sortProperty = sort.substring(1);
13
- } else {
14
- sortProperty = sort;
15
- sortDirection = 'asc';
16
9
  }
17
- if (sortProperty === 'id') {
18
- sortProperty = '_id';
19
- } else {
20
- sortProperty = getLocalizedSortProperty({
10
+ if (typeof sort === 'string') {
11
+ sort = [
12
+ sort
13
+ ];
14
+ }
15
+ const sorting = sort.reduce((acc, item)=>{
16
+ let sortProperty;
17
+ let sortDirection;
18
+ if (item.indexOf('-') === 0) {
19
+ sortProperty = item.substring(1);
20
+ sortDirection = 'desc';
21
+ } else {
22
+ sortProperty = item;
23
+ sortDirection = 'asc';
24
+ }
25
+ if (sortProperty === 'id') {
26
+ acc['_id'] = sortDirection;
27
+ return acc;
28
+ }
29
+ const localizedProperty = getLocalizedSortProperty({
21
30
  config,
22
31
  fields,
23
32
  locale,
24
33
  segments: sortProperty.split('.')
25
34
  });
26
- }
27
- return {
28
- [sortProperty]: sortDirection
29
- };
35
+ acc[localizedProperty] = sortDirection;
36
+ return acc;
37
+ }, {});
38
+ return sorting;
30
39
  };
31
40
 
32
41
  //# sourceMappingURL=buildSortParam.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/queries/buildSortParam.ts"],"sourcesContent":["import type { PaginateOptions } from 'mongoose'\nimport type { Field, SanitizedConfig } from 'payload'\n\nimport { getLocalizedSortProperty } from './getLocalizedSortProperty.js'\n\ntype Args = {\n config: SanitizedConfig\n fields: Field[]\n locale: string\n sort: string\n timestamps: boolean\n}\n\nexport type SortArgs = {\n direction: SortDirection\n property: string\n}[]\n\nexport type SortDirection = 'asc' | 'desc'\n\nexport const buildSortParam = ({\n config,\n fields,\n locale,\n sort,\n timestamps,\n}: Args): PaginateOptions['sort'] => {\n let sortProperty: string\n let sortDirection: SortDirection = 'desc'\n\n if (!sort) {\n if (timestamps) {\n sortProperty = 'createdAt'\n } else {\n sortProperty = '_id'\n }\n } else if (sort.indexOf('-') === 0) {\n sortProperty = sort.substring(1)\n } else {\n sortProperty = sort\n sortDirection = 'asc'\n }\n\n if (sortProperty === 'id') {\n sortProperty = '_id'\n } else {\n sortProperty = getLocalizedSortProperty({\n config,\n fields,\n locale,\n segments: sortProperty.split('.'),\n })\n }\n\n return { [sortProperty]: sortDirection }\n}\n"],"names":["getLocalizedSortProperty","buildSortParam","config","fields","locale","sort","timestamps","sortProperty","sortDirection","indexOf","substring","segments","split"],"mappings":"AAGA,SAASA,wBAAwB,QAAQ,gCAA+B;AAiBxE,OAAO,MAAMC,iBAAiB,CAAC,EAC7BC,MAAM,EACNC,MAAM,EACNC,MAAM,EACNC,IAAI,EACJC,UAAU,EACL;IACL,IAAIC;IACJ,IAAIC,gBAA+B;IAEnC,IAAI,CAACH,MAAM;QACT,IAAIC,YAAY;YACdC,eAAe;QACjB,OAAO;YACLA,eAAe;QACjB;IACF,OAAO,IAAIF,KAAKI,OAAO,CAAC,SAAS,GAAG;QAClCF,eAAeF,KAAKK,SAAS,CAAC;IAChC,OAAO;QACLH,eAAeF;QACfG,gBAAgB;IAClB;IAEA,IAAID,iBAAiB,MAAM;QACzBA,eAAe;IACjB,OAAO;QACLA,eAAeP,yBAAyB;YACtCE;YACAC;YACAC;YACAO,UAAUJ,aAAaK,KAAK,CAAC;QAC/B;IACF;IAEA,OAAO;QAAE,CAACL,aAAa,EAAEC;IAAc;AACzC,EAAC"}
1
+ {"version":3,"sources":["../../src/queries/buildSortParam.ts"],"sourcesContent":["import type { PaginateOptions } from 'mongoose'\nimport type { Field, SanitizedConfig, Sort } from 'payload'\n\nimport { getLocalizedSortProperty } from './getLocalizedSortProperty.js'\n\ntype Args = {\n config: SanitizedConfig\n fields: Field[]\n locale: string\n sort: Sort\n timestamps: boolean\n}\n\nexport type SortArgs = {\n direction: SortDirection\n property: string\n}[]\n\nexport type SortDirection = 'asc' | 'desc'\n\nexport const buildSortParam = ({\n config,\n fields,\n locale,\n sort,\n timestamps,\n}: Args): PaginateOptions['sort'] => {\n if (!sort) {\n if (timestamps) {\n sort = '-createdAt'\n } else {\n sort = '-id'\n }\n }\n\n if (typeof sort === 'string') {\n sort = [sort]\n }\n\n const sorting = sort.reduce<PaginateOptions['sort']>((acc, item) => {\n let sortProperty: string\n let sortDirection: SortDirection\n if (item.indexOf('-') === 0) {\n sortProperty = item.substring(1)\n sortDirection = 'desc'\n } else {\n sortProperty = item\n sortDirection = 'asc'\n }\n if (sortProperty === 'id') {\n acc['_id'] = sortDirection\n return acc\n }\n const localizedProperty = getLocalizedSortProperty({\n config,\n fields,\n locale,\n segments: sortProperty.split('.'),\n })\n acc[localizedProperty] = sortDirection\n return acc\n }, {})\n\n return sorting\n}\n"],"names":["getLocalizedSortProperty","buildSortParam","config","fields","locale","sort","timestamps","sorting","reduce","acc","item","sortProperty","sortDirection","indexOf","substring","localizedProperty","segments","split"],"mappings":"AAGA,SAASA,wBAAwB,QAAQ,gCAA+B;AAiBxE,OAAO,MAAMC,iBAAiB,CAAC,EAC7BC,MAAM,EACNC,MAAM,EACNC,MAAM,EACNC,IAAI,EACJC,UAAU,EACL;IACL,IAAI,CAACD,MAAM;QACT,IAAIC,YAAY;YACdD,OAAO;QACT,OAAO;YACLA,OAAO;QACT;IACF;IAEA,IAAI,OAAOA,SAAS,UAAU;QAC5BA,OAAO;YAACA;SAAK;IACf;IAEA,MAAME,UAAUF,KAAKG,MAAM,CAA0B,CAACC,KAAKC;QACzD,IAAIC;QACJ,IAAIC;QACJ,IAAIF,KAAKG,OAAO,CAAC,SAAS,GAAG;YAC3BF,eAAeD,KAAKI,SAAS,CAAC;YAC9BF,gBAAgB;QAClB,OAAO;YACLD,eAAeD;YACfE,gBAAgB;QAClB;QACA,IAAID,iBAAiB,MAAM;YACzBF,GAAG,CAAC,MAAM,GAAGG;YACb,OAAOH;QACT;QACA,MAAMM,oBAAoBf,yBAAyB;YACjDE;YACAC;YACAC;YACAY,UAAUL,aAAaM,KAAK,CAAC;QAC/B;QACAR,GAAG,CAACM,kBAAkB,GAAGH;QACzB,OAAOH;IACT,GAAG,CAAC;IAEJ,OAAOF;AACT,EAAC"}
@@ -14,7 +14,7 @@ describe('get localized sort property', ()=>{
14
14
  }
15
15
  });
16
16
  });
17
- it('passes through a non-localized sort property', async ()=>{
17
+ it('passes through a non-localized sort property', ()=>{
18
18
  const result = getLocalizedSortProperty({
19
19
  config,
20
20
  fields: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/queries/getLocalizedSortProperty.spec.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { sanitizeConfig } from 'payload'\n\nimport { getLocalizedSortProperty } from './getLocalizedSortProperty.js'\n\nlet config: SanitizedConfig\n\ndescribe('get localized sort property', () => {\n beforeAll(async () => {\n config = await sanitizeConfig({\n localization: {\n defaultLocale: 'en',\n fallback: true,\n locales: ['en', 'es'],\n },\n } as Config)\n })\n it('passes through a non-localized sort property', async () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title')\n })\n\n it('properly localizes an un-localized sort property', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n\n it('keeps specifically asked-for localized sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n locale: 'en',\n segments: ['title', 'es'],\n })\n\n expect(result).toStrictEqual('title.es')\n })\n\n it('properly localizes nested sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'group',\n type: 'group',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['group', 'title'],\n })\n\n expect(result).toStrictEqual('group.title.en')\n })\n\n it('keeps requested locale with nested sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'group',\n type: 'group',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['group', 'title', 'es'],\n })\n\n expect(result).toStrictEqual('group.title.es')\n })\n\n it('properly localizes field within row', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n\n it('properly localizes field within named tab', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n name: 'tab',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['tab', 'title'],\n })\n\n expect(result).toStrictEqual('tab.title.en')\n })\n\n it('properly localizes field within unnamed tab', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n label: 'Tab',\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n})\n"],"names":["sanitizeConfig","getLocalizedSortProperty","config","describe","beforeAll","localization","defaultLocale","fallback","locales","it","result","fields","name","type","locale","segments","expect","toStrictEqual","localized","tabs","label"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/queries/getLocalizedSortProperty.spec.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { sanitizeConfig } from 'payload'\n\nimport { getLocalizedSortProperty } from './getLocalizedSortProperty.js'\n\nlet config: SanitizedConfig\n\ndescribe('get localized sort property', () => {\n beforeAll(async () => {\n config = await sanitizeConfig({\n localization: {\n defaultLocale: 'en',\n fallback: true,\n locales: ['en', 'es'],\n },\n } as Config)\n })\n it('passes through a non-localized sort property', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title')\n })\n\n it('properly localizes an un-localized sort property', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n\n it('keeps specifically asked-for localized sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n locale: 'en',\n segments: ['title', 'es'],\n })\n\n expect(result).toStrictEqual('title.es')\n })\n\n it('properly localizes nested sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'group',\n type: 'group',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['group', 'title'],\n })\n\n expect(result).toStrictEqual('group.title.en')\n })\n\n it('keeps requested locale with nested sort properties', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n name: 'group',\n type: 'group',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['group', 'title', 'es'],\n })\n\n expect(result).toStrictEqual('group.title.es')\n })\n\n it('properly localizes field within row', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'row',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n\n it('properly localizes field within named tab', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n name: 'tab',\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['tab', 'title'],\n })\n\n expect(result).toStrictEqual('tab.title.en')\n })\n\n it('properly localizes field within unnamed tab', () => {\n const result = getLocalizedSortProperty({\n config,\n fields: [\n {\n type: 'tabs',\n tabs: [\n {\n fields: [\n {\n name: 'title',\n type: 'text',\n localized: true,\n },\n ],\n label: 'Tab',\n },\n ],\n },\n ],\n locale: 'en',\n segments: ['title'],\n })\n\n expect(result).toStrictEqual('title.en')\n })\n})\n"],"names":["sanitizeConfig","getLocalizedSortProperty","config","describe","beforeAll","localization","defaultLocale","fallback","locales","it","result","fields","name","type","locale","segments","expect","toStrictEqual","localized","tabs","label"],"mappings":"AAEA,SAASA,cAAc,QAAQ,UAAS;AAExC,SAASC,wBAAwB,QAAQ,gCAA+B;AAExE,IAAIC;AAEJC,SAAS,+BAA+B;IACtCC,UAAU;QACRF,SAAS,MAAMF,eAAe;YAC5BK,cAAc;gBACZC,eAAe;gBACfC,UAAU;gBACVC,SAAS;oBAAC;oBAAM;iBAAK;YACvB;QACF;IACF;IACAC,GAAG,gDAAgD;QACjD,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;gBACR;aACD;YACDC,QAAQ;YACRC,UAAU;gBAAC;aAAQ;QACrB;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,oDAAoD;QACrD,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;oBACNK,WAAW;gBACb;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;aAAQ;QACrB;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,0DAA0D;QAC3D,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;oBACNK,WAAW;gBACb;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;gBAAS;aAAK;QAC3B;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,6CAA6C;QAC9C,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;oBACNF,QAAQ;wBACN;4BACEC,MAAM;4BACNC,MAAM;4BACNK,WAAW;wBACb;qBACD;gBACH;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;gBAAS;aAAQ;QAC9B;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,sDAAsD;QACvD,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;oBACNF,QAAQ;wBACN;4BACEC,MAAM;4BACNC,MAAM;4BACNK,WAAW;wBACb;qBACD;gBACH;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;gBAAS;gBAAS;aAAK;QACpC;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,uCAAuC;QACxC,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEE,MAAM;oBACNF,QAAQ;wBACN;4BACEC,MAAM;4BACNC,MAAM;4BACNK,WAAW;wBACb;qBACD;gBACH;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;aAAQ;QACrB;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,6CAA6C;QAC9C,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEE,MAAM;oBACNM,MAAM;wBACJ;4BACEP,MAAM;4BACND,QAAQ;gCACN;oCACEC,MAAM;oCACNC,MAAM;oCACNK,WAAW;gCACb;6BACD;wBACH;qBACD;gBACH;aACD;YACDJ,QAAQ;YACRC,UAAU;gBAAC;gBAAO;aAAQ;QAC5B;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;IAEAR,GAAG,+CAA+C;QAChD,MAAMC,SAAST,yBAAyB;YACtCC;YACAS,QAAQ;gBACN;oBACEE,MAAM;oBACNM,MAAM;wBACJ;4BACER,QAAQ;gCACN;oCACEC,MAAM;oCACNC,MAAM;oCACNK,WAAW;gCACb;6BACD;4BACDE,OAAO;wBACT;qBACD;gBACH;aACD;YACDN,QAAQ;YACRC,UAAU;gBAAC;aAAQ;QACrB;QAEAC,OAAON,QAAQO,aAAa,CAAC;IAC/B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"parseParams.d.ts","sourceRoot":"","sources":["../../src/queries/parseParams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAY,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAQ9D,wBAAsB,WAAW,CAAC,EAChC,cAAc,EACd,MAAM,EACN,UAAU,EACV,MAAM,EACN,OAAO,EACP,KAAK,GACN,EAAE;IACD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,CAAA;CACb,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA0DnC"}
1
+ {"version":3,"file":"parseParams.d.ts","sourceRoot":"","sources":["../../src/queries/parseParams.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAY,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAQ9D,wBAAsB,WAAW,CAAC,EAChC,cAAc,EACd,MAAM,EACN,UAAU,EACV,MAAM,EACN,OAAO,EACP,KAAK,GACN,EAAE;IACD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,CAAA;CACb,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA+DnC"}
@@ -23,7 +23,9 @@ export async function parseParams({ collectionSlug, fields, globalSlug, locale,
23
23
  payload,
24
24
  where: condition
25
25
  });
26
- if (builtConditions.length > 0) result[conditionOperator] = builtConditions;
26
+ if (builtConditions.length > 0) {
27
+ result[conditionOperator] = builtConditions;
28
+ }
27
29
  } else {
28
30
  // It's a path - and there can be multiple comparisons on a single path.
29
31
  // For example - title like 'test' and title not equal to 'tester'
@@ -48,7 +50,10 @@ export async function parseParams({ collectionSlug, fields, globalSlug, locale,
48
50
  [searchParam.path]: searchParam.value
49
51
  };
50
52
  } else if (typeof searchParam?.value === 'object') {
51
- result = deepMergeWithCombinedArrays(result, searchParam.value);
53
+ result = deepMergeWithCombinedArrays(result, searchParam.value, {
54
+ // dont clone Types.ObjectIDs
55
+ clone: false
56
+ });
52
57
  }
53
58
  }
54
59
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/queries/parseParams.ts"],"sourcesContent":["import type { FilterQuery } from 'mongoose'\nimport type { Field, Operator, Payload, Where } from 'payload'\n\nimport { deepMergeWithCombinedArrays } from 'payload'\nimport { validOperators } 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 payload,\n where,\n}: {\n collectionSlug?: string\n fields: Field[]\n globalSlug?: string\n locale: string\n payload: Payload\n where: Where\n}): Promise<Record<string, unknown>> {\n let result = {} as FilterQuery<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'\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 payload,\n where: condition,\n })\n if (builtConditions.length > 0) result[conditionOperator] = builtConditions\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 for (const operator of Object.keys(pathOperators)) {\n if (validOperators.includes(operator as Operator)) {\n const searchParam = await buildSearchParam({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: relationOrPath,\n locale,\n operator,\n payload,\n val: pathOperators[operator],\n })\n\n if (searchParam?.value && searchParam?.path) {\n result = {\n ...result,\n [searchParam.path]: searchParam.value,\n }\n } else if (typeof searchParam?.value === 'object') {\n result = deepMergeWithCombinedArrays(result, searchParam.value)\n }\n }\n }\n }\n }\n }\n }\n\n return result\n}\n"],"names":["deepMergeWithCombinedArrays","validOperators","buildAndOrConditions","buildSearchParam","parseParams","collectionSlug","fields","globalSlug","locale","payload","where","result","relationOrPath","Object","keys","condition","conditionOperator","toLowerCase","Array","isArray","builtConditions","length","pathOperators","operator","includes","searchParam","incomingPath","val","value","path"],"mappings":"AAGA,SAASA,2BAA2B,QAAQ,UAAS;AACrD,SAASC,cAAc,QAAQ,iBAAgB;AAE/C,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SAASC,gBAAgB,QAAQ,yBAAwB;AAEzD,OAAO,eAAeC,YAAY,EAChCC,cAAc,EACdC,MAAM,EACNC,UAAU,EACVC,MAAM,EACNC,OAAO,EACPC,KAAK,EAQN;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;YACJ,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,MAAMlB,qBAAqB;oBACjDG;oBACAC;oBACAC;oBACAC;oBACAC;oBACAC,OAAOK;gBACT;gBACA,IAAIK,gBAAgBC,MAAM,GAAG,GAAGV,MAAM,CAACK,kBAAkB,GAAGI;YAC9D,OAAO;gBACL,wEAAwE;gBACxE,kEAAkE;gBAClE,8EAA8E;gBAC9E,MAAME,gBAAgBZ,KAAK,CAACE,eAAe;gBAC3C,IAAI,OAAOU,kBAAkB,UAAU;oBACrC,KAAK,MAAMC,YAAYV,OAAOC,IAAI,CAACQ,eAAgB;wBACjD,IAAIrB,eAAeuB,QAAQ,CAACD,WAAuB;4BACjD,MAAME,cAAc,MAAMtB,iBAAiB;gCACzCE;gCACAC;gCACAC;gCACAmB,cAAcd;gCACdJ;gCACAe;gCACAd;gCACAkB,KAAKL,aAAa,CAACC,SAAS;4BAC9B;4BAEA,IAAIE,aAAaG,SAASH,aAAaI,MAAM;gCAC3ClB,SAAS;oCACP,GAAGA,MAAM;oCACT,CAACc,YAAYI,IAAI,CAAC,EAAEJ,YAAYG,KAAK;gCACvC;4BACF,OAAO,IAAI,OAAOH,aAAaG,UAAU,UAAU;gCACjDjB,SAASX,4BAA4BW,QAAQc,YAAYG,KAAK;4BAChE;wBACF;oBACF;gBACF;YACF;QACF;IACF;IAEA,OAAOjB;AACT"}
1
+ {"version":3,"sources":["../../src/queries/parseParams.ts"],"sourcesContent":["import type { FilterQuery } from 'mongoose'\nimport type { Field, Operator, Payload, Where } from 'payload'\n\nimport { deepMergeWithCombinedArrays } from 'payload'\nimport { validOperators } 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 payload,\n where,\n}: {\n collectionSlug?: string\n fields: Field[]\n globalSlug?: string\n locale: string\n payload: Payload\n where: Where\n}): Promise<Record<string, unknown>> {\n let result = {} as FilterQuery<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'\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 payload,\n where: condition,\n })\n if (builtConditions.length > 0) {\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 for (const operator of Object.keys(pathOperators)) {\n if (validOperators.includes(operator as Operator)) {\n const searchParam = await buildSearchParam({\n collectionSlug,\n fields,\n globalSlug,\n incomingPath: relationOrPath,\n locale,\n operator,\n payload,\n val: pathOperators[operator],\n })\n\n if (searchParam?.value && searchParam?.path) {\n result = {\n ...result,\n [searchParam.path]: searchParam.value,\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\n return result\n}\n"],"names":["deepMergeWithCombinedArrays","validOperators","buildAndOrConditions","buildSearchParam","parseParams","collectionSlug","fields","globalSlug","locale","payload","where","result","relationOrPath","Object","keys","condition","conditionOperator","toLowerCase","Array","isArray","builtConditions","length","pathOperators","operator","includes","searchParam","incomingPath","val","value","path","clone"],"mappings":"AAGA,SAASA,2BAA2B,QAAQ,UAAS;AACrD,SAASC,cAAc,QAAQ,iBAAgB;AAE/C,SAASC,oBAAoB,QAAQ,4BAA2B;AAChE,SAASC,gBAAgB,QAAQ,yBAAwB;AAEzD,OAAO,eAAeC,YAAY,EAChCC,cAAc,EACdC,MAAM,EACNC,UAAU,EACVC,MAAM,EACNC,OAAO,EACPC,KAAK,EAQN;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;YACJ,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,MAAMlB,qBAAqB;oBACjDG;oBACAC;oBACAC;oBACAC;oBACAC;oBACAC,OAAOK;gBACT;gBACA,IAAIK,gBAAgBC,MAAM,GAAG,GAAG;oBAC9BV,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,KAAK,MAAMC,YAAYV,OAAOC,IAAI,CAACQ,eAAgB;wBACjD,IAAIrB,eAAeuB,QAAQ,CAACD,WAAuB;4BACjD,MAAME,cAAc,MAAMtB,iBAAiB;gCACzCE;gCACAC;gCACAC;gCACAmB,cAAcd;gCACdJ;gCACAe;gCACAd;gCACAkB,KAAKL,aAAa,CAACC,SAAS;4BAC9B;4BAEA,IAAIE,aAAaG,SAASH,aAAaI,MAAM;gCAC3ClB,SAAS;oCACP,GAAGA,MAAM;oCACT,CAACc,YAAYI,IAAI,CAAC,EAAEJ,YAAYG,KAAK;gCACvC;4BACF,OAAO,IAAI,OAAOH,aAAaG,UAAU,UAAU;gCACjDjB,SAASX,4BAA4BW,QAAQc,YAAYG,KAAK,EAAE;oCAC9D,6BAA6B;oCAC7BE,OAAO;gCACT;4BACF;wBACF;oBACF;gBACF;YACF;QACF;IACF;IAEA,OAAOnB;AACT"}
@@ -1,12 +1,13 @@
1
- import type { Field, TabAsField } from 'payload';
1
+ import type { Field, Payload, TabAsField } from 'payload';
2
2
  type SanitizeQueryValueArgs = {
3
3
  field: Field | TabAsField;
4
4
  hasCustomID: boolean;
5
5
  operator: string;
6
6
  path: string;
7
+ payload: Payload;
7
8
  val: any;
8
9
  };
9
- export declare const sanitizeQueryValue: ({ field, hasCustomID, operator, path, val, }: SanitizeQueryValueArgs) => {
10
+ export declare const sanitizeQueryValue: ({ field, hasCustomID, operator, path, payload, val, }: SanitizeQueryValueArgs) => {
10
11
  operator?: string;
11
12
  rawQuery?: unknown;
12
13
  val?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizeQueryValue.d.ts","sourceRoot":"","sources":["../../src/queries/sanitizeQueryValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAKhD,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,KAAK,GAAG,UAAU,CAAA;IACzB,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,GAAG,CAAA;CACT,CAAA;AAED,eAAO,MAAM,kBAAkB,iDAM5B,sBAAsB,KAAG;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,OAAO,CAAA;CAgKd,CAAA"}
1
+ {"version":3,"file":"sanitizeQueryValue.d.ts","sourceRoot":"","sources":["../../src/queries/sanitizeQueryValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAS,KAAK,EAAE,OAAO,EAAqB,UAAU,EAAE,MAAM,SAAS,CAAA;AAKnF,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,KAAK,GAAG,UAAU,CAAA;IACzB,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;CACT,CAAA;AA+DD,eAAO,MAAM,kBAAkB,0DAO5B,sBAAsB,KAAG;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,OAAO,CAAA;CAqTd,CAAA"}
@@ -1,33 +1,165 @@
1
- import mongoose from 'mongoose';
2
- import { createArrayFromCommaDelineated } from 'payload';
3
- export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=>{
1
+ import { Types } from 'mongoose';
2
+ import { createArrayFromCommaDelineated, flattenTopLevelFields } from 'payload';
3
+ const buildExistsQuery = (formattedValue, path, treatEmptyString = true)=>{
4
+ if (formattedValue) {
5
+ return {
6
+ rawQuery: {
7
+ $and: [
8
+ {
9
+ [path]: {
10
+ $exists: true
11
+ }
12
+ },
13
+ {
14
+ [path]: {
15
+ $ne: null
16
+ }
17
+ },
18
+ ...treatEmptyString ? [
19
+ {
20
+ [path]: {
21
+ $ne: ''
22
+ }
23
+ }
24
+ ] : []
25
+ ]
26
+ }
27
+ };
28
+ } else {
29
+ return {
30
+ rawQuery: {
31
+ $or: [
32
+ {
33
+ [path]: {
34
+ $exists: false
35
+ }
36
+ },
37
+ {
38
+ [path]: {
39
+ $eq: null
40
+ }
41
+ },
42
+ ...treatEmptyString ? [
43
+ {
44
+ [path]: {
45
+ $eq: ''
46
+ }
47
+ }
48
+ ] : []
49
+ ]
50
+ }
51
+ };
52
+ }
53
+ };
54
+ // returns nestedField Field object from blocks.nestedField path because getLocalizedPaths splits them only for relationships
55
+ const getFieldFromSegments = ({ field, segments })=>{
56
+ if ('blocks' in field) {
57
+ for (const block of field.blocks){
58
+ const field = getFieldFromSegments({
59
+ field: block,
60
+ segments
61
+ });
62
+ if (field) {
63
+ return field;
64
+ }
65
+ }
66
+ }
67
+ if ('fields' in field) {
68
+ for(let i = 0; i < segments.length; i++){
69
+ const foundField = flattenTopLevelFields(field.fields).find((each)=>each.name === segments[i]);
70
+ if (!foundField) {
71
+ break;
72
+ }
73
+ if (foundField && segments.length - 1 === i) {
74
+ return foundField;
75
+ }
76
+ segments.shift();
77
+ return getFieldFromSegments({
78
+ field: foundField,
79
+ segments
80
+ });
81
+ }
82
+ }
83
+ };
84
+ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, payload, val })=>{
4
85
  let formattedValue = val;
5
86
  let formattedOperator = operator;
87
+ if ([
88
+ 'array',
89
+ 'blocks',
90
+ 'group',
91
+ 'tab'
92
+ ].includes(field.type) && path.includes('.')) {
93
+ const segments = path.split('.');
94
+ segments.shift();
95
+ const foundField = getFieldFromSegments({
96
+ field,
97
+ segments
98
+ });
99
+ if (foundField) {
100
+ field = foundField;
101
+ }
102
+ }
6
103
  // Disregard invalid _ids
7
- if (path === '_id' && typeof val === 'string' && val.split(',').length === 1) {
8
- if (!hasCustomID) {
9
- const isValid = mongoose.Types.ObjectId.isValid(val);
10
- if (!isValid) {
11
- return {
12
- operator: formattedOperator,
13
- val: undefined
14
- };
104
+ if (path === '_id') {
105
+ if (typeof val === 'string' && val.split(',').length === 1) {
106
+ if (!hasCustomID) {
107
+ const isValid = Types.ObjectId.isValid(val);
108
+ if (!isValid) {
109
+ return {
110
+ operator: formattedOperator,
111
+ val: undefined
112
+ };
113
+ } else {
114
+ if ([
115
+ 'in',
116
+ 'not_in'
117
+ ].includes(operator)) {
118
+ formattedValue = createArrayFromCommaDelineated(formattedValue).map((id)=>new Types.ObjectId(id));
119
+ } else {
120
+ formattedValue = new Types.ObjectId(val);
121
+ }
122
+ }
15
123
  }
16
- }
17
- if (field.type === 'number') {
18
- const parsedNumber = parseFloat(val);
19
- if (Number.isNaN(parsedNumber)) {
20
- return {
21
- operator: formattedOperator,
22
- val: undefined
23
- };
124
+ if (field.type === 'number') {
125
+ const parsedNumber = parseFloat(val);
126
+ if (Number.isNaN(parsedNumber)) {
127
+ return {
128
+ operator: formattedOperator,
129
+ val: undefined
130
+ };
131
+ }
24
132
  }
133
+ } else if (Array.isArray(val) || typeof val === 'string' && val.split(',').length > 1) {
134
+ if (typeof val === 'string') {
135
+ formattedValue = createArrayFromCommaDelineated(val);
136
+ }
137
+ formattedValue = formattedValue.reduce((formattedValues, inVal)=>{
138
+ if (!hasCustomID) {
139
+ if (Types.ObjectId.isValid(inVal)) {
140
+ formattedValues.push(new Types.ObjectId(inVal));
141
+ }
142
+ }
143
+ if (field.type === 'number') {
144
+ const parsedNumber = parseFloat(inVal);
145
+ if (!Number.isNaN(parsedNumber)) {
146
+ formattedValues.push(parsedNumber);
147
+ }
148
+ } else {
149
+ formattedValues.push(inVal);
150
+ }
151
+ return formattedValues;
152
+ }, []);
25
153
  }
26
154
  }
27
155
  // Cast incoming values as proper searchable types
28
156
  if (field.type === 'checkbox' && typeof val === 'string') {
29
- if (val.toLowerCase() === 'true') formattedValue = true;
30
- if (val.toLowerCase() === 'false') formattedValue = false;
157
+ if (val.toLowerCase() === 'true') {
158
+ formattedValue = true;
159
+ }
160
+ if (val.toLowerCase() === 'false') {
161
+ formattedValue = false;
162
+ }
31
163
  }
32
164
  if ([
33
165
  'all',
@@ -39,8 +171,14 @@ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=
39
171
  formattedValue = formattedValue.map((arrayVal)=>parseFloat(arrayVal));
40
172
  }
41
173
  }
42
- if (field.type === 'number' && typeof formattedValue === 'string') {
43
- formattedValue = Number(val);
174
+ if (field.type === 'number') {
175
+ if (typeof formattedValue === 'string' && operator !== 'exists') {
176
+ formattedValue = Number(val);
177
+ }
178
+ if (operator === 'exists') {
179
+ formattedValue = val === 'true' ? true : val === 'false' ? false : Boolean(val);
180
+ return buildExistsQuery(formattedValue, path);
181
+ }
44
182
  }
45
183
  if (field.type === 'date' && typeof val === 'string' && operator !== 'exists') {
46
184
  formattedValue = new Date(val);
@@ -57,6 +195,11 @@ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=
57
195
  }
58
196
  // Object equality requires the value to be the first key in the object that is being queried.
59
197
  if (operator === 'equals' && formattedValue && typeof formattedValue === 'object' && formattedValue.value && formattedValue.relationTo) {
198
+ const { value } = formattedValue;
199
+ const isValid = Types.ObjectId.isValid(value);
200
+ if (isValid) {
201
+ formattedValue.value = new Types.ObjectId(value);
202
+ }
60
203
  return {
61
204
  rawQuery: {
62
205
  $and: [
@@ -74,20 +217,91 @@ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=
74
217
  }
75
218
  };
76
219
  }
77
- if (operator === 'in' && Array.isArray(formattedValue)) {
220
+ const relationTo = field.relationTo;
221
+ if ([
222
+ 'in',
223
+ 'not_in'
224
+ ].includes(operator) && Array.isArray(formattedValue)) {
78
225
  formattedValue = formattedValue.reduce((formattedValues, inVal)=>{
79
- const newValues = [
80
- inVal
81
- ];
82
- if (mongoose.Types.ObjectId.isValid(inVal)) newValues.push(new mongoose.Types.ObjectId(inVal));
83
- const parsedNumber = parseFloat(inVal);
84
- if (!Number.isNaN(parsedNumber)) newValues.push(parsedNumber);
85
- return [
86
- ...formattedValues,
87
- ...newValues
88
- ];
226
+ if (!inVal) {
227
+ return formattedValues;
228
+ }
229
+ if (typeof relationTo === 'string' && payload.collections[relationTo].customIDType) {
230
+ if (payload.collections[relationTo].customIDType === 'number') {
231
+ const parsedNumber = parseFloat(inVal);
232
+ if (!Number.isNaN(parsedNumber)) {
233
+ formattedValues.push(parsedNumber);
234
+ return formattedValues;
235
+ }
236
+ }
237
+ formattedValues.push(inVal);
238
+ return formattedValues;
239
+ }
240
+ if (Array.isArray(relationTo) && relationTo.some((relationTo)=>!!payload.collections[relationTo].customIDType)) {
241
+ if (Types.ObjectId.isValid(inVal.toString())) {
242
+ formattedValues.push(new Types.ObjectId(inVal));
243
+ } else {
244
+ formattedValues.push(inVal);
245
+ }
246
+ return formattedValues;
247
+ }
248
+ if (Types.ObjectId.isValid(inVal.toString())) {
249
+ formattedValues.push(new Types.ObjectId(inVal));
250
+ }
251
+ return formattedValues;
89
252
  }, []);
90
253
  }
254
+ if ([
255
+ 'contains',
256
+ 'equals',
257
+ 'like',
258
+ 'not_equals'
259
+ ].includes(operator) && (!Array.isArray(relationTo) || !path.endsWith('.relationTo'))) {
260
+ if (typeof relationTo === 'string') {
261
+ const customIDType = payload.collections[relationTo].customIDType;
262
+ if (customIDType) {
263
+ if (customIDType === 'number') {
264
+ formattedValue = parseFloat(val);
265
+ if (Number.isNaN(formattedValue)) {
266
+ return {
267
+ operator: formattedOperator,
268
+ val: undefined
269
+ };
270
+ }
271
+ }
272
+ } else {
273
+ if (!Types.ObjectId.isValid(formattedValue)) {
274
+ return {
275
+ operator: formattedOperator,
276
+ val: undefined
277
+ };
278
+ }
279
+ formattedValue = new Types.ObjectId(formattedValue);
280
+ }
281
+ } else {
282
+ const hasCustomIDType = relationTo.some((relationTo)=>!!payload.collections[relationTo].customIDType);
283
+ if (hasCustomIDType) {
284
+ if (typeof val === 'string') {
285
+ const formattedNumber = Number(val);
286
+ formattedValue = [
287
+ Types.ObjectId.isValid(val) ? new Types.ObjectId(val) : val
288
+ ];
289
+ formattedOperator = operator === 'not_equals' ? 'not_in' : 'in';
290
+ if (!Number.isNaN(formattedNumber)) {
291
+ formattedValue.push(formattedNumber);
292
+ }
293
+ }
294
+ } else {
295
+ if (!Types.ObjectId.isValid(formattedValue)) {
296
+ return {
297
+ operator: formattedOperator,
298
+ val: undefined
299
+ };
300
+ }
301
+ formattedValue = new Types.ObjectId(formattedValue);
302
+ }
303
+ }
304
+ }
91
305
  }
92
306
  // Set up specific formatting necessary by operators
93
307
  if (operator === 'near') {
@@ -113,8 +327,12 @@ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=
113
327
  ]
114
328
  }
115
329
  };
116
- if (maxDistance) formattedValue.$maxDistance = parseFloat(maxDistance);
117
- if (minDistance) formattedValue.$minDistance = parseFloat(minDistance);
330
+ if (maxDistance) {
331
+ formattedValue.$maxDistance = parseFloat(maxDistance);
332
+ }
333
+ if (minDistance) {
334
+ formattedValue.$minDistance = parseFloat(minDistance);
335
+ }
118
336
  }
119
337
  }
120
338
  if (operator === 'within' || operator === 'intersects') {
@@ -123,12 +341,20 @@ export const sanitizeQueryValue = ({ field, hasCustomID, operator, path, val })=
123
341
  };
124
342
  }
125
343
  if (path !== '_id' || path === '_id' && hasCustomID && field.type === 'text') {
126
- if (operator === 'contains') {
344
+ if (operator === 'contains' && !Types.ObjectId.isValid(formattedValue)) {
127
345
  formattedValue = {
128
346
  $options: 'i',
129
347
  $regex: formattedValue.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&')
130
348
  };
131
349
  }
350
+ if (operator === 'exists') {
351
+ formattedValue = formattedValue === 'true' || formattedValue === true;
352
+ // _id can't be empty string, will error Cast to ObjectId failed for value ""
353
+ return buildExistsQuery(formattedValue, path, ![
354
+ 'relationship',
355
+ 'upload'
356
+ ].includes(field.type));
357
+ }
132
358
  }
133
359
  if ((path === '_id' || path === 'parent') && operator === 'like' && formattedValue.length === 24 && !hasCustomID) {
134
360
  formattedOperator = 'equals';