fix: allow to set maxDepth: 0 for join fields, improve join field JSDoc (#10336)

Allows to set `maxDepth: 0` for join fields and improves JSDoc about
`maxDepth`, adds tests to confirm that
https://github.com/payloadcms/payload/issues/10243 is not an issue, but
just happens because the default `maxDepth` is `1`.
This commit is contained in:
Sasha
2025-01-03 21:25:19 +02:00
committed by GitHub
parent c7b3204439
commit ba228dd0f3
5 changed files with 166 additions and 2 deletions

View File

@@ -20,7 +20,7 @@ export const sanitizeJoinField = ({
if (typeof joins === 'undefined') {
throw new APIError('Join fields cannot be added to arrays, blocks or globals.')
}
if (!field.maxDepth) {
if (typeof field.maxDepth === 'undefined') {
field.maxDepth = 1
}
const join: SanitizedJoin = {

View File

@@ -1416,6 +1416,13 @@ export type JoinField = {
* This does not need to be set and will be overridden by the relationship field's localized property.
*/
localized?: boolean
/**
* The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries.
*
* @see https://payloadcms.com/docs/getting-started/concepts#depth
*
* @default 1
*/
maxDepth?: number
/**
* A string for the field in the collection being joined to.

View File

@@ -168,6 +168,45 @@ export default buildConfigWithDefaults({
},
],
},
{
slug: 'depth-joins-1',
fields: [
{
name: 'rel',
type: 'relationship',
relationTo: 'depth-joins-2',
},
{
name: 'joins',
type: 'join',
collection: 'depth-joins-3',
on: 'rel',
maxDepth: 2,
},
],
},
{
slug: 'depth-joins-2',
fields: [
{
name: 'joins',
type: 'join',
collection: 'depth-joins-1',
on: 'rel',
maxDepth: 2,
},
],
},
{
slug: 'depth-joins-3',
fields: [
{
name: 'rel',
type: 'relationship',
relationTo: 'depth-joins-1',
},
],
},
],
localization: {
locales: ['en', 'es'],

View File

@@ -5,7 +5,7 @@ import { getFileByPath } from 'payload'
import { fileURLToPath } from 'url'
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import type { Category, Config, Post, Singular } from './payload-types.js'
import type { Category, Config, DepthJoins1, DepthJoins3, Post, Singular } from './payload-types.js'
import { devUser } from '../credentials.js'
import { idToString } from '../helpers/idToString.js'
@@ -984,6 +984,35 @@ describe('Joins Field', () => {
expect((data.joins.docs[0] as TypeWithID).id).toBe(doc_2.id)
})
it('should populate joins on depth 2', async () => {
const depthJoin_2 = await payload.create({ collection: 'depth-joins-2', data: {}, depth: 0 })
const depthJoin_1 = await payload.create({
collection: 'depth-joins-1',
data: { rel: depthJoin_2 },
depth: 0,
})
const depthJoin_3 = await payload.create({
collection: 'depth-joins-3',
data: { rel: depthJoin_1 },
depth: 0,
})
const data = await payload.findByID({
collection: 'depth-joins-2',
id: depthJoin_2.id,
depth: 2,
})
const joinedDoc = data.joins.docs[0] as DepthJoins1
expect(joinedDoc.id).toBe(depthJoin_1.id)
const joinedDoc2 = joinedDoc.joins.docs[0] as DepthJoins3
expect(joinedDoc2.id).toBe(depthJoin_3.id)
})
})
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {

View File

@@ -25,6 +25,9 @@ export interface Config {
'categories-join-restricted': CategoriesJoinRestricted;
'restricted-posts': RestrictedPost;
'collection-restricted': CollectionRestricted;
'depth-joins-1': DepthJoins1;
'depth-joins-2': DepthJoins2;
'depth-joins-3': DepthJoins3;
users: User;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
@@ -66,6 +69,12 @@ export interface Config {
'categories-join-restricted': {
collectionRestrictedJoin: 'collection-restricted';
};
'depth-joins-1': {
joins: 'depth-joins-3';
};
'depth-joins-2': {
joins: 'depth-joins-1';
};
};
collectionsSelect: {
posts: PostsSelect<false> | PostsSelect<true>;
@@ -82,6 +91,9 @@ export interface Config {
'categories-join-restricted': CategoriesJoinRestrictedSelect<false> | CategoriesJoinRestrictedSelect<true>;
'restricted-posts': RestrictedPostsSelect<false> | RestrictedPostsSelect<true>;
'collection-restricted': CollectionRestrictedSelect<false> | CollectionRestrictedSelect<true>;
'depth-joins-1': DepthJoins1Select<false> | DepthJoins1Select<true>;
'depth-joins-2': DepthJoins2Select<false> | DepthJoins2Select<true>;
'depth-joins-3': DepthJoins3Select<false> | DepthJoins3Select<true>;
users: UsersSelect<false> | UsersSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -451,6 +463,43 @@ export interface RestrictedPost {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-1".
*/
export interface DepthJoins1 {
id: string;
rel?: (string | null) | DepthJoins2;
joins?: {
docs?: (string | DepthJoins3)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-2".
*/
export interface DepthJoins2 {
id: string;
joins?: {
docs?: (string | DepthJoins1)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-3".
*/
export interface DepthJoins3 {
id: string;
rel?: (string | null) | DepthJoins1;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
@@ -514,6 +563,18 @@ export interface PayloadLockedDocument {
relationTo: 'collection-restricted';
value: string | CollectionRestricted;
} | null)
| ({
relationTo: 'depth-joins-1';
value: string | DepthJoins1;
} | null)
| ({
relationTo: 'depth-joins-2';
value: string | DepthJoins2;
} | null)
| ({
relationTo: 'depth-joins-3';
value: string | DepthJoins3;
} | null)
| ({
relationTo: 'users';
value: string | User;
@@ -761,6 +822,34 @@ export interface CollectionRestrictedSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-1_select".
*/
export interface DepthJoins1Select<T extends boolean = true> {
rel?: T;
joins?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-2_select".
*/
export interface DepthJoins2Select<T extends boolean = true> {
joins?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "depth-joins-3_select".
*/
export interface DepthJoins3Select<T extends boolean = true> {
rel?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".