fix: block row removal w/ db-postgres adapter (#3951)

This commit is contained in:
Jarrod Flesch
2023-11-01 08:32:02 -04:00
committed by GitHub
parent 386fe0741d
commit 5ea88bb47d
11 changed files with 107 additions and 81 deletions

View File

@@ -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: '',

View File

@@ -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: '',

View File

@@ -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: '',

View File

@@ -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,

View File

@@ -30,6 +30,7 @@ export type RowToInsert = {
blocks: {
[blockType: string]: BlockRowToInsert[]
}
blocksToDelete: Set<string>
locales: {
[locale: string]: Record<string, unknown>
}

View File

@@ -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))

View File

@@ -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,
},
},
},
],
}

View File

@@ -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,
},
},
},
],
}

View File

@@ -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')
})
})
})
})