fix: block row removal w/ db-postgres adapter (#3951)
This commit is contained in:
@@ -14,6 +14,7 @@ type Args = {
|
||||
blocks: {
|
||||
[blockType: string]: BlockRowToInsert[]
|
||||
}
|
||||
blocksToDelete: Set<string>
|
||||
data: unknown
|
||||
field: ArrayField
|
||||
locale?: string
|
||||
@@ -31,6 +32,7 @@ export const transformArray = ({
|
||||
arrayTableName,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data,
|
||||
field,
|
||||
locale,
|
||||
@@ -78,6 +80,7 @@ export const transformArray = ({
|
||||
arrays: newRow.arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: '',
|
||||
data: arrayRow,
|
||||
fieldPrefix: '',
|
||||
|
||||
@@ -14,6 +14,7 @@ type Args = {
|
||||
blocks: {
|
||||
[blockType: string]: BlockRowToInsert[]
|
||||
}
|
||||
blocksToDelete: Set<string>
|
||||
data: Record<string, unknown>[]
|
||||
field: BlockField
|
||||
locale?: string
|
||||
@@ -29,6 +30,7 @@ export const transformBlocks = ({
|
||||
adapter,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data,
|
||||
field,
|
||||
locale,
|
||||
@@ -76,6 +78,7 @@ export const transformBlocks = ({
|
||||
arrays: newRow.arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: '',
|
||||
data: blockRow,
|
||||
fieldPrefix: '',
|
||||
|
||||
@@ -25,6 +25,7 @@ export const transformForWrite = ({
|
||||
const rowToInsert: RowToInsert = {
|
||||
arrays: {},
|
||||
blocks: {},
|
||||
blocksToDelete: new Set(),
|
||||
locales: {},
|
||||
numbers: [],
|
||||
relationships: [],
|
||||
@@ -40,6 +41,7 @@ export const transformForWrite = ({
|
||||
arrays: rowToInsert.arrays,
|
||||
baseTableName: tableName,
|
||||
blocks: rowToInsert.blocks,
|
||||
blocksToDelete: rowToInsert.blocksToDelete,
|
||||
columnPrefix: '',
|
||||
data,
|
||||
fieldPrefix: '',
|
||||
|
||||
@@ -26,6 +26,7 @@ type Args = {
|
||||
blocks: {
|
||||
[blockType: string]: BlockRowToInsert[]
|
||||
}
|
||||
blocksToDelete: Set<string>
|
||||
/**
|
||||
* A snake-case field prefix, representing prior fields
|
||||
* Ex: my_group_my_named_tab_
|
||||
@@ -62,6 +63,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix,
|
||||
data,
|
||||
existingLocales,
|
||||
@@ -102,6 +104,7 @@ export const traverseFields = ({
|
||||
arrayTableName,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data: localeData,
|
||||
field,
|
||||
locale: localeKey,
|
||||
@@ -122,6 +125,7 @@ export const traverseFields = ({
|
||||
arrayTableName,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data: data[field.name],
|
||||
field,
|
||||
numbers,
|
||||
@@ -138,6 +142,10 @@ export const traverseFields = ({
|
||||
}
|
||||
|
||||
if (field.type === 'blocks') {
|
||||
field.blocks.forEach(({ slug }) => {
|
||||
blocksToDelete.add(toSnakeCase(slug))
|
||||
})
|
||||
|
||||
if (field.localized) {
|
||||
if (typeof data[field.name] === 'object' && data[field.name] !== null) {
|
||||
Object.entries(data[field.name]).forEach(([localeKey, localeData]) => {
|
||||
@@ -146,6 +154,7 @@ export const traverseFields = ({
|
||||
adapter,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data: localeData,
|
||||
field,
|
||||
locale: localeKey,
|
||||
@@ -163,6 +172,7 @@ export const traverseFields = ({
|
||||
adapter,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
data: fieldData,
|
||||
field,
|
||||
numbers,
|
||||
@@ -185,6 +195,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: `${columnName}_`,
|
||||
data: localeData as Record<string, unknown>,
|
||||
existingLocales,
|
||||
@@ -207,6 +218,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: `${columnName}_`,
|
||||
data: data[field.name] as Record<string, unknown>,
|
||||
existingLocales,
|
||||
@@ -238,6 +250,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: `${columnPrefix || ''}${toSnakeCase(tab.name)}_`,
|
||||
data: localeData as Record<string, unknown>,
|
||||
existingLocales,
|
||||
@@ -260,6 +273,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix: `${columnPrefix || ''}${toSnakeCase(tab.name)}_`,
|
||||
data: data[tab.name] as Record<string, unknown>,
|
||||
existingLocales,
|
||||
@@ -282,6 +296,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix,
|
||||
data,
|
||||
existingLocales,
|
||||
@@ -306,6 +321,7 @@ export const traverseFields = ({
|
||||
arrays,
|
||||
baseTableName,
|
||||
blocks,
|
||||
blocksToDelete,
|
||||
columnPrefix,
|
||||
data,
|
||||
existingLocales,
|
||||
|
||||
@@ -30,6 +30,7 @@ export type RowToInsert = {
|
||||
blocks: {
|
||||
[blockType: string]: BlockRowToInsert[]
|
||||
}
|
||||
blocksToDelete: Set<string>
|
||||
locales: {
|
||||
[locale: string]: Record<string, unknown>
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
import type { TypeWithID } from 'payload/types'
|
||||
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { ValidationError } from 'payload/errors'
|
||||
import { i18nInit } from 'payload/utilities'
|
||||
|
||||
import type { BlockRowToInsert } from '../transform/write/types'
|
||||
import type { Args } from './types'
|
||||
@@ -12,8 +14,6 @@ import { transformForWrite } from '../transform/write'
|
||||
import { deleteExistingArrayRows } from './deleteExistingArrayRows'
|
||||
import { deleteExistingRowsByPath } from './deleteExistingRowsByPath'
|
||||
import { insertArrays } from './insertArrays'
|
||||
import { ValidationError } from 'payload/errors'
|
||||
import { i18nInit } from 'payload/utilities'
|
||||
|
||||
export const upsertRow = async <T extends TypeWithID>({
|
||||
id,
|
||||
@@ -188,18 +188,15 @@ export const upsertRow = async <T extends TypeWithID>({
|
||||
|
||||
const insertedBlockRows: Record<string, Record<string, unknown>[]> = {}
|
||||
|
||||
for (const [blockName, blockRows] of Object.entries(blocksToInsert)) {
|
||||
if (operation === 'update') {
|
||||
await deleteExistingRowsByPath({
|
||||
adapter,
|
||||
db,
|
||||
parentID: insertedRow.id,
|
||||
pathColumnName: '_path',
|
||||
rows: blockRows.map(({ row }) => row),
|
||||
tableName: `${tableName}_blocks_${blockName}`,
|
||||
})
|
||||
if (operation === 'update') {
|
||||
for (const blockName of rowToInsert.blocksToDelete) {
|
||||
const blockTableName = `${tableName}_blocks_${blockName}`
|
||||
const blockTable = adapter.tables[blockTableName]
|
||||
await db.delete(blockTable).where(eq(blockTable._parentID, insertedRow.id))
|
||||
}
|
||||
}
|
||||
|
||||
for (const [blockName, blockRows] of Object.entries(blocksToInsert)) {
|
||||
insertedBlockRows[blockName] = await db
|
||||
.insert(adapter.tables[`${tableName}_blocks_${blockName}`])
|
||||
.values(blockRows.map(({ row }) => row))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { CollectionConfig } from '../../../../packages/payload/src/collections/config/types'
|
||||
|
||||
import { ArrayRowLabel } from './LabelComponent'
|
||||
import { AddCustomBlocks } from './components/AddCustomBlocks'
|
||||
|
||||
export const arrayDefaultValue = [{ text: 'row one' }, { text: 'row two' }]
|
||||
|
||||
@@ -127,39 +126,6 @@ const ArrayFields: CollectionConfig = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'customBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block-1',
|
||||
fields: [
|
||||
{
|
||||
name: 'block1Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'block-2',
|
||||
fields: [
|
||||
{
|
||||
name: 'block2Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ui',
|
||||
name: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
Field: AddCustomBlocks,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { CollectionConfig } from '../../../../packages/payload/src/collections/config/types'
|
||||
import type { BlockField } from '../../../../packages/payload/src/fields/config/types'
|
||||
|
||||
import { AddCustomBlocks } from './components/AddCustomBlocks'
|
||||
|
||||
export const getBlocksFieldSeedData = (prefix?: string): any => [
|
||||
{
|
||||
blockName: 'First block',
|
||||
@@ -210,7 +212,7 @@ const BlockFields: CollectionConfig = {
|
||||
name: 'blocksWithSimilarConfigs',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block-1',
|
||||
slug: 'block-a',
|
||||
fields: [
|
||||
{
|
||||
type: 'array',
|
||||
@@ -226,7 +228,7 @@ const BlockFields: CollectionConfig = {
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'block-2',
|
||||
slug: 'block-b',
|
||||
fields: [
|
||||
{
|
||||
type: 'array',
|
||||
@@ -243,6 +245,39 @@ const BlockFields: CollectionConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'customBlocks',
|
||||
type: 'blocks',
|
||||
blocks: [
|
||||
{
|
||||
slug: 'block-1',
|
||||
fields: [
|
||||
{
|
||||
name: 'block1Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'block-2',
|
||||
fields: [
|
||||
{
|
||||
name: 'block2Title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'ui',
|
||||
name: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
Field: AddCustomBlocks,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import path from 'path'
|
||||
|
||||
@@ -480,7 +481,7 @@ describe('fields', () => {
|
||||
test('should add different blocks with similar field configs', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
async function addBlock(name: 'Block 1' | 'Block 2') {
|
||||
async function addBlock(name: 'Block A' | 'Block B') {
|
||||
await page
|
||||
.locator('#field-blocksWithSimilarConfigs')
|
||||
.getByRole('button', { name: 'Add Blocks With Similar Config' })
|
||||
@@ -488,7 +489,7 @@ describe('fields', () => {
|
||||
await page.getByRole('button', { name }).click()
|
||||
}
|
||||
|
||||
await addBlock('Block 1')
|
||||
await addBlock('Block A')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-0')
|
||||
@@ -502,7 +503,7 @@ describe('fields', () => {
|
||||
page.locator('input[name="blocksWithSimilarConfigs.0.items.0.title"]'),
|
||||
).toHaveValue('items>0>title')
|
||||
|
||||
await addBlock('Block 2')
|
||||
await addBlock('Block B')
|
||||
|
||||
await page
|
||||
.locator('#blocksWithSimilarConfigs-row-1')
|
||||
@@ -516,6 +517,38 @@ describe('fields', () => {
|
||||
page.locator('input[name="blocksWithSimilarConfigs.1.items.0.title2"]'),
|
||||
).toHaveValue('items>1>title')
|
||||
})
|
||||
|
||||
describe('row manipulation', () => {
|
||||
describe('react hooks', () => {
|
||||
test('should add 2 new block rows', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 1' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.0.block1Title"]'),
|
||||
).toHaveValue('Block 1: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block2Title"]'),
|
||||
).toHaveValue('Block 2: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Replace Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block1Title"]'),
|
||||
).toHaveValue('REPLACED BLOCK')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('array', () => {
|
||||
@@ -643,36 +676,6 @@ describe('fields', () => {
|
||||
page.locator('#field-potentiallyEmptyArray__0__groupInRow__textInGroupInRow'),
|
||||
).toHaveValue(`${assertGroupText3} duplicate`)
|
||||
})
|
||||
|
||||
describe('react hooks', () => {
|
||||
test('should add 2 new block rows', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 1' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.0.block1Title"]'),
|
||||
).toHaveValue('Block 1: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Add Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block2Title"]'),
|
||||
).toHaveValue('Block 2: Prefilled Title')
|
||||
|
||||
await page
|
||||
.locator('.custom-blocks-field-management')
|
||||
.getByRole('button', { name: 'Replace Block 2' })
|
||||
.click()
|
||||
await expect(
|
||||
page.locator('#field-customBlocks input[name="customBlocks.1.block1Title"]'),
|
||||
).toHaveValue('REPLACED BLOCK')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user