This PR adds **atomic** `$push` **support for array fields**. It makes it possible to safely append new items to arrays, which is especially useful when running tasks in parallel (like job queues) where multiple processes might update the same record at the same time. By handling pushes atomically, we avoid race conditions and keep data consistent - especially on postgres, where the current implementation would nuke the entire array table before re-inserting every single array item. The feature works for both localized and unlocalized arrays, and supports pushing either single or multiple items at once. This PR is a requirement for reliably running parallel tasks in the job queue - see https://github.com/payloadcms/payload/pull/13452. Alongside documenting `$push`, this PR also adds documentation for `$inc`. ## Changes to updatedAt behavior https://github.com/payloadcms/payload/pull/13335 allows us to override the updatedAt property instead of the db always setting it to the current date. However, we are not able to skip updating the updatedAt property completely. This means, usage of $push results in 2 postgres db calls: 1. set updatedAt in main row 2. append array row in arrays table This PR changes the behavior to only automatically set updatedAt if it's undefined. If you explicitly set it to `null`, this now allows you to skip the db adapter automatically setting updatedAt. => This allows us to use $push in just one single db call ## Usage Examples ### Pushing a single item to an array ```ts const post = (await payload.db.updateOne({ data: { array: { $push: { text: 'some text 2', id: new mongoose.Types.ObjectId().toHexString(), }, }, }, collection: 'posts', id: post.id, })) ``` ### Pushing a single item to a localized array ```ts const post = (await payload.db.updateOne({ data: { arrayLocalized: { $push: { en: { text: 'some text 2', id: new mongoose.Types.ObjectId().toHexString(), }, es: { text: 'some text 2 es', id: new mongoose.Types.ObjectId().toHexString(), }, }, }, }, collection: 'posts', id: post.id, })) ``` ### Pushing multiple items to an array ```ts const post = (await payload.db.updateOne({ data: { array: { $push: [ { text: 'some text 2', id: new mongoose.Types.ObjectId().toHexString(), }, { text: 'some text 3', id: new mongoose.Types.ObjectId().toHexString(), }, ], }, }, collection: 'posts', id: post.id, })) ``` ### Pushing multiple items to a localized array ```ts const post = (await payload.db.updateOne({ data: { arrayLocalized: { $push: { en: { text: 'some text 2', id: new mongoose.Types.ObjectId().toHexString(), }, es: [ { text: 'some text 2 es', id: new mongoose.Types.ObjectId().toHexString(), }, { text: 'some text 3 es', id: new mongoose.Types.ObjectId().toHexString(), }, ], }, }, }, collection: 'posts', id: post.id, })) ``` --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1211110462564647
1002 lines
22 KiB
TypeScript
1002 lines
22 KiB
TypeScript
import type { Config, TextField } from 'payload'
|
|
|
|
import { randomUUID } from 'crypto'
|
|
import { fileURLToPath } from 'node:url'
|
|
import path from 'path'
|
|
|
|
import { seed } from './seed.js'
|
|
import {
|
|
customIDsSlug,
|
|
customSchemaSlug,
|
|
defaultValuesSlug,
|
|
errorOnUnnamedFieldsSlug,
|
|
fakeCustomIDsSlug,
|
|
fieldsPersistanceSlug,
|
|
pgMigrationSlug,
|
|
placesSlug,
|
|
postsSlug,
|
|
relationASlug,
|
|
relationBSlug,
|
|
relationshipsMigrationSlug,
|
|
} from './shared.js'
|
|
|
|
const defaultValueField: TextField = {
|
|
name: 'defaultValue',
|
|
type: 'text',
|
|
defaultValue: 'default value from database',
|
|
}
|
|
|
|
const filename = fileURLToPath(import.meta.url)
|
|
const dirname = path.dirname(filename)
|
|
|
|
export const getConfig: () => Partial<Config> = () => ({
|
|
admin: {
|
|
importMap: {
|
|
baseDir: path.resolve(dirname),
|
|
},
|
|
},
|
|
collections: [
|
|
{
|
|
slug: 'noTimeStamps',
|
|
timestamps: false,
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'title',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'categories',
|
|
versions: { drafts: true },
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'title',
|
|
},
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
name: 'hideout',
|
|
fields: [
|
|
{
|
|
label: 'Cameras',
|
|
type: 'tabs',
|
|
unique: true,
|
|
tabs: [
|
|
{
|
|
name: 'camera1',
|
|
fields: [
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
name: 'time1Image',
|
|
type: 'relationship',
|
|
relationTo: 'posts',
|
|
unique: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'simple',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'text',
|
|
},
|
|
{
|
|
type: 'number',
|
|
name: 'number',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'categories-custom-id',
|
|
versions: { drafts: true },
|
|
fields: [
|
|
{
|
|
type: 'number',
|
|
name: 'id',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: postsSlug,
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
required: true,
|
|
// access: { read: () => false },
|
|
},
|
|
{
|
|
type: 'relationship',
|
|
relationTo: 'categories',
|
|
name: 'category',
|
|
},
|
|
{
|
|
type: 'relationship',
|
|
relationTo: 'categories-custom-id',
|
|
name: 'categoryCustomID',
|
|
},
|
|
{
|
|
name: 'localized',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'number',
|
|
type: 'number',
|
|
},
|
|
{
|
|
type: 'blocks',
|
|
name: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'block-third',
|
|
fields: [
|
|
{
|
|
type: 'blocks',
|
|
name: 'nested',
|
|
blocks: [
|
|
{
|
|
slug: 'block-fourth',
|
|
fields: [
|
|
{
|
|
type: 'blocks',
|
|
name: 'nested',
|
|
blocks: [],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
name: 'D1',
|
|
fields: [
|
|
{
|
|
name: 'D2',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
type: 'collapsible',
|
|
fields: [
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
fields: [
|
|
{
|
|
name: 'D3',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
type: 'collapsible',
|
|
fields: [
|
|
{
|
|
name: 'D4',
|
|
type: 'text',
|
|
},
|
|
],
|
|
label: 'Collapsible2',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
label: 'Tab1',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
label: 'Collapsible2',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
label: 'Tab1',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'hasTransaction',
|
|
type: 'checkbox',
|
|
hooks: {
|
|
beforeChange: [({ req }) => !!req.transactionID],
|
|
},
|
|
admin: {
|
|
readOnly: true,
|
|
},
|
|
},
|
|
{
|
|
name: 'throwAfterChange',
|
|
type: 'checkbox',
|
|
defaultValue: false,
|
|
hooks: {
|
|
afterChange: [
|
|
({ value }) => {
|
|
if (value) {
|
|
throw new Error('throw after change')
|
|
}
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
name: 'arrayWithIDs',
|
|
type: 'array',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'textLocalized',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'arrayWithIDsLocalized',
|
|
type: 'array',
|
|
localized: true,
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'blocksWithIDs',
|
|
type: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'block-first',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'group',
|
|
name: 'group',
|
|
fields: [{ name: 'text', type: 'text' }],
|
|
},
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
name: 'tab',
|
|
fields: [{ name: 'text', type: 'text' }],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
hooks: {
|
|
beforeOperation: [
|
|
({ args, operation, req }) => {
|
|
if (operation === 'update') {
|
|
const defaultIDType = req.payload.db.defaultIDType
|
|
|
|
if (defaultIDType === 'number' && typeof args.id === 'string') {
|
|
throw new Error('ID was not sanitized to a number properly')
|
|
}
|
|
}
|
|
|
|
return args
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
slug: errorOnUnnamedFieldsSlug,
|
|
fields: [
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
label: 'UnnamedTab',
|
|
fields: [
|
|
{
|
|
name: 'groupWithinUnnamedTab',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: defaultValuesSlug,
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
defaultValueField,
|
|
{
|
|
name: 'array',
|
|
type: 'array',
|
|
// default array with one object to test subfield defaultValue properties for Mongoose
|
|
defaultValue: [{}],
|
|
fields: [defaultValueField],
|
|
},
|
|
{
|
|
name: 'group',
|
|
type: 'group',
|
|
// we need to have to use as default in order to have subfield defaultValue properties directly for Mongoose
|
|
defaultValue: {},
|
|
fields: [defaultValueField],
|
|
},
|
|
{
|
|
name: 'select',
|
|
type: 'select',
|
|
defaultValue: 'default',
|
|
options: [
|
|
{ value: 'option0', label: 'Option 0' },
|
|
{ value: 'option1', label: 'Option 1' },
|
|
{ value: 'default', label: 'Default' },
|
|
],
|
|
},
|
|
{
|
|
name: 'point',
|
|
type: 'point',
|
|
defaultValue: [10, 20],
|
|
},
|
|
{
|
|
name: 'escape',
|
|
type: 'text',
|
|
defaultValue: "Thanks, we're excited for you to join us.",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: relationASlug,
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'richText',
|
|
type: 'richText',
|
|
},
|
|
],
|
|
labels: {
|
|
plural: 'Relation As',
|
|
singular: 'Relation A',
|
|
},
|
|
},
|
|
{
|
|
slug: relationBSlug,
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'relationship',
|
|
type: 'relationship',
|
|
relationTo: 'relation-a',
|
|
},
|
|
{
|
|
name: 'richText',
|
|
type: 'richText',
|
|
},
|
|
],
|
|
labels: {
|
|
plural: 'Relation Bs',
|
|
singular: 'Relation B',
|
|
},
|
|
},
|
|
{
|
|
slug: pgMigrationSlug,
|
|
fields: [
|
|
{
|
|
name: 'relation1',
|
|
type: 'relationship',
|
|
relationTo: 'relation-a',
|
|
},
|
|
{
|
|
name: 'myArray',
|
|
type: 'array',
|
|
fields: [
|
|
{
|
|
name: 'relation2',
|
|
type: 'relationship',
|
|
relationTo: 'relation-b',
|
|
},
|
|
{
|
|
name: 'mySubArray',
|
|
type: 'array',
|
|
fields: [
|
|
{
|
|
name: 'relation3',
|
|
type: 'relationship',
|
|
localized: true,
|
|
relationTo: 'relation-b',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'myGroup',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
name: 'relation4',
|
|
type: 'relationship',
|
|
localized: true,
|
|
relationTo: 'relation-b',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'myBlocks',
|
|
type: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'myBlock',
|
|
fields: [
|
|
{
|
|
name: 'relation5',
|
|
type: 'relationship',
|
|
relationTo: 'relation-a',
|
|
},
|
|
{
|
|
name: 'relation6',
|
|
type: 'relationship',
|
|
localized: true,
|
|
relationTo: 'relation-b',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
versions: true,
|
|
},
|
|
{
|
|
slug: customSchemaSlug,
|
|
dbName: 'customs',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'localizedText',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
{
|
|
name: 'relationship',
|
|
type: 'relationship',
|
|
hasMany: true,
|
|
relationTo: 'relation-a',
|
|
},
|
|
{
|
|
name: 'select',
|
|
type: 'select',
|
|
dbName: ({ tableName }) => `${tableName}_customSelect`,
|
|
enumName: 'selectEnum',
|
|
hasMany: true,
|
|
options: ['a', 'b', 'c'],
|
|
},
|
|
{
|
|
name: 'radio',
|
|
type: 'select',
|
|
enumName: 'radioEnum',
|
|
options: ['a', 'b', 'c'],
|
|
},
|
|
{
|
|
name: 'array',
|
|
type: 'array',
|
|
dbName: 'customArrays',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'localizedText',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'blocks',
|
|
type: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'block-second',
|
|
dbName: 'customBlocks',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'localizedText',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
versions: {
|
|
drafts: true,
|
|
},
|
|
},
|
|
{
|
|
slug: placesSlug,
|
|
fields: [
|
|
{
|
|
name: 'country',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'city',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'virtual-relations',
|
|
admin: { useAsTitle: 'postTitle' },
|
|
access: { read: () => true },
|
|
fields: [
|
|
{
|
|
name: 'postTitle',
|
|
type: 'text',
|
|
virtual: 'post.title',
|
|
},
|
|
{
|
|
name: 'postTitleHidden',
|
|
type: 'text',
|
|
virtual: 'post.title',
|
|
hidden: true,
|
|
},
|
|
{
|
|
name: 'postCategoryTitle',
|
|
type: 'text',
|
|
virtual: 'post.category.title',
|
|
},
|
|
{
|
|
name: 'postCategoryID',
|
|
type: 'json',
|
|
virtual: 'post.category.id',
|
|
},
|
|
{
|
|
name: 'postCategoryCustomID',
|
|
type: 'number',
|
|
virtual: 'post.categoryCustomID.id',
|
|
},
|
|
{
|
|
name: 'postID',
|
|
type: 'json',
|
|
virtual: 'post.id',
|
|
},
|
|
{
|
|
name: 'postLocalized',
|
|
type: 'text',
|
|
virtual: 'post.localized',
|
|
},
|
|
{
|
|
name: 'post',
|
|
type: 'relationship',
|
|
relationTo: 'posts',
|
|
},
|
|
{
|
|
name: 'customID',
|
|
type: 'relationship',
|
|
relationTo: 'custom-ids',
|
|
},
|
|
{
|
|
name: 'customIDValue',
|
|
type: 'text',
|
|
virtual: 'customID.id',
|
|
},
|
|
],
|
|
versions: { drafts: true },
|
|
},
|
|
{
|
|
slug: fieldsPersistanceSlug,
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
virtual: true,
|
|
},
|
|
{
|
|
name: 'textHooked',
|
|
type: 'text',
|
|
virtual: true,
|
|
hooks: { afterRead: [() => 'hooked'] },
|
|
},
|
|
{
|
|
name: 'array',
|
|
type: 'array',
|
|
virtual: true,
|
|
fields: [],
|
|
},
|
|
{
|
|
type: 'row',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'textWithinRow',
|
|
virtual: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'collapsible',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'textWithinCollapsible',
|
|
virtual: true,
|
|
},
|
|
],
|
|
label: 'Colllapsible',
|
|
},
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
label: 'tab',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'textWithinTabs',
|
|
virtual: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: customIDsSlug,
|
|
fields: [
|
|
{
|
|
name: 'id',
|
|
type: 'text',
|
|
admin: {
|
|
readOnly: true,
|
|
},
|
|
hooks: {
|
|
beforeChange: [
|
|
({ value, operation }) => {
|
|
if (operation === 'create') {
|
|
return randomUUID()
|
|
}
|
|
return value
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
],
|
|
versions: { drafts: true },
|
|
},
|
|
{
|
|
slug: fakeCustomIDsSlug,
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'group',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
name: 'id',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: 'tabs',
|
|
tabs: [
|
|
{
|
|
name: 'myTab',
|
|
fields: [
|
|
{
|
|
name: 'id',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: relationshipsMigrationSlug,
|
|
fields: [
|
|
{
|
|
type: 'relationship',
|
|
relationTo: 'default-values',
|
|
name: 'relationship',
|
|
},
|
|
{
|
|
type: 'relationship',
|
|
relationTo: ['default-values'],
|
|
name: 'relationship_2',
|
|
},
|
|
],
|
|
versions: true,
|
|
},
|
|
{
|
|
slug: 'compound-indexes',
|
|
fields: [
|
|
{
|
|
name: 'one',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'two',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'three',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'group',
|
|
type: 'group',
|
|
fields: [
|
|
{
|
|
name: 'four',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
indexes: [
|
|
{
|
|
fields: ['one', 'two'],
|
|
unique: true,
|
|
},
|
|
{
|
|
fields: ['three', 'group.four'],
|
|
unique: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'aliases',
|
|
fields: [
|
|
{
|
|
name: 'thisIsALongFieldNameThatCanCauseAPostgresErrorEvenThoughWeSetAShorterDBName',
|
|
dbName: 'shortname',
|
|
type: 'array',
|
|
fields: [
|
|
{
|
|
name: 'nestedArray',
|
|
type: 'array',
|
|
dbName: 'short_nested_1',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'blocks-docs',
|
|
fields: [
|
|
{
|
|
type: 'blocks',
|
|
localized: true,
|
|
blocks: [
|
|
{
|
|
slug: 'cta',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
name: 'testBlocksLocalized',
|
|
},
|
|
{
|
|
type: 'blocks',
|
|
blocks: [
|
|
{
|
|
slug: 'cta',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
name: 'testBlocks',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'unique-fields',
|
|
fields: [
|
|
{
|
|
name: 'slugField',
|
|
type: 'text',
|
|
unique: true,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
globals: [
|
|
{
|
|
slug: 'header',
|
|
fields: [
|
|
{
|
|
name: 'itemsLvl1',
|
|
type: 'array',
|
|
dbName: 'header_items_lvl1',
|
|
fields: [
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'itemsLvl2',
|
|
type: 'array',
|
|
dbName: 'header_items_lvl2',
|
|
fields: [
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'itemsLvl3',
|
|
type: 'array',
|
|
dbName: 'header_items_lvl3',
|
|
fields: [
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'itemsLvl4',
|
|
type: 'array',
|
|
dbName: 'header_items_lvl4',
|
|
fields: [
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'global',
|
|
dbName: 'customGlobal',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
],
|
|
versions: true,
|
|
},
|
|
{
|
|
slug: 'global-2',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'global-3',
|
|
fields: [
|
|
{
|
|
name: 'text',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: 'virtual-relation-global',
|
|
fields: [
|
|
{
|
|
type: 'text',
|
|
name: 'postTitle',
|
|
virtual: 'post.title',
|
|
},
|
|
{
|
|
type: 'relationship',
|
|
name: 'post',
|
|
relationTo: 'posts',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
localization: {
|
|
defaultLocale: 'en',
|
|
locales: ['en', 'es'],
|
|
},
|
|
onInit: async (payload) => {
|
|
if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') {
|
|
await seed(payload)
|
|
}
|
|
},
|
|
typescript: {
|
|
outputFile: path.resolve(dirname, 'payload-types.ts'),
|
|
},
|
|
})
|