fix: querying by polymorphic join field relationTo with overrideAccess: false (#11999)

Previously, querying by polymorphic joins `relationTo` with
`overrideAccess: false` caused an error:
```
QueryError: The following paths cannot be queried: relationTo
```

As this field actually doesn't exist in the schema. Now, under condition
that the query comes from a polymorphic join we skip checking
`relationTo` field access.
This commit is contained in:
Sasha
2025-04-07 23:19:43 +03:00
committed by GitHub
parent 09782be0e0
commit b9ffbc6994
5 changed files with 34 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ type Args = {
errors?: { path: string }[] errors?: { path: string }[]
overrideAccess: boolean overrideAccess: boolean
policies?: EntityPolicies policies?: EntityPolicies
polymorphicJoin?: boolean
req: PayloadRequest req: PayloadRequest
versionFields?: FlattenedField[] versionFields?: FlattenedField[]
where: Where where: Where
@@ -52,6 +53,7 @@ export async function validateQueryPaths({
collections: {}, collections: {},
globals: {}, globals: {},
}, },
polymorphicJoin,
req, req,
versionFields, versionFields,
where, where,
@@ -77,6 +79,7 @@ export async function validateQueryPaths({
overrideAccess, overrideAccess,
path, path,
policies, policies,
polymorphicJoin,
req, req,
val, val,
versionFields, versionFields,

View File

@@ -21,6 +21,7 @@ type Args = {
parentIsLocalized?: boolean parentIsLocalized?: boolean
path: string path: string
policies: EntityPolicies policies: EntityPolicies
polymorphicJoin?: boolean
req: PayloadRequest req: PayloadRequest
val: unknown val: unknown
versionFields?: FlattenedField[] versionFields?: FlattenedField[]
@@ -39,6 +40,7 @@ export async function validateSearchParam({
parentIsLocalized, parentIsLocalized,
path: incomingPath, path: incomingPath,
policies, policies,
polymorphicJoin,
req, req,
val, val,
versionFields, versionFields,
@@ -102,6 +104,10 @@ export async function validateSearchParam({
errors.push({ path }) errors.push({ path })
} }
if (polymorphicJoin && path === 'relationTo') {
return
}
if (!overrideAccess && fieldAffectsData(field)) { if (!overrideAccess && fieldAffectsData(field)) {
if (collectionSlug) { if (collectionSlug) {
if (!policies.collections[collectionSlug]) { if (!policies.collections[collectionSlug]) {
@@ -140,8 +146,10 @@ export async function validateSearchParam({
const segments = fieldPath.split('.') const segments = fieldPath.split('.')
let fieldAccess let fieldAccess
if (versionFields) { if (versionFields) {
fieldAccess = policies[entityType][entitySlug] fieldAccess = policies[entityType][entitySlug]
if (segments[0] === 'parent' || segments[0] === 'version') { if (segments[0] === 'parent' || segments[0] === 'version') {
segments.shift() segments.shift()
} }

View File

@@ -1,5 +1,6 @@
// @ts-strict-ignore // @ts-strict-ignore
import type { SanitizedCollectionConfig, SanitizedJoin } from '../collections/config/types.js' import type { SanitizedCollectionConfig, SanitizedJoin } from '../collections/config/types.js'
import type { FlattenedField } from '../fields/config/types.js'
import type { JoinQuery, PayloadRequest } from '../types/index.js' import type { JoinQuery, PayloadRequest } from '../types/index.js'
import executeAccess from '../auth/executeAccess.js' import executeAccess from '../auth/executeAccess.js'
@@ -67,6 +68,7 @@ const sanitizeJoinFieldQuery = async ({
collectionConfig: joinCollectionConfig, collectionConfig: joinCollectionConfig,
errors, errors,
overrideAccess, overrideAccess,
polymorphicJoin: Array.isArray(join.field.collection),
req, req,
// incoming where input, but we shouldn't validate generated from the access control. // incoming where input, but we shouldn't validate generated from the access control.
where: joinQuery.where, where: joinQuery.where,

View File

@@ -222,6 +222,7 @@ export default buildConfigWithDefaults({
}, },
{ {
slug: 'multiple-collections-parents', slug: 'multiple-collections-parents',
access: { read: () => true },
fields: [ fields: [
{ {
type: 'join', type: 'join',
@@ -236,6 +237,7 @@ export default buildConfigWithDefaults({
}, },
{ {
slug: 'multiple-collections-1', slug: 'multiple-collections-1',
access: { read: () => true },
admin: { useAsTitle: 'title' }, admin: { useAsTitle: 'title' },
fields: [ fields: [
{ {
@@ -255,6 +257,7 @@ export default buildConfigWithDefaults({
}, },
{ {
slug: 'multiple-collections-2', slug: 'multiple-collections-2',
access: { read: () => true },
admin: { useAsTitle: 'title' }, admin: { useAsTitle: 'title' },
fields: [ fields: [
{ {

View File

@@ -1389,7 +1389,7 @@ describe('Joins Field', () => {
expect(parent.children?.docs).toHaveLength(1) expect(parent.children?.docs).toHaveLength(1)
expect(parent.children.docs[0]?.value.title).toBe('doc-1') expect(parent.children.docs[0]?.value.title).toBe('doc-1')
// WHERE by _relationTo (join for specific collectionSlug) // WHERE by relationTo (join for specific collectionSlug)
parent = await payload.findByID({ parent = await payload.findByID({
collection: 'multiple-collections-parents', collection: 'multiple-collections-parents',
id: parent.id, id: parent.id,
@@ -1405,6 +1405,23 @@ describe('Joins Field', () => {
}, },
}) })
// WHERE by relationTo with overrideAccess:false
parent = await payload.findByID({
collection: 'multiple-collections-parents',
id: parent.id,
overrideAccess: false,
depth: 1,
joins: {
children: {
where: {
relationTo: {
equals: 'multiple-collections-2',
},
},
},
},
})
expect(parent.children?.docs).toHaveLength(1) expect(parent.children?.docs).toHaveLength(1)
expect(parent.children.docs[0]?.value.title).toBe('doc-2') expect(parent.children.docs[0]?.value.title).toBe('doc-2')