chore: removes indexes from collection config (#3476)
This commit is contained in:
@@ -6,17 +6,17 @@ desc: Structure your Collections for your needs by defining fields, adding slugs
|
|||||||
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||||
---
|
---
|
||||||
|
|
||||||
Payload Collections are defined through configs of their own, and you can define as many as your application needs. Each Collection will scaffold a new collection automatically in your database of choice, based on fields that you define.
|
Payload Collections are defined through configs of their own, and you can define as many as your application needs. Each
|
||||||
|
Collection will scaffold a new collection automatically in your database of choice, based on fields that you define.
|
||||||
|
|
||||||
It's often best practice to write your Collections in separate files and then import them into the main Payload config.
|
It's often best practice to write your Collections in separate files and then import them into the main Payload config.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||||
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||||
| **`indexes`** \* | Array of database indexes to create, including compound indexes that have multiple fields. |
|
|
||||||
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
|
||||||
| **`hooks`** | Entry points to "tie in" to Collection actions at specific points. [More](/docs/hooks/overview#collection-hooks) |
|
| **`hooks`** | Entry points to "tie in" to Collection actions at specific points. [More](/docs/hooks/overview#collection-hooks) |
|
||||||
@@ -59,14 +59,17 @@ export const Orders: CollectionConfig = {
|
|||||||
|
|
||||||
#### More collection config examples
|
#### More collection config examples
|
||||||
|
|
||||||
You can find an assortment of [example collection configs](https://github.com/payloadcms/public-demo/tree/master/src/collections) in the Public Demo source code on GitHub.
|
You can find an assortment
|
||||||
|
of [example collection configs](https://github.com/payloadcms/public-demo/tree/master/src/collections) in the Public
|
||||||
|
Demo source code on GitHub.
|
||||||
|
|
||||||
### Admin options
|
### Admin options
|
||||||
|
|
||||||
You can customize the way that the Admin panel behaves on a collection-by-collection basis by defining the `admin` property on a collection's config.
|
You can customize the way that the Admin panel behaves on a collection-by-collection basis by defining the `admin`
|
||||||
|
property on a collection's config.
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
||||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. |
|
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. |
|
||||||
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
|
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
|
||||||
@@ -84,9 +87,11 @@ You can customize the way that the Admin panel behaves on a collection-by-collec
|
|||||||
|
|
||||||
### Preview
|
### Preview
|
||||||
|
|
||||||
Collection `admin` options can accept a `preview` function that will be used to generate a link pointing to the frontend of your app to preview data.
|
Collection `admin` options can accept a `preview` function that will be used to generate a link pointing to the frontend
|
||||||
|
of your app to preview data.
|
||||||
|
|
||||||
If the function is specified, a Preview button will automatically appear in the corresponding collection's Edit view. Clicking the Preview button will link to the URL that is generated by the function.
|
If the function is specified, a Preview button will automatically appear in the corresponding collection's Edit view.
|
||||||
|
Clicking the Preview button will link to the URL that is generated by the function.
|
||||||
|
|
||||||
**The preview function accepts two arguments:**
|
**The preview function accepts two arguments:**
|
||||||
|
|
||||||
@@ -124,27 +129,36 @@ export const Posts: CollectionConfig = {
|
|||||||
Here are a few options that you can specify options for pagination on a collection-by-collection basis:
|
Here are a few options that you can specify options for pagination on a collection-by-collection basis:
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| -------------- | --------------------------------------------------------------------------------------------------- |
|
|----------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
||||||
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. |
|
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. |
|
||||||
|
|
||||||
### Access control
|
### Access control
|
||||||
|
|
||||||
You can specify extremely granular access control (what users can do with documents in a collection) on a collection by collection basis. To learn more, go to the [Access Control](/docs/access-control/overview) docs.
|
You can specify extremely granular access control (what users can do with documents in a collection) on a collection by
|
||||||
|
collection basis. To learn more, go to the [Access Control](/docs/access-control/overview) docs.
|
||||||
|
|
||||||
### Hooks
|
### Hooks
|
||||||
|
|
||||||
Hooks are a powerful way to extend collection functionality and execute your own logic, and can be defined on a collection by collection basis. To learn more, go to the [Hooks](/docs/hooks/overview) documentation.
|
Hooks are a powerful way to extend collection functionality and execute your own logic, and can be defined on a
|
||||||
|
collection by collection basis. To learn more, go to the [Hooks](/docs/hooks/overview) documentation.
|
||||||
|
|
||||||
### Field types
|
### Field types
|
||||||
|
|
||||||
Collections support all field types that Payload has to offer—including simple fields like text and checkboxes all the way to more complicated layout-building field groups like Blocks. [Click here](/docs/fields/overview) to learn more about field types.
|
Collections support all field types that Payload has to offer—including simple fields like text and checkboxes all the
|
||||||
|
way to more complicated layout-building field groups like Blocks. [Click here](/docs/fields/overview) to learn more
|
||||||
|
about field types.
|
||||||
|
|
||||||
### List Searchable Fields
|
### List Searchable Fields
|
||||||
|
|
||||||
In the List view, there is a "search" box that allows you to quickly find a document with a search. By default, it searches on the ID field. If you have `admin.useAsTitle` defined, the list search will use that field. However, you can define more than one field to search to make it easier on your admin editors to find the data they need.
|
In the List view, there is a "search" box that allows you to quickly find a document with a search. By default, it
|
||||||
|
searches on the ID field. If you have `admin.useAsTitle` defined, the list search will use that field. However, you can
|
||||||
|
define more than one field to search to make it easier on your admin editors to find the data they need.
|
||||||
|
|
||||||
For example, let's say you have a Posts collection with `title`, `metaDescription`, and `tags` fields - and you want all three of those fields to be searchable in the List view. You can simply add `admin.listSearchableFields: ['title', 'metaDescription', 'tags']` - and the admin UI will automatically search on those three fields plus the ID field.
|
For example, let's say you have a Posts collection with `title`, `metaDescription`, and `tags` fields - and you want all
|
||||||
|
three of those fields to be searchable in the List view. You can simply
|
||||||
|
add `admin.listSearchableFields: ['title', 'metaDescription', 'tags']` - and the admin UI will automatically search on
|
||||||
|
those three fields plus the ID field.
|
||||||
|
|
||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
<strong>Note:</strong>
|
<strong>Note:</strong>
|
||||||
@@ -159,7 +173,10 @@ In addition to collection hooks themselves, Payload provides for admin UI-specif
|
|||||||
|
|
||||||
**`beforeDuplicate`**
|
**`beforeDuplicate`**
|
||||||
|
|
||||||
The `beforeDuplicate` hook is an async function that accepts an object containing the data to duplicate, as well as the locale of the doc to duplicate. Within this hook, you can modify the data to be duplicated, which is useful in cases where you have unique fields that need to be incremented or similar, as well as if you want to automatically modify a document's `title`.
|
The `beforeDuplicate` hook is an async function that accepts an object containing the data to duplicate, as well as the
|
||||||
|
locale of the doc to duplicate. Within this hook, you can modify the data to be duplicated, which is useful in cases
|
||||||
|
where you have unique fields that need to be incremented or similar, as well as if you want to automatically modify a
|
||||||
|
document's `title`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import type { SanitizedCollectionConfig } from 'payload/types'
|
|||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
import mongooseAggregatePaginate from 'mongoose-aggregate-paginate-v2'
|
import mongooseAggregatePaginate from 'mongoose-aggregate-paginate-v2'
|
||||||
import paginate from 'mongoose-paginate-v2'
|
import paginate from 'mongoose-paginate-v2'
|
||||||
import { buildVersionGlobalFields } from 'payload/versions'
|
import {
|
||||||
import { buildVersionCollectionFields } from 'payload/versions'
|
buildVersionCollectionFields,
|
||||||
import { getVersionsModelName } from 'payload/versions'
|
buildVersionGlobalFields,
|
||||||
|
getVersionsModelName,
|
||||||
|
} from 'payload/versions'
|
||||||
|
|
||||||
import type { MongooseAdapter } from '.'
|
import type { MongooseAdapter } from '.'
|
||||||
import type { CollectionModel } from './types'
|
import type { CollectionModel } from './types'
|
||||||
@@ -36,20 +38,6 @@ export const init: Init = async function init(this: MongooseAdapter) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (collection.indexes) {
|
|
||||||
collection.indexes.forEach((index) => {
|
|
||||||
// prefix 'version.' to each field in the index
|
|
||||||
const versionIndex = {
|
|
||||||
fields: {},
|
|
||||||
options: index.options,
|
|
||||||
}
|
|
||||||
Object.entries(index.fields).forEach(([key, value]) => {
|
|
||||||
versionIndex.fields[`version.${key}`] = value
|
|
||||||
})
|
|
||||||
versionSchema.index(versionIndex.fields, versionIndex.options)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
versionSchema.plugin<any, PaginateOptions>(paginate, { useEstimatedCount: true }).plugin(
|
versionSchema.plugin<any, PaginateOptions>(paginate, { useEstimatedCount: true }).plugin(
|
||||||
getBuildQueryPlugin({
|
getBuildQueryPlugin({
|
||||||
collectionSlug: collection.slug,
|
collectionSlug: collection.slug,
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ const buildCollectionSchema = (
|
|||||||
schema.index({ updatedAt: 1 })
|
schema.index({ updatedAt: 1 })
|
||||||
schema.index({ createdAt: 1 })
|
schema.index({ createdAt: 1 })
|
||||||
}
|
}
|
||||||
if (collection.indexes) {
|
|
||||||
collection.indexes.forEach((index) => {
|
|
||||||
schema.index(index.fields, index.options)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
schema
|
schema
|
||||||
.plugin<any, PaginateOptions>(paginate, { useEstimatedCount: true })
|
.plugin<any, PaginateOptions>(paginate, { useEstimatedCount: true })
|
||||||
.plugin(getBuildQueryPlugin({ collectionSlug: collection.slug }))
|
.plugin(getBuildQueryPlugin({ collectionSlug: collection.slug }))
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
|||||||
buildTable({
|
buildTable({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
buildRelationships: true,
|
buildRelationships: true,
|
||||||
collectionIndexes: collection.indexes,
|
|
||||||
disableUnique: false,
|
disableUnique: false,
|
||||||
fields: collection.fields,
|
fields: collection.fields,
|
||||||
tableName,
|
tableName,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import type { Relation } from 'drizzle-orm'
|
import type { Relation } from 'drizzle-orm'
|
||||||
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
||||||
import type { Field, SanitizedCollectionConfig } from 'payload/types'
|
import type { Field } from 'payload/types'
|
||||||
|
|
||||||
import { relations } from 'drizzle-orm'
|
import { relations } from 'drizzle-orm'
|
||||||
import {
|
import {
|
||||||
@@ -27,7 +27,6 @@ type Args = {
|
|||||||
baseColumns?: Record<string, PgColumnBuilder>
|
baseColumns?: Record<string, PgColumnBuilder>
|
||||||
baseExtraConfig?: Record<string, (cols: GenericColumns) => IndexBuilder | UniqueConstraintBuilder>
|
baseExtraConfig?: Record<string, (cols: GenericColumns) => IndexBuilder | UniqueConstraintBuilder>
|
||||||
buildRelationships?: boolean
|
buildRelationships?: boolean
|
||||||
collectionIndexes?: SanitizedCollectionConfig['indexes']
|
|
||||||
disableUnique: boolean
|
disableUnique: boolean
|
||||||
fields: Field[]
|
fields: Field[]
|
||||||
rootRelationsToBuild?: Map<string, string>
|
rootRelationsToBuild?: Map<string, string>
|
||||||
@@ -46,7 +45,6 @@ export const buildTable = ({
|
|||||||
baseColumns = {},
|
baseColumns = {},
|
||||||
baseExtraConfig = {},
|
baseExtraConfig = {},
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes = [],
|
|
||||||
disableUnique = false,
|
disableUnique = false,
|
||||||
fields,
|
fields,
|
||||||
rootRelationsToBuild,
|
rootRelationsToBuild,
|
||||||
@@ -98,7 +96,6 @@ export const buildTable = ({
|
|||||||
} = traverseFields({
|
} = traverseFields({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columns,
|
columns,
|
||||||
disableUnique,
|
disableUnique,
|
||||||
fields,
|
fields,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import type { Relation } from 'drizzle-orm'
|
import type { Relation } from 'drizzle-orm'
|
||||||
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
|
||||||
import type { Field, SanitizedCollectionConfig, TabAsField } from 'payload/types'
|
import type { Field, TabAsField } from 'payload/types'
|
||||||
|
|
||||||
import { relations } from 'drizzle-orm'
|
import { relations } from 'drizzle-orm'
|
||||||
import {
|
import {
|
||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
pgEnum,
|
pgEnum,
|
||||||
text,
|
text,
|
||||||
timestamp,
|
timestamp,
|
||||||
unique,
|
|
||||||
varchar,
|
varchar,
|
||||||
} from 'drizzle-orm/pg-core'
|
} from 'drizzle-orm/pg-core'
|
||||||
import { InvalidConfiguration } from 'payload/errors'
|
import { InvalidConfiguration } from 'payload/errors'
|
||||||
@@ -33,7 +32,6 @@ import { validateExistingBlockIsIdentical } from './validateExistingBlockIsIdent
|
|||||||
type Args = {
|
type Args = {
|
||||||
adapter: PostgresAdapter
|
adapter: PostgresAdapter
|
||||||
buildRelationships: boolean
|
buildRelationships: boolean
|
||||||
collectionIndexes: SanitizedCollectionConfig['indexes']
|
|
||||||
columnPrefix?: string
|
columnPrefix?: string
|
||||||
columns: Record<string, PgColumnBuilder>
|
columns: Record<string, PgColumnBuilder>
|
||||||
disableUnique?: boolean
|
disableUnique?: boolean
|
||||||
@@ -62,7 +60,6 @@ type Result = {
|
|||||||
export const traverseFields = ({
|
export const traverseFields = ({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columnPrefix,
|
columnPrefix,
|
||||||
columns,
|
columns,
|
||||||
disableUnique = false,
|
disableUnique = false,
|
||||||
@@ -111,24 +108,6 @@ export const traverseFields = ({
|
|||||||
targetIndexes = localesIndexes
|
targetIndexes = localesIndexes
|
||||||
}
|
}
|
||||||
|
|
||||||
const collectionIndex = collectionIndexes
|
|
||||||
? collectionIndexes.findIndex((index) => {
|
|
||||||
return Object.keys(index.fields).some((indexField) => indexField === fieldName)
|
|
||||||
})
|
|
||||||
: -1
|
|
||||||
|
|
||||||
if (collectionIndex > -1) {
|
|
||||||
const name = toSnakeCase(
|
|
||||||
`${Object.keys(collectionIndexes[collectionIndex].fields).join('_')}`,
|
|
||||||
)
|
|
||||||
targetIndexes[`${name}Idx`] = createIndex({
|
|
||||||
name: Object.keys(collectionIndexes[collectionIndex].fields),
|
|
||||||
columnName: name,
|
|
||||||
unique: collectionIndexes[collectionIndex].options.unique,
|
|
||||||
})
|
|
||||||
collectionIndexes.splice(collectionIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(field.unique || field.index) &&
|
(field.unique || field.index) &&
|
||||||
!['array', 'blocks', 'group', 'point', 'relationship', 'upload'].includes(field.type) &&
|
!['array', 'blocks', 'group', 'point', 'relationship', 'upload'].includes(field.type) &&
|
||||||
@@ -416,7 +395,6 @@ export const traverseFields = ({
|
|||||||
} = traverseFields({
|
} = traverseFields({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columnPrefix,
|
columnPrefix,
|
||||||
columns,
|
columns,
|
||||||
disableUnique,
|
disableUnique,
|
||||||
@@ -450,7 +428,6 @@ export const traverseFields = ({
|
|||||||
} = traverseFields({
|
} = traverseFields({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columnPrefix: `${columnName}_`,
|
columnPrefix: `${columnName}_`,
|
||||||
columns,
|
columns,
|
||||||
disableUnique,
|
disableUnique,
|
||||||
@@ -485,7 +462,6 @@ export const traverseFields = ({
|
|||||||
} = traverseFields({
|
} = traverseFields({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columnPrefix,
|
columnPrefix,
|
||||||
columns,
|
columns,
|
||||||
disableUnique,
|
disableUnique,
|
||||||
@@ -522,7 +498,6 @@ export const traverseFields = ({
|
|||||||
} = traverseFields({
|
} = traverseFields({
|
||||||
adapter,
|
adapter,
|
||||||
buildRelationships,
|
buildRelationships,
|
||||||
collectionIndexes,
|
|
||||||
columnPrefix,
|
columnPrefix,
|
||||||
columns,
|
columns,
|
||||||
disableUnique,
|
disableUnique,
|
||||||
|
|||||||
@@ -353,10 +353,6 @@ export type CollectionConfig = {
|
|||||||
beforeRead?: BeforeReadHook[]
|
beforeRead?: BeforeReadHook[]
|
||||||
beforeValidate?: BeforeValidateHook[]
|
beforeValidate?: BeforeValidateHook[]
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Array of database indexes to create, including compound indexes that have multiple fields
|
|
||||||
*/
|
|
||||||
indexes?: TypeOfIndex[]
|
|
||||||
/**
|
/**
|
||||||
* Label configuration
|
* Label configuration
|
||||||
*/
|
*/
|
||||||
@@ -441,52 +437,3 @@ export type TypeWithTimestamps = {
|
|||||||
id: number | string
|
id: number | string
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type IndexDirection =
|
|
||||||
| '2d'
|
|
||||||
| '2dsphere'
|
|
||||||
| 'asc'
|
|
||||||
| 'ascending'
|
|
||||||
| 'desc'
|
|
||||||
| 'descending'
|
|
||||||
| 'geoHaystack'
|
|
||||||
| 'hashed'
|
|
||||||
| 'text'
|
|
||||||
| -1
|
|
||||||
| 1
|
|
||||||
|
|
||||||
type IndexOptions = {
|
|
||||||
'2dsphereIndexVersion'?: number
|
|
||||||
/** Creates the index in the background, yielding whenever possible. */
|
|
||||||
background?: boolean
|
|
||||||
bits?: number
|
|
||||||
bucketSize?: number
|
|
||||||
/** (MongoDB 4.4. or higher) Specifies how many data-bearing members of a replica set, including the primary, must complete the index builds successfully before the primary marks the indexes as ready. This option accepts the same values for the "w" field in a write concern plus "votingMembers", which indicates all voting data-bearing nodes. */
|
|
||||||
commitQuorum?: number | string
|
|
||||||
default_language?: string
|
|
||||||
/** Allows you to expire data on indexes applied to a data (MongoDB 2.2 or higher) */
|
|
||||||
expireAfterSeconds?: number
|
|
||||||
expires?: number | string
|
|
||||||
/** Specifies that the index should exist on the target collection but should not be used by the query planner when executing operations. (MongoDB 4.4 or higher) */
|
|
||||||
hidden?: boolean
|
|
||||||
language_override?: string
|
|
||||||
/** For geospatial indexes set the high bound for the co-ordinates. */
|
|
||||||
max?: number
|
|
||||||
/** For geospatial indexes set the lower bound for the co-ordinates. */
|
|
||||||
min?: number
|
|
||||||
/** Override the autogenerated index name (useful if the resulting name is larger than 128 bytes) */
|
|
||||||
name?: string
|
|
||||||
/** Creates a sparse index. */
|
|
||||||
sparse?: boolean
|
|
||||||
textIndexVersion?: number
|
|
||||||
/** Creates an unique index. */
|
|
||||||
unique?: boolean
|
|
||||||
/** Specifies the index version number, either 0 or 1. */
|
|
||||||
version?: number
|
|
||||||
weights?: Record<string, number>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TypeOfIndex = {
|
|
||||||
fields: Record<string, IndexDirection>
|
|
||||||
options?: IndexOptions
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -67,18 +67,6 @@ const getPreferencesCollection = (config: Config): CollectionConfig => ({
|
|||||||
type: 'json',
|
type: 'json',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: {
|
|
||||||
key: 1,
|
|
||||||
'user.relationTo': 1,
|
|
||||||
'user.value': 1,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
slug: 'payload-preferences',
|
slug: 'payload-preferences',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,24 +7,23 @@ import type { IndexedField } from '../../payload-types'
|
|||||||
const beforeDuplicate: BeforeDuplicate<IndexedField> = ({ data }) => {
|
const beforeDuplicate: BeforeDuplicate<IndexedField> = ({ data }) => {
|
||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
uniqueText: data.uniqueText ? `${data.uniqueText}-copy` : '',
|
collapsibleLocalizedUnique: data.collapsibleLocalizedUnique
|
||||||
|
? `${data.collapsibleLocalizedUnique}-copy`
|
||||||
|
: '',
|
||||||
|
collapsibleTextUnique: data.collapsibleTextUnique ? `${data.collapsibleTextUnique}-copy` : '',
|
||||||
group: {
|
group: {
|
||||||
...(data.group || {}),
|
...(data.group || {}),
|
||||||
localizedUnique: data.group?.localizedUnique ? `${data.group?.localizedUnique}-copy` : '',
|
localizedUnique: data.group?.localizedUnique ? `${data.group?.localizedUnique}-copy` : '',
|
||||||
},
|
},
|
||||||
collapsibleTextUnique: data.collapsibleTextUnique ? `${data.collapsibleTextUnique}-copy` : '',
|
|
||||||
collapsibleLocalizedUnique: data.collapsibleLocalizedUnique
|
|
||||||
? `${data.collapsibleLocalizedUnique}-copy`
|
|
||||||
: '',
|
|
||||||
partOne: data.partOne ? `${data.partOne}-copy` : '',
|
partOne: data.partOne ? `${data.partOne}-copy` : '',
|
||||||
partTwo: data.partTwo ? `${data.partTwo}-copy` : '',
|
partTwo: data.partTwo ? `${data.partTwo}-copy` : '',
|
||||||
|
uniqueText: data.uniqueText ? `${data.uniqueText}-copy` : '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const IndexedFields: CollectionConfig = {
|
const IndexedFields: CollectionConfig = {
|
||||||
slug: 'indexed-fields',
|
slug: 'indexed-fields',
|
||||||
// used to assert that versions also get indexes
|
// used to assert that versions also get indexes
|
||||||
versions: true,
|
|
||||||
admin: {
|
admin: {
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeDuplicate,
|
beforeDuplicate,
|
||||||
@@ -33,9 +32,9 @@ const IndexedFields: CollectionConfig = {
|
|||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'text',
|
name: 'text',
|
||||||
type: 'text',
|
|
||||||
required: true,
|
|
||||||
index: true,
|
index: true,
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'uniqueText',
|
name: 'uniqueText',
|
||||||
@@ -47,54 +46,41 @@ const IndexedFields: CollectionConfig = {
|
|||||||
type: 'point',
|
type: 'point',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'group',
|
|
||||||
name: 'group',
|
name: 'group',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'localizedUnique',
|
name: 'localizedUnique',
|
||||||
|
localized: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
unique: true,
|
unique: true,
|
||||||
localized: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'point',
|
name: 'point',
|
||||||
type: 'point',
|
type: 'point',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: 'group',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'collapsible',
|
|
||||||
label: 'Collapsible',
|
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'collapsibleLocalizedUnique',
|
name: 'collapsibleLocalizedUnique',
|
||||||
|
localized: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
unique: true,
|
unique: true,
|
||||||
localized: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'collapsibleTextUnique',
|
name: 'collapsibleTextUnique',
|
||||||
type: 'text',
|
|
||||||
label: 'collapsibleTextUnique',
|
label: 'collapsibleTextUnique',
|
||||||
|
type: 'text',
|
||||||
unique: true,
|
unique: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
label: 'Collapsible',
|
||||||
{
|
type: 'collapsible',
|
||||||
name: 'partOne',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'partTwo',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: { partOne: 1, partTwo: 1 },
|
|
||||||
options: { unique: true, name: 'compound-index', sparse: true },
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
versions: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IndexedFields
|
export default IndexedFields
|
||||||
|
|||||||
@@ -286,15 +286,6 @@ describe('Fields', () => {
|
|||||||
expect(options.uniqueText).toMatchObject({ unique: true })
|
expect(options.uniqueText).toMatchObject({ unique: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should have unique compound indexes', () => {
|
|
||||||
expect(definitions.partOne).toEqual(1)
|
|
||||||
expect(options.partOne).toMatchObject({
|
|
||||||
name: 'compound-index',
|
|
||||||
sparse: true,
|
|
||||||
unique: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have 2dsphere indexes on point fields', () => {
|
it('should have 2dsphere indexes on point fields', () => {
|
||||||
expect(definitions.point).toEqual('2dsphere')
|
expect(definitions.point).toEqual('2dsphere')
|
||||||
})
|
})
|
||||||
@@ -342,14 +333,6 @@ describe('Fields', () => {
|
|||||||
it('should have versions indexes', () => {
|
it('should have versions indexes', () => {
|
||||||
expect(definitions['version.text']).toEqual(1)
|
expect(definitions['version.text']).toEqual(1)
|
||||||
})
|
})
|
||||||
it('should have version indexes from collection indexes', () => {
|
|
||||||
expect(definitions['version.partOne']).toEqual(1)
|
|
||||||
expect(options['version.partOne']).toMatchObject({
|
|
||||||
name: 'compound-index',
|
|
||||||
sparse: true,
|
|
||||||
unique: true,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('point', () => {
|
describe('point', () => {
|
||||||
@@ -440,32 +423,6 @@ describe('Fields', () => {
|
|||||||
return result.error
|
return result.error
|
||||||
}).toBeDefined()
|
}).toBeDefined()
|
||||||
})
|
})
|
||||||
it('should throw validation error saving on unique combined fields', async () => {
|
|
||||||
await payload.delete({ collection: 'indexed-fields', where: {} })
|
|
||||||
const data1 = {
|
|
||||||
partOne: 'u',
|
|
||||||
partTwo: 'u',
|
|
||||||
text: 'a',
|
|
||||||
uniqueText: 'a',
|
|
||||||
}
|
|
||||||
const data2 = {
|
|
||||||
partOne: 'u',
|
|
||||||
partTwo: 'u',
|
|
||||||
text: 'b',
|
|
||||||
uniqueText: 'b',
|
|
||||||
}
|
|
||||||
await payload.create({
|
|
||||||
collection: 'indexed-fields',
|
|
||||||
data: data1,
|
|
||||||
})
|
|
||||||
expect(async () => {
|
|
||||||
const result = await payload.create({
|
|
||||||
collection: 'indexed-fields',
|
|
||||||
data: data2,
|
|
||||||
})
|
|
||||||
return result.error
|
|
||||||
}).toBeDefined()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('array', () => {
|
describe('array', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user