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.
This commit is contained in:
@@ -350,10 +350,13 @@ export const promise = async ({
|
|||||||
case 'array': {
|
case 'array': {
|
||||||
const rows = siblingDoc[field.name] as JsonObject
|
const rows = siblingDoc[field.name] as JsonObject
|
||||||
|
|
||||||
const arraySelect = select?.[field.name]
|
let arraySelect = select?.[field.name]
|
||||||
|
|
||||||
if (selectMode === 'include' && typeof arraySelect === 'object') {
|
if (selectMode === 'include' && typeof arraySelect === 'object') {
|
||||||
arraySelect.id = true
|
arraySelect = {
|
||||||
|
...arraySelect,
|
||||||
|
id: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(rows)) {
|
if (Array.isArray(rows)) {
|
||||||
@@ -427,7 +430,7 @@ export const promise = async ({
|
|||||||
case 'blocks': {
|
case 'blocks': {
|
||||||
const rows = siblingDoc[field.name]
|
const rows = siblingDoc[field.name]
|
||||||
|
|
||||||
const blocksSelect = select?.[field.name]
|
let blocksSelect = select?.[field.name]
|
||||||
|
|
||||||
if (Array.isArray(rows)) {
|
if (Array.isArray(rows)) {
|
||||||
rows.forEach((row, i) => {
|
rows.forEach((row, i) => {
|
||||||
@@ -438,6 +441,10 @@ export const promise = async ({
|
|||||||
let blockSelectMode = selectMode
|
let blockSelectMode = selectMode
|
||||||
|
|
||||||
if (typeof blocksSelect === 'object') {
|
if (typeof blocksSelect === 'object') {
|
||||||
|
blocksSelect = {
|
||||||
|
...blocksSelect,
|
||||||
|
}
|
||||||
|
|
||||||
// sanitize blocks: {cta: false} to blocks: {cta: {id: true, blockType: true}}
|
// sanitize blocks: {cta: false} to blocks: {cta: {id: true, blockType: true}}
|
||||||
if (selectMode === 'exclude' && blocksSelect[block.slug] === false) {
|
if (selectMode === 'exclude' && blocksSelect[block.slug] === false) {
|
||||||
blockSelectMode = 'include'
|
blockSelectMode = 'include'
|
||||||
@@ -451,6 +458,10 @@ export const promise = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof blocksSelect[block.slug] === 'object') {
|
if (typeof blocksSelect[block.slug] === 'object') {
|
||||||
|
blocksSelect[block.slug] = {
|
||||||
|
...(blocksSelect[block.slug] as object),
|
||||||
|
}
|
||||||
|
|
||||||
blocksSelect[block.slug]['id'] = true
|
blocksSelect[block.slug]['id'] = true
|
||||||
blocksSelect[block.slug]['blockType'] = true
|
blocksSelect[block.slug]['blockType'] = true
|
||||||
}
|
}
|
||||||
@@ -535,7 +546,6 @@ export const promise = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'collapsible':
|
case 'collapsible':
|
||||||
|
|
||||||
case 'row': {
|
case 'row': {
|
||||||
traverseFields({
|
traverseFields({
|
||||||
collection,
|
collection,
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
// I need only slug, NOT the WHOLE CONTENT!
|
// I need only slug, NOT the WHOLE CONTENT!
|
||||||
defaultPopulate: {
|
defaultPopulate: {
|
||||||
slug: true,
|
slug: true,
|
||||||
|
array: {
|
||||||
|
title: true,
|
||||||
|
},
|
||||||
|
blocks: {
|
||||||
|
some: {
|
||||||
|
title: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
access: { read: () => true },
|
access: { read: () => true },
|
||||||
fields: [
|
fields: [
|
||||||
@@ -85,5 +93,38 @@ export const Pages: CollectionConfig<'pages'> = {
|
|||||||
name: 'additional',
|
name: 'additional',
|
||||||
type: 'text',
|
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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1781,15 +1781,64 @@ describe('Select', () => {
|
|||||||
describe('populate / defaultPopulate', () => {
|
describe('populate / defaultPopulate', () => {
|
||||||
let homePage: Page
|
let homePage: Page
|
||||||
let aboutPage: 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 }
|
let expectedHomePageOverride: { additional: string; id: number | string }
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
homePage = await payload.create({
|
homePage = await payload.create({
|
||||||
depth: 0,
|
depth: 0,
|
||||||
collection: 'pages',
|
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 }
|
expectedHomePageOverride = { id: homePage.id, additional: homePage.additional }
|
||||||
aboutPage = await payload.create({
|
aboutPage = await payload.create({
|
||||||
depth: 0,
|
depth: 0,
|
||||||
|
|||||||
@@ -309,6 +309,22 @@ export interface Page {
|
|||||||
| null;
|
| null;
|
||||||
slug: string;
|
slug: string;
|
||||||
additional?: string | null;
|
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;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -657,6 +673,25 @@ export interface PagesSelect<T extends boolean = true> {
|
|||||||
};
|
};
|
||||||
slug?: T;
|
slug?: T;
|
||||||
additional?: 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;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user