fix: populate is ignored for nested relationships (#11227)
### What? As described in https://github.com/payloadcms/payload/issues/11209, previously, the `populate` argument was ignored for nested relationships. ### Why? `populate` should work for nested relationships, no matter where they are in the tree. ### How? Preserves the `populate` argument in the payload data loader. Fixes https://github.com/payloadcms/payload/issues/11209
This commit is contained in:
@@ -3,7 +3,7 @@ import type { BatchLoadFn } from 'dataloader'
|
|||||||
|
|
||||||
import DataLoader from 'dataloader'
|
import DataLoader from 'dataloader'
|
||||||
|
|
||||||
import type { PayloadRequest, SelectType } from '../types/index.js'
|
import type { PayloadRequest, PopulateType, SelectType } from '../types/index.js'
|
||||||
import type { TypeWithID } from './config/types.js'
|
import type { TypeWithID } from './config/types.js'
|
||||||
|
|
||||||
import { isValidID } from '../utilities/isValidID.js'
|
import { isValidID } from '../utilities/isValidID.js'
|
||||||
@@ -57,6 +57,7 @@ const batchAndLoadDocs =
|
|||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
draft,
|
draft,
|
||||||
select,
|
select,
|
||||||
|
populate,
|
||||||
] = JSON.parse(key)
|
] = JSON.parse(key)
|
||||||
|
|
||||||
const batchKeyArray = [
|
const batchKeyArray = [
|
||||||
@@ -70,6 +71,7 @@ const batchAndLoadDocs =
|
|||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
draft,
|
draft,
|
||||||
select,
|
select,
|
||||||
|
populate,
|
||||||
]
|
]
|
||||||
|
|
||||||
const batchKey = JSON.stringify(batchKeyArray)
|
const batchKey = JSON.stringify(batchKeyArray)
|
||||||
@@ -107,6 +109,7 @@ const batchAndLoadDocs =
|
|||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
draft,
|
draft,
|
||||||
select,
|
select,
|
||||||
|
populate,
|
||||||
] = JSON.parse(batchKey)
|
] = JSON.parse(batchKey)
|
||||||
|
|
||||||
req.transactionID = transactionID
|
req.transactionID = transactionID
|
||||||
@@ -121,6 +124,7 @@ const batchAndLoadDocs =
|
|||||||
locale,
|
locale,
|
||||||
overrideAccess: Boolean(overrideAccess),
|
overrideAccess: Boolean(overrideAccess),
|
||||||
pagination: false,
|
pagination: false,
|
||||||
|
populate,
|
||||||
req,
|
req,
|
||||||
select,
|
select,
|
||||||
showHiddenFields: Boolean(showHiddenFields),
|
showHiddenFields: Boolean(showHiddenFields),
|
||||||
@@ -144,6 +148,7 @@ const batchAndLoadDocs =
|
|||||||
fallbackLocale,
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
|
populate,
|
||||||
select,
|
select,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
transactionID: req.transactionID,
|
transactionID: req.transactionID,
|
||||||
@@ -173,6 +178,7 @@ type CreateCacheKeyArgs = {
|
|||||||
fallbackLocale: string
|
fallbackLocale: string
|
||||||
locale: string
|
locale: string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
|
populate?: PopulateType
|
||||||
select?: SelectType
|
select?: SelectType
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
transactionID: number | Promise<number | string> | string
|
transactionID: number | Promise<number | string> | string
|
||||||
@@ -186,6 +192,7 @@ export const createDataloaderCacheKey = ({
|
|||||||
fallbackLocale,
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
|
populate,
|
||||||
select,
|
select,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
transactionID,
|
transactionID,
|
||||||
@@ -202,4 +209,5 @@ export const createDataloaderCacheKey = ({
|
|||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
draft,
|
draft,
|
||||||
select,
|
select,
|
||||||
|
populate,
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ const populate = async ({
|
|||||||
fallbackLocale,
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
|
populate: populateArg,
|
||||||
select:
|
select:
|
||||||
populateArg?.[relatedCollection.config.slug] ??
|
populateArg?.[relatedCollection.config.slug] ??
|
||||||
relatedCollection.config.defaultPopulate,
|
relatedCollection.config.defaultPopulate,
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
},
|
},
|
||||||
access: { read: () => true },
|
access: { read: () => true },
|
||||||
fields: [
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'relatedPage',
|
||||||
|
type: 'relationship',
|
||||||
|
relationTo: 'pages',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'content',
|
name: 'content',
|
||||||
type: 'blocks',
|
type: 'blocks',
|
||||||
|
|||||||
@@ -2230,6 +2230,33 @@ describe('Select', () => {
|
|||||||
expect(richTextLexicalRel.value).toMatchObject(expectedHomePageOverride)
|
expect(richTextLexicalRel.value).toMatchObject(expectedHomePageOverride)
|
||||||
expect(richTextSlateRel.value).toMatchObject(expectedHomePageOverride)
|
expect(richTextSlateRel.value).toMatchObject(expectedHomePageOverride)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should apply populate on depth 2', async () => {
|
||||||
|
const page_1 = await payload.create({
|
||||||
|
collection: 'pages',
|
||||||
|
data: { relatedPage: null, blocks: [{ blockType: 'some' }], slug: 'page-1' },
|
||||||
|
})
|
||||||
|
const page_2 = await payload.create({
|
||||||
|
collection: 'pages',
|
||||||
|
data: { relatedPage: page_1.id, slug: 'page-2' },
|
||||||
|
})
|
||||||
|
const page_3 = await payload.create({
|
||||||
|
collection: 'pages',
|
||||||
|
data: { relatedPage: page_2.id, slug: 'page-3' },
|
||||||
|
})
|
||||||
|
const result = await payload.findByID({
|
||||||
|
collection: 'pages',
|
||||||
|
id: page_3.id,
|
||||||
|
depth: 3,
|
||||||
|
populate: { pages: { slug: true, relatedPage: true } },
|
||||||
|
})
|
||||||
|
expect(result.relatedPage.id).toBe(page_2.id)
|
||||||
|
expect(result.relatedPage.relatedPage as Page).toStrictEqual({
|
||||||
|
id: page_1.id,
|
||||||
|
slug: page_1.slug,
|
||||||
|
relatedPage: null,
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,65 @@
|
|||||||
* and re-run `payload generate:types` to regenerate this file.
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported timezones in IANA format.
|
||||||
|
*
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "supportedTimezones".
|
||||||
|
*/
|
||||||
|
export type SupportedTimezones =
|
||||||
|
| 'Pacific/Midway'
|
||||||
|
| 'Pacific/Niue'
|
||||||
|
| 'Pacific/Honolulu'
|
||||||
|
| 'Pacific/Rarotonga'
|
||||||
|
| 'America/Anchorage'
|
||||||
|
| 'Pacific/Gambier'
|
||||||
|
| 'America/Los_Angeles'
|
||||||
|
| 'America/Tijuana'
|
||||||
|
| 'America/Denver'
|
||||||
|
| 'America/Phoenix'
|
||||||
|
| 'America/Chicago'
|
||||||
|
| 'America/Guatemala'
|
||||||
|
| 'America/New_York'
|
||||||
|
| 'America/Bogota'
|
||||||
|
| 'America/Caracas'
|
||||||
|
| 'America/Santiago'
|
||||||
|
| 'America/Buenos_Aires'
|
||||||
|
| 'America/Sao_Paulo'
|
||||||
|
| 'Atlantic/South_Georgia'
|
||||||
|
| 'Atlantic/Azores'
|
||||||
|
| 'Atlantic/Cape_Verde'
|
||||||
|
| 'Europe/London'
|
||||||
|
| 'Europe/Berlin'
|
||||||
|
| 'Africa/Lagos'
|
||||||
|
| 'Europe/Athens'
|
||||||
|
| 'Africa/Cairo'
|
||||||
|
| 'Europe/Moscow'
|
||||||
|
| 'Asia/Riyadh'
|
||||||
|
| 'Asia/Dubai'
|
||||||
|
| 'Asia/Baku'
|
||||||
|
| 'Asia/Karachi'
|
||||||
|
| 'Asia/Tashkent'
|
||||||
|
| 'Asia/Calcutta'
|
||||||
|
| 'Asia/Dhaka'
|
||||||
|
| 'Asia/Almaty'
|
||||||
|
| 'Asia/Jakarta'
|
||||||
|
| 'Asia/Bangkok'
|
||||||
|
| 'Asia/Shanghai'
|
||||||
|
| 'Asia/Singapore'
|
||||||
|
| 'Asia/Tokyo'
|
||||||
|
| 'Asia/Seoul'
|
||||||
|
| 'Australia/Sydney'
|
||||||
|
| 'Pacific/Guam'
|
||||||
|
| 'Pacific/Noumea'
|
||||||
|
| 'Pacific/Auckland'
|
||||||
|
| 'Pacific/Fiji';
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
auth: {
|
auth: {
|
||||||
users: UserAuthOperations;
|
users: UserAuthOperations;
|
||||||
};
|
};
|
||||||
|
blocks: {};
|
||||||
collections: {
|
collections: {
|
||||||
posts: Post;
|
posts: Post;
|
||||||
'localized-posts': LocalizedPost;
|
'localized-posts': LocalizedPost;
|
||||||
@@ -122,7 +177,7 @@ export interface Post {
|
|||||||
unnamedTabNumber?: number | null;
|
unnamedTabNumber?: number | null;
|
||||||
hasOne?: (string | null) | Rel;
|
hasOne?: (string | null) | Rel;
|
||||||
hasMany?: (string | Rel)[] | null;
|
hasMany?: (string | Rel)[] | null;
|
||||||
hasManyUpload?: (string | Rel)[] | null;
|
hasManyUpload?: (string | Upload)[] | null;
|
||||||
hasOnePoly?: {
|
hasOnePoly?: {
|
||||||
relationTo: 'rels';
|
relationTo: 'rels';
|
||||||
value: string | Rel;
|
value: string | Rel;
|
||||||
@@ -145,6 +200,24 @@ export interface Rel {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "upload".
|
||||||
|
*/
|
||||||
|
export interface Upload {
|
||||||
|
id: string;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
url?: string | null;
|
||||||
|
thumbnailURL?: string | null;
|
||||||
|
filename?: string | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
focalX?: number | null;
|
||||||
|
focalY?: number | null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "localized-posts".
|
* via the `definition` "localized-posts".
|
||||||
@@ -290,6 +363,7 @@ export interface DeepPost {
|
|||||||
*/
|
*/
|
||||||
export interface Page {
|
export interface Page {
|
||||||
id: string;
|
id: string;
|
||||||
|
relatedPage?: (string | null) | Page;
|
||||||
content?:
|
content?:
|
||||||
| {
|
| {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -369,24 +443,6 @@ export interface Point {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
|
||||||
* via the `definition` "upload".
|
|
||||||
*/
|
|
||||||
export interface Upload {
|
|
||||||
id: string;
|
|
||||||
updatedAt: string;
|
|
||||||
createdAt: string;
|
|
||||||
url?: string | null;
|
|
||||||
thumbnailURL?: string | null;
|
|
||||||
filename?: string | null;
|
|
||||||
mimeType?: string | null;
|
|
||||||
filesize?: number | null;
|
|
||||||
width?: number | null;
|
|
||||||
height?: number | null;
|
|
||||||
focalX?: number | null;
|
|
||||||
focalY?: number | null;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "users".
|
* via the `definition` "users".
|
||||||
@@ -706,6 +762,7 @@ export interface DeepPostsSelect<T extends boolean = true> {
|
|||||||
* via the `definition` "pages_select".
|
* via the `definition` "pages_select".
|
||||||
*/
|
*/
|
||||||
export interface PagesSelect<T extends boolean = true> {
|
export interface PagesSelect<T extends boolean = true> {
|
||||||
|
relatedPage?: T;
|
||||||
content?:
|
content?:
|
||||||
| T
|
| T
|
||||||
| {
|
| {
|
||||||
|
|||||||
Reference in New Issue
Block a user