Skip to content

Commit ba228dd

Browse files
authored
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 #10243 is not an issue, but just happens because the default `maxDepth` is `1`.
1 parent c7b3204 commit ba228dd

File tree

5 files changed

+166
-2
lines changed

5 files changed

+166
-2
lines changed

packages/payload/src/fields/config/sanitizeJoinField.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const sanitizeJoinField = ({
2020
if (typeof joins === 'undefined') {
2121
throw new APIError('Join fields cannot be added to arrays, blocks or globals.')
2222
}
23-
if (!field.maxDepth) {
23+
if (typeof field.maxDepth === 'undefined') {
2424
field.maxDepth = 1
2525
}
2626
const join: SanitizedJoin = {

packages/payload/src/fields/config/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,13 @@ export type JoinField = {
14161416
* This does not need to be set and will be overridden by the relationship field's localized property.
14171417
*/
14181418
localized?: boolean
1419+
/**
1420+
* The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries.
1421+
*
1422+
* @see https://payloadcms.com/docs/getting-started/concepts#depth
1423+
*
1424+
* @default 1
1425+
*/
14191426
maxDepth?: number
14201427
/**
14211428
* A string for the field in the collection being joined to.

test/joins/config.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,45 @@ export default buildConfigWithDefaults({
168168
},
169169
],
170170
},
171+
{
172+
slug: 'depth-joins-1',
173+
fields: [
174+
{
175+
name: 'rel',
176+
type: 'relationship',
177+
relationTo: 'depth-joins-2',
178+
},
179+
{
180+
name: 'joins',
181+
type: 'join',
182+
collection: 'depth-joins-3',
183+
on: 'rel',
184+
maxDepth: 2,
185+
},
186+
],
187+
},
188+
{
189+
slug: 'depth-joins-2',
190+
fields: [
191+
{
192+
name: 'joins',
193+
type: 'join',
194+
collection: 'depth-joins-1',
195+
on: 'rel',
196+
maxDepth: 2,
197+
},
198+
],
199+
},
200+
{
201+
slug: 'depth-joins-3',
202+
fields: [
203+
{
204+
name: 'rel',
205+
type: 'relationship',
206+
relationTo: 'depth-joins-1',
207+
},
208+
],
209+
},
171210
],
172211
localization: {
173212
locales: ['en', 'es'],

test/joins/int.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getFileByPath } from 'payload'
55
import { fileURLToPath } from 'url'
66

77
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
8-
import type { Category, Config, Post, Singular } from './payload-types.js'
8+
import type { Category, Config, DepthJoins1, DepthJoins3, Post, Singular } from './payload-types.js'
99

1010
import { devUser } from '../credentials.js'
1111
import { idToString } from '../helpers/idToString.js'
@@ -984,6 +984,35 @@ describe('Joins Field', () => {
984984

985985
expect((data.joins.docs[0] as TypeWithID).id).toBe(doc_2.id)
986986
})
987+
988+
it('should populate joins on depth 2', async () => {
989+
const depthJoin_2 = await payload.create({ collection: 'depth-joins-2', data: {}, depth: 0 })
990+
const depthJoin_1 = await payload.create({
991+
collection: 'depth-joins-1',
992+
data: { rel: depthJoin_2 },
993+
depth: 0,
994+
})
995+
996+
const depthJoin_3 = await payload.create({
997+
collection: 'depth-joins-3',
998+
data: { rel: depthJoin_1 },
999+
depth: 0,
1000+
})
1001+
1002+
const data = await payload.findByID({
1003+
collection: 'depth-joins-2',
1004+
id: depthJoin_2.id,
1005+
depth: 2,
1006+
})
1007+
1008+
const joinedDoc = data.joins.docs[0] as DepthJoins1
1009+
1010+
expect(joinedDoc.id).toBe(depthJoin_1.id)
1011+
1012+
const joinedDoc2 = joinedDoc.joins.docs[0] as DepthJoins3
1013+
1014+
expect(joinedDoc2.id).toBe(depthJoin_3.id)
1015+
})
9871016
})
9881017

9891018
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {

test/joins/payload-types.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ export interface Config {
2525
'categories-join-restricted': CategoriesJoinRestricted;
2626
'restricted-posts': RestrictedPost;
2727
'collection-restricted': CollectionRestricted;
28+
'depth-joins-1': DepthJoins1;
29+
'depth-joins-2': DepthJoins2;
30+
'depth-joins-3': DepthJoins3;
2831
users: User;
2932
'payload-locked-documents': PayloadLockedDocument;
3033
'payload-preferences': PayloadPreference;
@@ -66,6 +69,12 @@ export interface Config {
6669
'categories-join-restricted': {
6770
collectionRestrictedJoin: 'collection-restricted';
6871
};
72+
'depth-joins-1': {
73+
joins: 'depth-joins-3';
74+
};
75+
'depth-joins-2': {
76+
joins: 'depth-joins-1';
77+
};
6978
};
7079
collectionsSelect: {
7180
posts: PostsSelect<false> | PostsSelect<true>;
@@ -82,6 +91,9 @@ export interface Config {
8291
'categories-join-restricted': CategoriesJoinRestrictedSelect<false> | CategoriesJoinRestrictedSelect<true>;
8392
'restricted-posts': RestrictedPostsSelect<false> | RestrictedPostsSelect<true>;
8493
'collection-restricted': CollectionRestrictedSelect<false> | CollectionRestrictedSelect<true>;
94+
'depth-joins-1': DepthJoins1Select<false> | DepthJoins1Select<true>;
95+
'depth-joins-2': DepthJoins2Select<false> | DepthJoins2Select<true>;
96+
'depth-joins-3': DepthJoins3Select<false> | DepthJoins3Select<true>;
8597
users: UsersSelect<false> | UsersSelect<true>;
8698
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
8799
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -451,6 +463,43 @@ export interface RestrictedPost {
451463
updatedAt: string;
452464
createdAt: string;
453465
}
466+
/**
467+
* This interface was referenced by `Config`'s JSON-Schema
468+
* via the `definition` "depth-joins-1".
469+
*/
470+
export interface DepthJoins1 {
471+
id: string;
472+
rel?: (string | null) | DepthJoins2;
473+
joins?: {
474+
docs?: (string | DepthJoins3)[] | null;
475+
hasNextPage?: boolean | null;
476+
} | null;
477+
updatedAt: string;
478+
createdAt: string;
479+
}
480+
/**
481+
* This interface was referenced by `Config`'s JSON-Schema
482+
* via the `definition` "depth-joins-2".
483+
*/
484+
export interface DepthJoins2 {
485+
id: string;
486+
joins?: {
487+
docs?: (string | DepthJoins1)[] | null;
488+
hasNextPage?: boolean | null;
489+
} | null;
490+
updatedAt: string;
491+
createdAt: string;
492+
}
493+
/**
494+
* This interface was referenced by `Config`'s JSON-Schema
495+
* via the `definition` "depth-joins-3".
496+
*/
497+
export interface DepthJoins3 {
498+
id: string;
499+
rel?: (string | null) | DepthJoins1;
500+
updatedAt: string;
501+
createdAt: string;
502+
}
454503
/**
455504
* This interface was referenced by `Config`'s JSON-Schema
456505
* via the `definition` "payload-locked-documents".
@@ -514,6 +563,18 @@ export interface PayloadLockedDocument {
514563
relationTo: 'collection-restricted';
515564
value: string | CollectionRestricted;
516565
} | null)
566+
| ({
567+
relationTo: 'depth-joins-1';
568+
value: string | DepthJoins1;
569+
} | null)
570+
| ({
571+
relationTo: 'depth-joins-2';
572+
value: string | DepthJoins2;
573+
} | null)
574+
| ({
575+
relationTo: 'depth-joins-3';
576+
value: string | DepthJoins3;
577+
} | null)
517578
| ({
518579
relationTo: 'users';
519580
value: string | User;
@@ -761,6 +822,34 @@ export interface CollectionRestrictedSelect<T extends boolean = true> {
761822
updatedAt?: T;
762823
createdAt?: T;
763824
}
825+
/**
826+
* This interface was referenced by `Config`'s JSON-Schema
827+
* via the `definition` "depth-joins-1_select".
828+
*/
829+
export interface DepthJoins1Select<T extends boolean = true> {
830+
rel?: T;
831+
joins?: T;
832+
updatedAt?: T;
833+
createdAt?: T;
834+
}
835+
/**
836+
* This interface was referenced by `Config`'s JSON-Schema
837+
* via the `definition` "depth-joins-2_select".
838+
*/
839+
export interface DepthJoins2Select<T extends boolean = true> {
840+
joins?: T;
841+
updatedAt?: T;
842+
createdAt?: T;
843+
}
844+
/**
845+
* This interface was referenced by `Config`'s JSON-Schema
846+
* via the `definition` "depth-joins-3_select".
847+
*/
848+
export interface DepthJoins3Select<T extends boolean = true> {
849+
rel?: T;
850+
updatedAt?: T;
851+
createdAt?: T;
852+
}
764853
/**
765854
* This interface was referenced by `Config`'s JSON-Schema
766855
* via the `definition` "users_select".

0 commit comments

Comments
 (0)