Skip to content

Commit 2b40e0f

Browse files
feat: polymorphic join querying by fields that don't exist in every collection (#12648)
This PR makes it possible to do polymorphic join querying by fields that don't exist in all collections specified in `field.collection`, for example: ``` const result = await payload.find({ collection: 'payload-folders', joins: { documentsAndFolders: { where: { and: [ { relationTo: { in: ['folderPoly1', 'folderPoly2'], }, }, { folderPoly2Title: { // this field exists only in the folderPoly2 collection, before it'd throw a query error. equals: 'Poly 2 Title', }, }, ], }, }, }, }) ``` --------- Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
1 parent 30dd9a2 commit 2b40e0f

File tree

6 files changed

+92
-1
lines changed

6 files changed

+92
-1
lines changed

packages/payload/src/database/queryValidation/validateQueryPaths.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export async function validateQueryPaths({
5959
errors,
6060
overrideAccess,
6161
policies,
62+
polymorphicJoin,
6263
req,
6364
versionFields,
6465
where: item,
@@ -71,6 +72,7 @@ export async function validateQueryPaths({
7172
globalConfig,
7273
overrideAccess,
7374
policies,
75+
polymorphicJoin,
7476
req,
7577
versionFields,
7678
where: item,

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ export async function validateSearchParam({
9999
promises.push(
100100
...paths.map(async ({ collectionSlug, field, invalid, path }, i) => {
101101
if (invalid) {
102-
errors.push({ path })
102+
if (!polymorphicJoin) {
103+
errors.push({ path })
104+
}
105+
103106
return
104107
}
105108

test/joins/collections/FolderPoly1.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { CollectionConfig } from 'payload'
2+
3+
export const FolderPoly1: CollectionConfig = {
4+
slug: 'folderPoly1',
5+
fields: [
6+
{
7+
name: 'folderPoly1Title',
8+
type: 'text',
9+
},
10+
],
11+
folders: true,
12+
}

test/joins/collections/FolderPoly2.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { CollectionConfig } from 'payload'
2+
3+
export const FolderPoly2: CollectionConfig = {
4+
slug: 'folderPoly2',
5+
fields: [
6+
{
7+
name: 'folderPoly2Title',
8+
type: 'text',
9+
},
10+
],
11+
folders: true,
12+
}

test/joins/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import path from 'path'
44
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
55
import { Categories } from './collections/Categories.js'
66
import { CategoriesVersions } from './collections/CategoriesVersions.js'
7+
import { FolderPoly1 } from './collections/FolderPoly1.js'
8+
import { FolderPoly2 } from './collections/FolderPoly2.js'
79
import { HiddenPosts } from './collections/HiddenPosts.js'
810
import { Posts } from './collections/Posts.js'
911
import { SelfJoins } from './collections/SelfJoins.js'
@@ -337,6 +339,8 @@ export default buildConfigWithDefaults({
337339
},
338340
],
339341
},
342+
FolderPoly1,
343+
FolderPoly2,
340344
],
341345
localization: {
342346
locales: [

test/joins/int.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,64 @@ describe('Joins Field', () => {
289289
expect(categoryWithPosts.localizedPolymorphics.docs[0]).toHaveProperty('id')
290290
})
291291

292+
it('should not throw a path validation error when querying joins with polymorphic relationships', async () => {
293+
const folderDoc = await payload.create({
294+
collection: 'payload-folders',
295+
data: {
296+
name: 'sharedFolder',
297+
},
298+
})
299+
300+
await payload.create({
301+
collection: 'folderPoly1',
302+
data: {
303+
folderPoly1Title: 'Poly 1 title',
304+
folder: folderDoc.id,
305+
},
306+
depth: 0,
307+
})
308+
309+
await payload.create({
310+
collection: 'folderPoly2',
311+
data: {
312+
folderPoly2Title: 'Poly 2 Title',
313+
folder: folderDoc.id,
314+
},
315+
depth: 0,
316+
})
317+
318+
const result = await payload.find({
319+
collection: 'payload-folders',
320+
joins: {
321+
documentsAndFolders: {
322+
limit: 100_000,
323+
sort: 'name',
324+
where: {
325+
and: [
326+
{
327+
relationTo: {
328+
in: ['folderPoly1', 'folderPoly2'],
329+
},
330+
},
331+
{
332+
folderPoly2Title: {
333+
equals: 'Poly 2 Title',
334+
},
335+
},
336+
],
337+
},
338+
},
339+
},
340+
where: {
341+
id: {
342+
equals: folderDoc.id,
343+
},
344+
},
345+
})
346+
347+
expect(result.docs[0]?.documentsAndFolders.docs).toHaveLength(1)
348+
})
349+
292350
it('should filter joins using where query', async () => {
293351
const categoryWithPosts = await payload.findByID({
294352
id: category.id,

0 commit comments

Comments
 (0)