Skip to content

Commit bc9b501

Browse files
authored
fix: querying virtual fields deeply with draft: true (#12868)
Fixes an issue when querying deeply new relationship virtual fields with `draft: true`. Changes the method for `where` sanitization, before it was done in `validateSearchParam` which didn't work with versions properly, now there's a separate `sanitizeWhereQuery` function that does this.
1 parent bb17cc3 commit bc9b501

11 files changed

Lines changed: 108 additions & 5 deletions

File tree

‎packages/payload/src/collections/operations/count.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { Collection } from '../config/types.js'
66
importexecuteAccessfrom'../../auth/executeAccess.js'
77
import{combineQueries}from'../../database/combineQueries.js'
88
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
9+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
910
import{killTransaction}from'../../utilities/killTransaction.js'
1011
import{buildAfterOperation}from'./utils.js'
1112

@@ -71,6 +72,7 @@ export const countOperation = async <TSlug extends CollectionSlug>(
7172
letresult: {totalDocs: number}
7273

7374
constfullWhere=combineQueries(where!,accessResult!)
75+
sanitizeWhereQuery({fields: collectionConfig.flattenedFields, payload,where: fullWhere})
7476

7577
awaitvalidateQueryPaths({
7678
collectionConfig,

‎packages/payload/src/collections/operations/countVersions.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Collection } from '../config/types.js'
55
importexecuteAccessfrom'../../auth/executeAccess.js'
66
import{combineQueries}from'../../database/combineQueries.js'
77
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
8+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
89
import{buildVersionCollectionFields,typeCollectionSlug}from'../../index.js'
910
import{killTransaction}from'../../utilities/killTransaction.js'
1011
import{buildAfterOperation}from'./utils.js'
@@ -77,6 +78,8 @@ export const countVersionsOperation = async <TSlug extends CollectionSlug>(
7778

7879
constversionFields=buildVersionCollectionFields(payload.config,collectionConfig,true)
7980

81+
sanitizeWhereQuery({fields: versionFields, payload,where: fullWhere})
82+
8083
awaitvalidateQueryPaths({
8184
collectionConfig,
8285
overrideAccess: overrideAccess!,

‎packages/payload/src/collections/operations/delete.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
importexecuteAccessfrom'../../auth/executeAccess.js'
1414
import{combineQueries}from'../../database/combineQueries.js'
1515
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
16+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
1617
import{APIError}from'../../errors/index.js'
1718
import{afterRead}from'../../fields/hooks/afterRead/index.js'
1819
import{deleteUserPreferences}from'../../preferences/deleteUserPreferences.js'
@@ -107,6 +108,8 @@ export const deleteOperation = async <
107108

108109
constfullWhere=combineQueries(where,accessResult!)
109110

111+
sanitizeWhereQuery({fields: collectionConfig.flattenedFields, payload,where: fullWhere})
112+
110113
constselect=sanitizeSelect({
111114
fields: collectionConfig.flattenedFields,
112115
forceSelect: collectionConfig.forceSelect,

‎packages/payload/src/collections/operations/find.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import executeAccess from '../../auth/executeAccess.js'
1919
import{combineQueries}from'../../database/combineQueries.js'
2020
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
2121
import{sanitizeJoinQuery}from'../../database/sanitizeJoinQuery.js'
22+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
2223
import{afterRead}from'../../fields/hooks/afterRead/index.js'
2324
import{lockedDocumentsCollectionSlug}from'../../locked-documents/config.js'
2425
import{killTransaction}from'../../utilities/killTransaction.js'
@@ -144,6 +145,7 @@ export const findOperation = async <
144145
letresult: PaginatedDocs<DataFromCollectionSlug<TSlug>>
145146

146147
letfullWhere=combineQueries(where!,accessResult!)
148+
sanitizeWhereQuery({fields: collectionConfig.flattenedFields, payload,where: fullWhere})
147149

148150
constsort=sanitizeSortQuery({
149151
fields: collection.config.flattenedFields,

‎packages/payload/src/collections/operations/findByID.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type {
1818
importexecuteAccessfrom'../../auth/executeAccess.js'
1919
import{combineQueries}from'../../database/combineQueries.js'
2020
import{sanitizeJoinQuery}from'../../database/sanitizeJoinQuery.js'
21+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
2122
import{NotFound}from'../../errors/index.js'
2223
import{afterRead}from'../../fields/hooks/afterRead/index.js'
2324
import{validateQueryPaths}from'../../index.js'
@@ -110,6 +111,12 @@ export const findByIDOperation = async <
110111

111112
constfullWhere=combineQueries(where,accessResult)
112113

114+
sanitizeWhereQuery({
115+
fields: collectionConfig.flattenedFields,
116+
payload: args.req.payload,
117+
where: fullWhere,
118+
})
119+
113120
constsanitizedJoins=awaitsanitizeJoinQuery({
114121
collectionConfig,
115122
joins,

‎packages/payload/src/collections/operations/findVersions.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { Collection } from '../config/types.js'
77
importexecuteAccessfrom'../../auth/executeAccess.js'
88
import{combineQueries}from'../../database/combineQueries.js'
99
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
10+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
1011
import{afterRead}from'../../fields/hooks/afterRead/index.js'
1112
import{killTransaction}from'../../utilities/killTransaction.js'
1213
import{sanitizeInternalFields}from'../../utilities/sanitizeInternalFields.js'
@@ -71,9 +72,10 @@ export const findVersionsOperation = async <TData extends TypeWithVersion<TData>
7172
})
7273

7374
constfullWhere=combineQueries(where!,accessResults)
75+
sanitizeWhereQuery({fields: versionFields, payload,where: fullWhere})
7476

7577
constselect=sanitizeSelect({
76-
fields: buildVersionCollectionFields(payload.config,collectionConfig,true),
78+
fields: versionFields,
7779
forceSelect: getQueryDraftsSelect({select: collectionConfig.forceSelect}),
7880
select: incomingSelect,
7981
versions: true,

‎packages/payload/src/collections/operations/update.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import type {
1515
importexecuteAccessfrom'../../auth/executeAccess.js'
1616
import{combineQueries}from'../../database/combineQueries.js'
1717
import{validateQueryPaths}from'../../database/queryValidation/validateQueryPaths.js'
18-
import{APIError,Forbidden}from'../../errors/index.js'
18+
import{sanitizeWhereQuery}from'../../database/sanitizeWhereQuery.js'
19+
import{APIError}from'../../errors/index.js'
1920
import{typeCollectionSlug,deepCopyObjectSimple}from'../../index.js'
2021
import{generateFileData}from'../../uploads/generateFileData.js'
2122
import{unlinkTempFiles}from'../../uploads/unlinkTempFiles.js'
@@ -140,6 +141,8 @@ export const updateOperation = async <
140141

141142
constfullWhere=combineQueries(where,accessResult!)
142143

144+
sanitizeWhereQuery({fields: collectionConfig.flattenedFields, payload,where: fullWhere})
145+
143146
constsort=sanitizeSortQuery({
144147
fields: collection.config.flattenedFields,
145148
sort: incomingSort,

‎packages/payload/src/database/queryValidation/validateSearchParams.ts‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,6 @@ export async function validateSearchParam({
113113
if('virtual'infield&&field.virtual){
114114
if(field.virtual===true){
115115
errors.push({ path })
116-
}else{
117-
constraint[`${field.virtual}`askeyofWhereField]=constraint[pathaskeyofWhereField]
118-
deleteconstraint[pathaskeyofWhereField]
119116
}
120117
}
121118

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
importtype{FlattenedField}from'../fields/config/types.js'
2+
importtype{Payload,Where}from'../types/index.js'
3+
4+
/**
5+
* Currently used only for virtual fields linked with relationships
6+
*/
7+
exportconstsanitizeWhereQuery=({
8+
fields,
9+
payload,
10+
where,
11+
}: {
12+
fields: FlattenedField[]
13+
payload: Payload
14+
where: Where
15+
})=>{
16+
for(constkeyinwhere){
17+
constvalue=where[key]
18+
19+
if(['and','or'].includes(key.toLowerCase())&&Array.isArray(value)){
20+
for(constwhereofvalue){
21+
sanitizeWhereQuery({ fields, payload, where })
22+
}
23+
continue
24+
}
25+
26+
constpaths=key.split('.')
27+
letpathHasChanged=false
28+
29+
letcurrentFields=fields
30+
31+
for(leti=0;i<paths.length;i++){
32+
constpath=paths[i]!
33+
constfield=currentFields.find((each)=>each.name===path)
34+
35+
if(!field){
36+
break
37+
}
38+
39+
if('virtual'infield&&field.virtual&&typeoffield.virtual==='string'){
40+
paths[i]=field.virtual
41+
pathHasChanged=true
42+
}
43+
44+
if('flattenedFields'infield){
45+
currentFields=field.flattenedFields
46+
}
47+
48+
if(
49+
(field.type==='relationship'||field.type==='upload')&&
50+
typeoffield.relationTo==='string'
51+
){
52+
constrelatedCollection=payload.collections[field.relationTo]
53+
if(relatedCollection){
54+
currentFields=relatedCollection.config.flattenedFields
55+
}
56+
}
57+
}
58+
59+
if(pathHasChanged){
60+
where[paths.join('.')]=where[key]!
61+
deletewhere[key]
62+
}
63+
}
64+
}

‎test/database/config.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export default buildConfigWithDefaults({
3838
collections: [
3939
{
4040
slug: 'categories',
41+
versions: {drafts: true},
4142
fields: [
4243
{
4344
type: 'text',

0 commit comments

Comments
 (0)