fix(drizzle)!: localized fields uniqueness per locale (#8230)
Previously, this worked with MongoDB but failed with Postgres / SQLite
when the `slug` field has both `localized: true` and `unique: true`.
```ts
await payload.create({
collection: "posts",
locale: "en",
data: {
slug: "my-post"
}
})
await payload.create({
collection: "posts",
locale: "de",
data: {
slug: "my-post"
}
})
```
Now, we build unique constraints and indexes in combination with the
_locale column. This should also improve query performance for fields
with both index: true and localized: true.
### Migration steps (Postgres/SQLite only)
This change updates the database schema and requires a migration (if you
have any localized fields). To apply it, run the following commands:
```sh
pnpm payload migration:create locale_unique_indexes
pnpm payload migrate
```
Note that if you use `db.push: true` which is a default, you don't have
to run `pnpm payload migrate` in the development mode, only in the
production, as Payload automatically pushes the schema to your DB with
it.
This commit is contained in:
@@ -153,7 +153,7 @@ export const traverseFields = ({
|
||||
adapter.fieldConstraints[rootTableName][`${columnName}_idx`] = constraintValue
|
||||
}
|
||||
targetIndexes[`${newTableName}_${field.name}Idx`] = createIndex({
|
||||
name: fieldName,
|
||||
name: field.localized ? [fieldName, '_locale'] : fieldName,
|
||||
columnName,
|
||||
tableName: newTableName,
|
||||
unique,
|
||||
|
||||
@@ -159,7 +159,7 @@ export const traverseFields = ({
|
||||
adapter.fieldConstraints[rootTableName][`${columnName}_idx`] = constraintValue
|
||||
}
|
||||
targetIndexes[`${newTableName}_${field.name}Idx`] = createIndex({
|
||||
name: fieldName,
|
||||
name: field.localized ? [fieldName, '_locale'] : fieldName,
|
||||
columnName,
|
||||
tableName: newTableName,
|
||||
unique,
|
||||
|
||||
@@ -111,6 +111,12 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
{
|
||||
name: 'unique',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
unique: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
ArrayCollection,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Payload, Where } from 'payload'
|
||||
|
||||
import path from 'path'
|
||||
import { type Payload, type Where } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { NextRESTClient } from '../helpers/NextRESTClient.js'
|
||||
@@ -1954,6 +1953,44 @@ describe('Localization', () => {
|
||||
expect(retrieved.array.es[0].text).toEqual(['hola', 'adios'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('localized with unique', () => {
|
||||
it('localized with unique should work for each locale', async () => {
|
||||
await payload.create({
|
||||
collection: 'localized-posts',
|
||||
locale: 'ar',
|
||||
data: {
|
||||
unique: 'text',
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'localized-posts',
|
||||
locale: 'en',
|
||||
data: {
|
||||
unique: 'text',
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'localized-posts',
|
||||
locale: 'es',
|
||||
data: {
|
||||
unique: 'text',
|
||||
},
|
||||
})
|
||||
|
||||
await expect(
|
||||
payload.create({
|
||||
collection: 'localized-posts',
|
||||
locale: 'en',
|
||||
data: {
|
||||
unique: 'text',
|
||||
},
|
||||
}),
|
||||
).rejects.toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function createLocalizedPost(data: {
|
||||
|
||||
@@ -137,6 +137,7 @@ export interface LocalizedPost {
|
||||
group?: {
|
||||
children?: string | null;
|
||||
};
|
||||
unique?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user