feat: join field support relationships inside arrays (#9773)

### What?

Allow the join field to have a configuration `on` relationships inside
of an array, ie `on: 'myArray.myRelationship'`.

### Why?

This is a more powerful and expressive way to use the join field and not
be limited by usage of array data. For example, if you have a roles
array for multinant sites, you could add a join field on the sites to
show who the admins are.

### How?

This fixes the traverseFields function to allow the configuration to
pass sanitization. In addition, the function for querying the drizzle
tables needed to be ehanced.

Additional changes from https://github.com/payloadcms/payload/pull/9995:

- Significantly improves traverseFields and the 'join' case with a raw
query injection pattern, right now it's internal but we could expose it
at some point, for example for querying vectors.
- Fixes potential issues with not passed locale to traverseFields (it
was undefined always)
- Adds an empty array fallback for joins with localized relationships

Fixes #
https://github.com/payloadcms/payload/discussions/9643

---------

Co-authored-by: Because789 <thomas@because789.ch>
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
This commit is contained in:
Dan Ribbens
2024-12-17 13:14:43 -05:00
committed by GitHub
parent eb037a0cc6
commit b0b2fc6c47
17 changed files with 290 additions and 141 deletions

View File

@@ -103,6 +103,12 @@ export const Categories: CollectionConfig = {
},
],
},
{
name: 'arrayPosts',
type: 'join',
collection: 'posts',
on: 'array.category',
},
{
name: 'singulars',
type: 'join',

View File

@@ -69,5 +69,16 @@ export const Posts: CollectionConfig = {
},
],
},
{
name: 'array',
type: 'array',
fields: [
{
name: 'category',
type: 'relationship',
relationTo: categoriesSlug,
},
],
},
],
}

View File

@@ -94,6 +94,7 @@ describe('Joins Field', () => {
category: category.id,
camelCaseCategory: category.id,
},
array: [{ category: category.id }],
})
}
})
@@ -183,6 +184,15 @@ describe('Joins Field', () => {
expect(docs[0].group.camelCaseCategory.group.camelCasePosts.docs).toHaveLength(10)
})
it('should populate joins with array relationships', async () => {
const categoryWithPosts = await payload.findByID({
id: category.id,
collection: categoriesSlug,
})
expect(categoryWithPosts.arrayPosts.docs).toBeDefined()
})
it('should populate uploads in joins', async () => {
const { docs } = await payload.find({
limit: 1,