From 7def6b7ddf8404a9ec2a56342ced6b6723176285 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:29:22 +0200 Subject: [PATCH] fix: `defaultPopulate` and `populate` with nested to arrays/blocks properties (#9751) Fixes https://github.com/payloadcms/payload/issues/9718 ### What? `defaultPopulate` and `populate` didn't work properly when defining nested to arrays and blocks properties: ```ts import type { CollectionConfig } from 'payload' export const Pages: CollectionConfig<'pages'> = { slug: 'pages', defaultPopulate: { slug: true, array: { title: true, }, blocks: { some: { title: true, }, }, }, access: { read: () => true }, fields: [ { name: 'slug', type: 'text', required: true, }, { name: 'additional', type: 'text', }, { name: 'array', type: 'array', fields: [ { name: 'title', type: 'text', }, { name: 'other', type: 'text', }, ], }, { name: 'blocks', type: 'blocks', blocks: [ { slug: 'some', fields: [ { name: 'title', type: 'text', }, { name: 'other', type: 'text', }, ], }, ], }, ], } ``` ### Why? This should work ### How? Turns out, it wasn't a great idea to mutate passed `select` directly in `afterRead/promise.ts` to force select some properties `id` , `blockType`. Now we do shallow copies when needed. --- .../src/fields/hooks/afterRead/promise.ts | 18 ++++-- test/select/collections/Pages/index.ts | 41 ++++++++++++++ test/select/int.spec.ts | 55 ++++++++++++++++++- test/select/payload-types.ts | 35 ++++++++++++ 4 files changed, 142 insertions(+), 7 deletions(-) diff --git a/packages/payload/src/fields/hooks/afterRead/promise.ts b/packages/payload/src/fields/hooks/afterRead/promise.ts index 25a22d5160..00fd083dbf 100644 --- a/packages/payload/src/fields/hooks/afterRead/promise.ts +++ b/packages/payload/src/fields/hooks/afterRead/promise.ts @@ -350,10 +350,13 @@ export const promise = async ({ case 'array': { const rows = siblingDoc[field.name] as JsonObject - const arraySelect = select?.[field.name] + let arraySelect = select?.[field.name] if (selectMode === 'include' && typeof arraySelect === 'object') { - arraySelect.id = true + arraySelect = { + ...arraySelect, + id: true, + } } if (Array.isArray(rows)) { @@ -427,7 +430,7 @@ export const promise = async ({ case 'blocks': { const rows = siblingDoc[field.name] - const blocksSelect = select?.[field.name] + let blocksSelect = select?.[field.name] if (Array.isArray(rows)) { rows.forEach((row, i) => { @@ -438,6 +441,10 @@ export const promise = async ({ let blockSelectMode = selectMode if (typeof blocksSelect === 'object') { + blocksSelect = { + ...blocksSelect, + } + // sanitize blocks: {cta: false} to blocks: {cta: {id: true, blockType: true}} if (selectMode === 'exclude' && blocksSelect[block.slug] === false) { blockSelectMode = 'include' @@ -451,6 +458,10 @@ export const promise = async ({ } if (typeof blocksSelect[block.slug] === 'object') { + blocksSelect[block.slug] = { + ...(blocksSelect[block.slug] as object), + } + blocksSelect[block.slug]['id'] = true blocksSelect[block.slug]['blockType'] = true } @@ -535,7 +546,6 @@ export const promise = async ({ } case 'collapsible': - case 'row': { traverseFields({ collection, diff --git a/test/select/collections/Pages/index.ts b/test/select/collections/Pages/index.ts index ee8d3c011f..bf79883f3f 100644 --- a/test/select/collections/Pages/index.ts +++ b/test/select/collections/Pages/index.ts @@ -10,6 +10,14 @@ export const Pages: CollectionConfig<'pages'> = { // I need only slug, NOT the WHOLE CONTENT! defaultPopulate: { slug: true, + array: { + title: true, + }, + blocks: { + some: { + title: true, + }, + }, }, access: { read: () => true }, fields: [ @@ -85,5 +93,38 @@ export const Pages: CollectionConfig<'pages'> = { name: 'additional', type: 'text', }, + { + name: 'array', + type: 'array', + fields: [ + { + name: 'title', + type: 'text', + }, + { + name: 'other', + type: 'text', + }, + ], + }, + { + name: 'blocks', + type: 'blocks', + blocks: [ + { + slug: 'some', + fields: [ + { + name: 'title', + type: 'text', + }, + { + name: 'other', + type: 'text', + }, + ], + }, + ], + }, ], } diff --git a/test/select/int.spec.ts b/test/select/int.spec.ts index 33d13a2549..ffa515817d 100644 --- a/test/select/int.spec.ts +++ b/test/select/int.spec.ts @@ -1781,15 +1781,64 @@ describe('Select', () => { describe('populate / defaultPopulate', () => { let homePage: Page let aboutPage: Page - let expectedHomePage: { id: number | string; slug: string } + let expectedHomePage: { + array: [ + { + id: string + title: string + }, + ] + blocks: [ + { + blockType: string + id: string + title: string + }, + ] + id: number | string + slug: string + } let expectedHomePageOverride: { additional: string; id: number | string } beforeAll(async () => { homePage = await payload.create({ depth: 0, collection: 'pages', - data: { content: [], slug: 'home', additional: 'additional-data' }, + data: { + content: [], + slug: 'home', + array: [ + { + title: 'some-title', + other: 'other', + }, + ], + blocks: [ + { + blockType: 'some', + other: 'other', + title: 'some-title', + }, + ], + additional: 'additional-data', + }, }) - expectedHomePage = { id: homePage.id, slug: homePage.slug } + expectedHomePage = { + id: homePage.id, + slug: homePage.slug, + array: [ + { + id: homePage.array[0].id, + title: homePage.array[0].title, + }, + ], + blocks: [ + { + blockType: homePage.blocks[0].blockType, + id: homePage.blocks[0].id, + title: homePage.blocks[0].title, + }, + ], + } expectedHomePageOverride = { id: homePage.id, additional: homePage.additional } aboutPage = await payload.create({ depth: 0, diff --git a/test/select/payload-types.ts b/test/select/payload-types.ts index ec139c5cf6..9d6c7ca08c 100644 --- a/test/select/payload-types.ts +++ b/test/select/payload-types.ts @@ -309,6 +309,22 @@ export interface Page { | null; slug: string; additional?: string | null; + array?: + | { + title?: string | null; + other?: string | null; + id?: string | null; + }[] + | null; + blocks?: + | { + title?: string | null; + other?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'some'; + }[] + | null; updatedAt: string; createdAt: string; } @@ -657,6 +673,25 @@ export interface PagesSelect { }; slug?: T; additional?: T; + array?: + | T + | { + title?: T; + other?: T; + id?: T; + }; + blocks?: + | T + | { + some?: + | T + | { + title?: T; + other?: T; + id?: T; + blockName?: T; + }; + }; updatedAt?: T; createdAt?: T; }