Skip to content

Commit 54afaf9

Browse files
r1tsuuDanRibbens
andauthored
fix(db-mongodb): strip deleted from the config blocks from the result (#12869)
If you (using the MongoDB adapter) delete a block from the payload config, but still have some data with that block in the DB, you'd receive in the admin panel an error like: ``` Block with type "cta" was found in block data, but no block with that type is defined in the config for field with schema path pages.blocks ``` Now, we remove those "unknown" blocks at the DB adapter level. Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
1 parent 3830d71 commit 54afaf9

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

packages/db-mongodb/src/utilities/transform.ts

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,9 @@ const stripFields = ({
277277
continue
278278
}
279279

280-
for (const data of localeData) {
280+
let hasNull = false
281+
for (let i = 0; i < localeData.length; i++) {
282+
const data = localeData[i]
281283
let fields: FlattenedField[] | null = null
282284

283285
if (field.type === 'array') {
@@ -286,11 +288,17 @@ const stripFields = ({
286288
let maybeBlock: FlattenedBlock | undefined = undefined
287289

288290
if (field.blockReferences) {
289-
const maybeBlockReference = field.blockReferences.find(
290-
(each) => typeof each === 'object' && each.slug === data.blockType,
291-
)
292-
if (maybeBlockReference && typeof maybeBlockReference === 'object') {
293-
maybeBlock = maybeBlockReference
291+
const maybeBlockReference = field.blockReferences.find((each) => {
292+
const slug = typeof each === 'string' ? each : each.slug
293+
return slug === data.blockType
294+
})
295+
296+
if (maybeBlockReference) {
297+
if (typeof maybeBlockReference === 'object') {
298+
maybeBlock = maybeBlockReference
299+
} else {
300+
maybeBlock = config.blocks?.find((each) => each.slug === maybeBlockReference)
301+
}
294302
}
295303
}
296304

@@ -300,6 +308,9 @@ const stripFields = ({
300308

301309
if (maybeBlock) {
302310
fields = maybeBlock.flattenedFields
311+
} else {
312+
localeData[i] = null
313+
hasNull = true
303314
}
304315
}
305316

@@ -310,6 +321,10 @@ const stripFields = ({
310321
stripFields({ config, data, fields, reservedKeys })
311322
}
312323

324+
if (hasNull) {
325+
fieldData[localeKey] = localeData.filter(Boolean)
326+
}
327+
313328
continue
314329
} else {
315330
stripFields({ config, data: localeData, fields: field.flattenedFields, reservedKeys })
@@ -323,7 +338,10 @@ const stripFields = ({
323338
continue
324339
}
325340

326-
for (const data of fieldData) {
341+
let hasNull = false
342+
343+
for (let i = 0; i < fieldData.length; i++) {
344+
const data = fieldData[i]
327345
let fields: FlattenedField[] | null = null
328346

329347
if (field.type === 'array') {
@@ -332,12 +350,17 @@ const stripFields = ({
332350
let maybeBlock: FlattenedBlock | undefined = undefined
333351

334352
if (field.blockReferences) {
335-
const maybeBlockReference = field.blockReferences.find(
336-
(each) => typeof each === 'object' && each.slug === data.blockType,
337-
)
338-
339-
if (maybeBlockReference && typeof maybeBlockReference === 'object') {
340-
maybeBlock = maybeBlockReference
353+
const maybeBlockReference = field.blockReferences.find((each) => {
354+
const slug = typeof each === 'string' ? each : each.slug
355+
return slug === data.blockType
356+
})
357+
358+
if (maybeBlockReference) {
359+
if (typeof maybeBlockReference === 'object') {
360+
maybeBlock = maybeBlockReference
361+
} else {
362+
maybeBlock = config.blocks?.find((each) => each.slug === maybeBlockReference)
363+
}
341364
}
342365
}
343366

@@ -347,6 +370,9 @@ const stripFields = ({
347370

348371
if (maybeBlock) {
349372
fields = maybeBlock.flattenedFields
373+
} else {
374+
fieldData[i] = null
375+
hasNull = true
350376
}
351377
}
352378

@@ -357,6 +383,10 @@ const stripFields = ({
357383
stripFields({ config, data, fields, reservedKeys })
358384
}
359385

386+
if (hasNull) {
387+
data[field.name] = fieldData.filter(Boolean)
388+
}
389+
360390
continue
361391
} else {
362392
stripFields({ config, data: fieldData, fields: field.flattenedFields, reservedKeys })

test/access-control/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable no-restricted-exports */
1+
22
import { fileURLToPath } from 'node:url'
33
import path from 'path'
44
const filename = fileURLToPath(import.meta.url)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CustomView as CustomView_c4f0e2747eca2be436a06a63cea31567 } from '../../CustomView/index.js'
22

33
export const importMap = {
4-
"/CustomView/index.js#CustomView": CustomView_c4f0e2747eca2be436a06a63cea31567
4+
'/CustomView/index.js#CustomView': CustomView_c4f0e2747eca2be436a06a63cea31567,
55
}

test/database/int.spec.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,6 +2727,53 @@ describe('database', () => {
27272727
expect(res.blocks[0]?.nested[0]?.nested).toHaveLength(0)
27282728
})
27292729

2730+
it('should ignore blocks that exist in the db but not in the config', async () => {
2731+
// not possible w/ SQL anyway
2732+
// eslint-disable-next-line jest/no-conditional-in-test
2733+
if (payload.db.name !== 'mongoose') {
2734+
return
2735+
}
2736+
2737+
const res = await payload.db.collections['blocks-docs']?.collection.insertOne({
2738+
testBlocks: [
2739+
{
2740+
id: '1',
2741+
blockType: 'cta',
2742+
text: 'valid block',
2743+
},
2744+
{
2745+
id: '2',
2746+
blockType: 'cta_2',
2747+
text: 'non-valid block',
2748+
},
2749+
],
2750+
testBlocksLocalized: {
2751+
en: [
2752+
{
2753+
id: '1',
2754+
blockType: 'cta',
2755+
text: 'valid block',
2756+
},
2757+
{
2758+
id: '2',
2759+
blockType: 'cta_2',
2760+
text: 'non-valid block',
2761+
},
2762+
],
2763+
},
2764+
})
2765+
2766+
const doc = await payload.findByID({
2767+
collection: 'blocks-docs',
2768+
id: res?.insertedId?.toHexString() as string,
2769+
locale: 'en',
2770+
})
2771+
expect(doc.testBlocks).toHaveLength(1)
2772+
expect(doc.testBlocks[0].id).toBe('1')
2773+
expect(doc.testBlocksLocalized).toHaveLength(1)
2774+
expect(doc.testBlocksLocalized[0].id).toBe('1')
2775+
})
2776+
27302777
it('should CRUD with blocks as JSON in SQL adapters', async () => {
27312778
// eslint-disable-next-line jest/no-conditional-in-test
27322779
if (!('drizzle' in payload.db)) {

test/database/up-down-migration/migrations/20250624_142145.json renamed to test/database/up-down-migration/migrations/20250624_214621.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"id": "e7129a5b-a5af-490a-8ad9-318e3caeca26",
2+
"id": "a3dd8ca0-5e09-407b-9178-e0ff7f15da59",
33
"prevId": "00000000-0000-0000-0000-000000000000",
44
"version": "7",
55
"dialect": "postgresql",
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as migration_20250624_142145 from './20250624_142145.js'
1+
import * as migration_20250624_214621 from './20250624_214621.js'
22

33
export const migrations = [
44
{
5-
up: migration_20250624_142145.up,
6-
down: migration_20250624_142145.down,
7-
name: '20250624_142145',
5+
up: migration_20250624_214621.up,
6+
down: migration_20250624_214621.down,
7+
name: '20250624_214621',
88
},
99
]

0 commit comments

Comments
 (0)