feat(db-*): add defaultValues to database schemas (#7368)
## Description Prior to this change, the `defaultValue` for fields have only been used in the application layer of Payload. With this change, you get the added benefit of having the database columns get the default also. This is especially helpful when adding new columns to postgres with existing data to avoid needing to write complex migrations. In MongoDB this change applies the default to the Mongoose model which is useful when calling payload.db.create() directly. This only works for statically defined values. 🙏 A big thanks to @r1tsuu for the feature and implementation idea as I lifted some code from PR https://github.com/payloadcms/payload/pull/6983 - [x] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository. ## Type of change - [x] New feature (non-breaking change which adds functionality) - [x] This change requires a documentation update ## Checklist: - [x] I have added tests that prove my fix is effective or that my feature works - [x] Existing test suite passes locally with my changes - [x] I have made corresponding changes to the documentation
This commit is contained in:
@@ -205,7 +205,9 @@ export const MyField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
Default values can be defined as a static string or a function that returns a string. Functions are called with the following arguments:
|
||||
Default values can be defined as a static value or a function that returns a value. When a `defaultValue` is defined statically, Payload's DB adapters will apply it to the database schema or models.
|
||||
|
||||
Functions can be written to make use of the following argument properties:
|
||||
|
||||
- `user` - the authenticated user object
|
||||
- `locale` - the currently selected locale string
|
||||
|
||||
@@ -52,9 +52,19 @@ type FieldSchemaGenerator = (
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
) => void
|
||||
|
||||
/**
|
||||
* get a field's defaultValue only if defined and not dynamic so that it can be set on the field schema
|
||||
* @param field
|
||||
*/
|
||||
const formatDefaultValue = (field: FieldAffectingData) =>
|
||||
typeof field.defaultValue !== 'undefined' && typeof field.defaultValue !== 'function'
|
||||
? field.defaultValue
|
||||
: undefined
|
||||
|
||||
const formatBaseSchema = (field: FieldAffectingData, buildSchemaOptions: BuildSchemaOptions) => {
|
||||
const { disableUnique, draftsEnabled, indexSortableFields } = buildSchemaOptions
|
||||
const schema: SchemaTypeOptions<unknown> = {
|
||||
default: formatDefaultValue(field),
|
||||
index: field.index || (!disableUnique && field.unique) || indexSortableFields || false,
|
||||
required: false,
|
||||
unique: (!disableUnique && field.unique) || false,
|
||||
@@ -159,7 +169,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
},
|
||||
}),
|
||||
],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
schema.add({
|
||||
@@ -174,7 +183,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
): void => {
|
||||
const fieldSchema = {
|
||||
type: [new mongoose.Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
schema.add({
|
||||
@@ -339,7 +347,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
},
|
||||
coordinates: {
|
||||
type: [Number],
|
||||
default: field.defaultValue || undefined,
|
||||
default: formatDefaultValue(field),
|
||||
required: false,
|
||||
},
|
||||
}
|
||||
@@ -420,7 +428,9 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
|
||||
return {
|
||||
...locales,
|
||||
[locale]: field.hasMany ? { type: [localeSchema], default: undefined } : localeSchema,
|
||||
[locale]: field.hasMany
|
||||
? { type: [localeSchema], default: formatDefaultValue(field) }
|
||||
: localeSchema,
|
||||
}
|
||||
}, {}),
|
||||
localized: true,
|
||||
@@ -440,7 +450,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
if (field.hasMany) {
|
||||
schemaToReturn = {
|
||||
type: [schemaToReturn],
|
||||
default: undefined,
|
||||
default: formatDefaultValue(field),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -453,7 +463,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
if (field.hasMany) {
|
||||
schemaToReturn = {
|
||||
type: [schemaToReturn],
|
||||
default: undefined,
|
||||
default: formatDefaultValue(field),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type {
|
||||
ForeignKeyBuilder,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, PgColumnBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { Field, TabAsField } from 'payload'
|
||||
@@ -35,6 +34,7 @@ import { buildTable } from './build.js'
|
||||
import { createIndex } from './createIndex.js'
|
||||
import { idToUUID } from './idToUUID.js'
|
||||
import { parentIDColumnMap } from './parentIDColumnMap.js'
|
||||
import { withDefault } from './withDefault.js'
|
||||
|
||||
type Args = {
|
||||
adapter: PostgresAdapter
|
||||
@@ -170,14 +170,14 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = varchar(columnName)
|
||||
targetTable[fieldName] = withDefault(varchar(columnName), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'email':
|
||||
case 'code':
|
||||
case 'textarea': {
|
||||
targetTable[fieldName] = varchar(columnName)
|
||||
targetTable[fieldName] = withDefault(varchar(columnName), field)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -199,23 +199,26 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = numeric(columnName)
|
||||
targetTable[fieldName] = withDefault(numeric(columnName), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
targetTable[fieldName] = jsonb(columnName)
|
||||
targetTable[fieldName] = withDefault(jsonb(columnName), field)
|
||||
break
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
targetTable[fieldName] = timestamp(columnName, {
|
||||
mode: 'string',
|
||||
precision: 3,
|
||||
withTimezone: true,
|
||||
})
|
||||
targetTable[fieldName] = withDefault(
|
||||
timestamp(columnName, {
|
||||
mode: 'string',
|
||||
precision: 3,
|
||||
withTimezone: true,
|
||||
}),
|
||||
field,
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -311,13 +314,13 @@ export const traverseFields = ({
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
targetTable[fieldName] = adapter.enums[enumName](fieldName)
|
||||
targetTable[fieldName] = withDefault(adapter.enums[enumName](fieldName), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
targetTable[fieldName] = boolean(columnName)
|
||||
targetTable[fieldName] = withDefault(boolean(columnName), field)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
17
packages/db-postgres/src/schema/withDefault.ts
Normal file
17
packages/db-postgres/src/schema/withDefault.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { PgColumnBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { FieldAffectingData } from 'payload'
|
||||
|
||||
export const withDefault = (
|
||||
column: PgColumnBuilder,
|
||||
field: FieldAffectingData,
|
||||
): PgColumnBuilder => {
|
||||
if (typeof field.defaultValue === 'undefined' || typeof field.defaultValue === 'function')
|
||||
return column
|
||||
|
||||
if (typeof field.defaultValue === 'string' && field.defaultValue.includes("'")) {
|
||||
const escapedString = field.defaultValue.replaceAll("'", "''")
|
||||
return column.default(escapedString)
|
||||
}
|
||||
|
||||
return column.default(field.defaultValue)
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, SQLiteColumnBuilder } from 'drizzle-orm/sqlite-core'
|
||||
import type { Field, TabAsField } from 'payload'
|
||||
@@ -30,6 +29,7 @@ import { buildTable } from './build.js'
|
||||
import { createIndex } from './createIndex.js'
|
||||
import { getIDColumn } from './getIDColumn.js'
|
||||
import { idToUUID } from './idToUUID.js'
|
||||
import { withDefault } from './withDefault.js'
|
||||
|
||||
type Args = {
|
||||
adapter: SQLiteAdapter
|
||||
@@ -166,14 +166,14 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = text(columnName)
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'email':
|
||||
case 'code':
|
||||
case 'textarea': {
|
||||
targetTable[fieldName] = text(columnName)
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -195,19 +195,19 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = numeric(columnName)
|
||||
targetTable[fieldName] = withDefault(numeric(columnName), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
targetTable[fieldName] = text(columnName, { mode: 'json' })
|
||||
targetTable[fieldName] = withDefault(text(columnName, { mode: 'json' }), field)
|
||||
break
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
targetTable[fieldName] = text(columnName)
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -295,13 +295,13 @@ export const traverseFields = ({
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
targetTable[fieldName] = text(fieldName, { enum: options })
|
||||
targetTable[fieldName] = withDefault(text(fieldName, { enum: options }), field)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
targetTable[fieldName] = integer(columnName, { mode: 'boolean' })
|
||||
targetTable[fieldName] = withDefault(integer(columnName, { mode: 'boolean' }), field)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
17
packages/db-sqlite/src/schema/withDefault.ts
Normal file
17
packages/db-sqlite/src/schema/withDefault.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { SQLiteColumnBuilder } from 'drizzle-orm/sqlite-core'
|
||||
import type { FieldAffectingData } from 'payload'
|
||||
|
||||
export const withDefault = (
|
||||
column: SQLiteColumnBuilder,
|
||||
field: FieldAffectingData,
|
||||
): SQLiteColumnBuilder => {
|
||||
if (typeof field.defaultValue === 'undefined' || typeof field.defaultValue === 'function')
|
||||
return column
|
||||
|
||||
if (typeof field.defaultValue === 'string' && field.defaultValue.includes("'")) {
|
||||
const escapedString = field.defaultValue.replaceAll("'", "''")
|
||||
return column.default(escapedString)
|
||||
}
|
||||
|
||||
return column.default(field.defaultValue)
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { Count } from 'payload'
|
||||
import type { SanitizedCollectionConfig } from 'payload'
|
||||
import type { Count , SanitizedCollectionConfig } from 'payload'
|
||||
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
@@ -15,7 +14,7 @@ export const count: Count = async function count(
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collectionConfig.slug))
|
||||
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
|
||||
const { joins, where } = await buildQuery({
|
||||
adapter: this,
|
||||
|
||||
@@ -10,7 +10,7 @@ export const create: Create = async function create(
|
||||
this: DrizzleAdapter,
|
||||
{ collection: collectionSlug, data, req },
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function createGlobal<T extends Record<string, unknown>>(
|
||||
this: DrizzleAdapter,
|
||||
{ slug, data, req = {} as PayloadRequest }: CreateGlobalArgs,
|
||||
): Promise<T> {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const globalConfig = this.payload.globals.config.find((config) => config.slug === slug)
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(globalConfig.slug))
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function createGlobalVersion<T extends TypeWithID>(
|
||||
this: DrizzleAdapter,
|
||||
{ autosave, globalSlug, req = {} as PayloadRequest, versionData }: CreateGlobalVersionArgs,
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const global = this.payload.globals.config.find(({ slug }) => slug === globalSlug)
|
||||
|
||||
const tableName = this.tableNameMap.get(`_${toSnakeCase(global.slug)}${this.versionsSuffix}`)
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function createVersion<T extends TypeWithID>(
|
||||
versionData,
|
||||
}: CreateVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
const defaultTableName = toSnakeCase(collection.slug)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export const deleteMany: DeleteMany = async function deleteMany(
|
||||
this: DrizzleAdapter,
|
||||
{ collection, req = {} as PayloadRequest, where },
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collectionConfig = this.payload.collections[collection].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collectionConfig.slug))
|
||||
|
||||
@@ -14,7 +14,7 @@ export const deleteOne: DeleteOne = async function deleteOne(
|
||||
this: DrizzleAdapter,
|
||||
{ collection: collectionSlug, req = {} as PayloadRequest, where: whereArg },
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
|
||||
@@ -12,7 +12,7 @@ export const deleteVersions: DeleteVersions = async function deleteVersion(
|
||||
this: DrizzleAdapter,
|
||||
{ collection, locale, req = {} as PayloadRequest, where: where },
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||
|
||||
const tableName = this.tableNameMap.get(
|
||||
|
||||
@@ -12,7 +12,7 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
this: DrizzleAdapter,
|
||||
{ id, collection: collectionSlug, data, draft, locale, req, where: whereArg },
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
const whereToUse = whereArg || { id: { equals: id } }
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function updateGlobal<T extends Record<string, unknown>>(
|
||||
this: DrizzleAdapter,
|
||||
{ slug, data, req = {} as PayloadRequest }: UpdateGlobalArgs,
|
||||
): Promise<T> {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const globalConfig = this.payload.globals.config.find((config) => config.slug === slug)
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(globalConfig.slug))
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function updateGlobalVersion<T extends TypeWithID>(
|
||||
where: whereArg,
|
||||
}: UpdateGlobalVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const globalConfig: SanitizedGlobalConfig = this.payload.globals.config.find(
|
||||
({ slug }) => slug === global,
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function updateVersion<T extends TypeWithID>(
|
||||
where: whereArg,
|
||||
}: UpdateVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||
const whereToUse = whereArg || { id: { equals: id } }
|
||||
const tableName = this.tableNameMap.get(
|
||||
|
||||
@@ -2,9 +2,17 @@ import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
import type { TextField } from 'payload'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
|
||||
const defaultValueField: TextField = {
|
||||
name: 'defaultValue',
|
||||
type: 'text',
|
||||
defaultValue: 'default value from database',
|
||||
}
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
{
|
||||
@@ -46,6 +54,40 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'default-values',
|
||||
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' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'relation-a',
|
||||
fields: [
|
||||
|
||||
@@ -89,11 +89,10 @@ describe('database', () => {
|
||||
})
|
||||
|
||||
it('should allow createdAt to be set in create', async () => {
|
||||
const createdAt = new Date('2021-01-01T00:00:00.000Z')
|
||||
const createdAt = new Date('2021-01-01T00:00:00.000Z').toISOString()
|
||||
const result = await payload.create({
|
||||
collection: 'posts',
|
||||
data: {
|
||||
// TODO: createdAt should be optional on RequiredDataFromCollectionSlug
|
||||
createdAt,
|
||||
title: 'hello',
|
||||
},
|
||||
@@ -104,8 +103,8 @@ describe('database', () => {
|
||||
collection: 'posts',
|
||||
})
|
||||
|
||||
expect(result.createdAt).toStrictEqual(createdAt.toISOString())
|
||||
expect(doc.createdAt).toStrictEqual(createdAt.toISOString())
|
||||
expect(result.createdAt).toStrictEqual(createdAt)
|
||||
expect(doc.createdAt).toStrictEqual(createdAt)
|
||||
})
|
||||
|
||||
it('updatedAt cannot be set in create', async () => {
|
||||
@@ -461,4 +460,24 @@ describe('database', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('defaultValue', () => {
|
||||
it('should set default value from db.create', async () => {
|
||||
// call the db adapter create directly to bypass Payload's default value assignment
|
||||
const result = await payload.db.create({
|
||||
collection: 'default-values',
|
||||
data: {
|
||||
// for drizzle DBs, we need to pass an array of objects to test subfields
|
||||
array: [{ id: 1 }],
|
||||
title: 'hello',
|
||||
},
|
||||
req: undefined,
|
||||
})
|
||||
|
||||
expect(result.defaultValue).toStrictEqual('default value from database')
|
||||
expect(result.array[0].defaultValue).toStrictEqual('default value from database')
|
||||
expect(result.group.defaultValue).toStrictEqual('default value from database')
|
||||
expect(result.select).toStrictEqual('default')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -76,17 +76,26 @@ describe('fields', () => {
|
||||
// TODO - This test is flaky. Rarely, but sometimes it randomly fails.
|
||||
test('should display unique constraint error in ui', async () => {
|
||||
const uniqueText = 'uniqueText'
|
||||
await payload.create({
|
||||
const doc = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data: {
|
||||
group: {
|
||||
unique: uniqueText,
|
||||
},
|
||||
localizedUniqueRequiredText: 'text',
|
||||
text: 'text',
|
||||
uniqueRequiredText: 'text',
|
||||
uniqueText,
|
||||
},
|
||||
})
|
||||
await payload.update({
|
||||
id: doc.id,
|
||||
collection: 'indexed-fields',
|
||||
data: {
|
||||
localizedUniqueRequiredText: 'es text',
|
||||
},
|
||||
locale: 'es',
|
||||
})
|
||||
|
||||
await page.goto(url.create)
|
||||
await page.waitForURL(url.create)
|
||||
|
||||
@@ -700,10 +700,19 @@ describe('Fields', () => {
|
||||
uniqueRequiredText: 'a',
|
||||
// uniqueText omitted on purpose
|
||||
}
|
||||
await payload.create({
|
||||
const doc = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
data,
|
||||
})
|
||||
// Update spanish so we do not run into the unique constraint for other locales
|
||||
await payload.update({
|
||||
id: doc.id,
|
||||
collection: 'indexed-fields',
|
||||
data: {
|
||||
localizedUniqueRequiredText: 'es1',
|
||||
},
|
||||
locale: 'es',
|
||||
})
|
||||
data.uniqueRequiredText = 'b'
|
||||
const result = await payload.create({
|
||||
collection: 'indexed-fields',
|
||||
|
||||
@@ -137,7 +137,7 @@ const link: LinkType = ({ appearances, disableLabel = false, overrides = {} } =
|
||||
linkResult.fields.push({
|
||||
name: 'appearance',
|
||||
type: 'select',
|
||||
defaultValue: 'default',
|
||||
defaultValue: appearanceOptionsToUse[0].value,
|
||||
options: appearanceOptionsToUse,
|
||||
admin: {
|
||||
description: 'Choose how the link should be rendered.',
|
||||
|
||||
Reference in New Issue
Block a user