feat: compound indexes (#11512)

### What?
This PR adds ability to define indexes on several fields for collections
(compound indexes).

Example:
```ts
{
  indexes: [{ unique: true, fields: ['title', 'group.name'] }]
}
```

### Why?
This can be used to either speed up querying/sorting by 2 or more fields
at the same time or to ensure uniqueness between several fields.

### How?
Implements this logic in database adapters. Additionally, adds a utility
`getFieldByPath`.
This commit is contained in:
Sasha
2025-03-05 03:09:24 +02:00
committed by GitHub
parent f01cfbcc57
commit bacc0f002a
18 changed files with 423 additions and 21 deletions

View File

@@ -57,9 +57,9 @@ export const Posts: CollectionConfig = {
The following options are available:
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
| Option | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| `custom` | Extension point for adding custom data (e.g. for plugins) |
@@ -67,17 +67,18 @@ The following options are available:
| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. |
| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| `fields` * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| `fields` * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) |
| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| `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. |
| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. |
_* An asterisk denotes that a property is required._

View File

@@ -3,7 +3,11 @@ import type { Init, SanitizedCollectionConfig } from 'payload'
import mongoose from 'mongoose'
import paginate from 'mongoose-paginate-v2'
import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'
import {
buildVersionCollectionFields,
buildVersionCompoundIndexes,
buildVersionGlobalFields,
} from 'payload'
import type { MongooseAdapter } from './index.js'
import type { CollectionModel, GlobalModel } from './types.js'
@@ -36,6 +40,7 @@ export const init: Init = function init(this: MongooseAdapter) {
},
...schemaOptions,
},
compoundIndexes: buildVersionCompoundIndexes({ indexes: collection.sanitizedIndexes }),
configFields: versionCollectionFields,
payload: this.payload,
})

View File

@@ -23,6 +23,7 @@ export const buildCollectionSchema = (
...schemaOptions,
},
},
compoundIndexes: collection.sanitizedIndexes,
configFields: collection.fields,
payload,
})

View File

@@ -2,7 +2,6 @@ import type { IndexOptions, Schema, SchemaOptions, SchemaTypeOptions } from 'mon
import mongoose from 'mongoose'
import {
APIError,
type ArrayField,
type BlocksField,
type CheckboxField,
@@ -22,6 +21,7 @@ import {
type RelationshipField,
type RichTextField,
type RowField,
type SanitizedCompoundIndex,
type SanitizedLocalizationConfig,
type SelectField,
type Tab,
@@ -128,6 +128,7 @@ const localizeSchema = (
export const buildSchema = (args: {
buildSchemaOptions: BuildSchemaOptions
compoundIndexes?: SanitizedCompoundIndex[]
configFields: Field[]
parentIsLocalized?: boolean
payload: Payload
@@ -166,6 +167,26 @@ export const buildSchema = (args: {
}
})
if (args.compoundIndexes) {
for (const index of args.compoundIndexes) {
const indexDefinition: Record<string, 1> = {}
for (const field of index.fields) {
if (field.pathHasLocalized && payload.config.localization) {
for (const locale of payload.config.localization.locales) {
indexDefinition[field.localizedPath.replace('<locale>', locale.code)] = 1
}
} else {
indexDefinition[field.path] = 1
}
}
schema.index(indexDefinition, {
unique: args.buildSchemaOptions.disableUnique ? false : index.unique,
})
}
}
return schema
}

View File

@@ -1,5 +1,6 @@
import type { FlattenedField } from 'payload'
import type { FlattenedField, SanitizedCompoundIndex } from 'payload'
import { InvalidConfiguration } from 'payload'
import toSnakeCase from 'to-snake-case'
import type {
@@ -33,6 +34,7 @@ type Args = {
baseIndexes?: Record<string, RawIndex>
buildNumbers?: boolean
buildRelationships?: boolean
compoundIndexes?: SanitizedCompoundIndex[]
disableNotNull: boolean
disableRelsTableUnique?: boolean
disableUnique: boolean
@@ -68,6 +70,7 @@ export const buildTable = ({
baseColumns = {},
baseForeignKeys = {},
baseIndexes = {},
compoundIndexes,
disableNotNull,
disableRelsTableUnique = false,
disableUnique = false,
@@ -268,6 +271,61 @@ export const buildTable = ({
adapter.rawRelations[localeTableName] = localeRelations
}
if (compoundIndexes) {
for (const index of compoundIndexes) {
let someLocalized: boolean | null = null
const columns: string[] = []
const getTableToUse = () => {
if (someLocalized) {
return localesTable
}
return table
}
for (const { path, pathHasLocalized } of index.fields) {
if (someLocalized === null) {
someLocalized = pathHasLocalized
}
if (someLocalized !== pathHasLocalized) {
throw new InvalidConfiguration(
`Compound indexes within localized and non localized fields are not supported in SQL. Expected ${path} to be ${someLocalized ? 'non' : ''} localized.`,
)
}
const columnPath = path.replaceAll('.', '_')
if (!getTableToUse().columns[columnPath]) {
throw new InvalidConfiguration(
`Column ${columnPath} for compound index on ${path} was not found in the ${getTableToUse().name} table.`,
)
}
columns.push(columnPath)
}
if (someLocalized) {
columns.push('_locale')
}
let name = columns.join('_')
// truncate against the limit, buildIndexName will handle collisions
if (name.length > 63) {
name = 'compound_index'
}
const indexName = buildIndexName({ name, adapter })
getTableToUse().indexes[indexName] = {
name: indexName,
on: columns,
unique: disableUnique ? false : index.unique,
}
}
}
if (isRoot) {
if (hasManyTextField) {
const textsTableName = `${rootTableName}_texts`

View File

@@ -1,4 +1,8 @@
import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'
import {
buildVersionCollectionFields,
buildVersionCompoundIndexes,
buildVersionGlobalFields,
} from 'payload'
import toSnakeCase from 'to-snake-case'
import type { DrizzleAdapter, RawIndex, SetColumnID } from '../types.js'
@@ -52,6 +56,7 @@ export const buildRawSchema = ({
buildTable({
adapter,
compoundIndexes: collection.sanitizedIndexes,
disableNotNull: !!collection?.versions?.drafts,
disableUnique: false,
fields: collection.flattenedFields,
@@ -70,6 +75,7 @@ export const buildRawSchema = ({
buildTable({
adapter,
compoundIndexes: buildVersionCompoundIndexes({ indexes: collection.sanitizedIndexes }),
disableNotNull: !!collection.versions?.drafts,
disableUnique: true,
fields: versionFields,

View File

@@ -1,4 +1,4 @@
import type { FlattenedField } from 'payload'
import type { CompoundIndex, FlattenedField } from 'payload'
import { InvalidConfiguration } from 'payload'
import {

View File

@@ -17,7 +17,15 @@ import { createClientFields } from '../../fields/config/client.js'
export type ServerOnlyCollectionProperties = keyof Pick<
SanitizedCollectionConfig,
'access' | 'custom' | 'endpoints' | 'flattenedFields' | 'hooks' | 'joins' | 'polymorphicJoins'
| 'access'
| 'custom'
| 'endpoints'
| 'flattenedFields'
| 'hooks'
| 'indexes'
| 'joins'
| 'polymorphicJoins'
| 'sanitizedIndexes'
>
export type ServerOnlyCollectionAdminProperties = keyof Pick<
@@ -70,6 +78,8 @@ const serverOnlyCollectionProperties: Partial<ServerOnlyCollectionProperties>[]
'joins',
'polymorphicJoins',
'flattenedFields',
'indexes',
'sanitizedIndexes',
// `upload`
// `admin`
// are all handled separately

View File

@@ -48,6 +48,7 @@ export const defaults: Partial<CollectionConfig> = {
me: [],
refresh: [],
},
indexes: [],
timestamps: true,
upload: false,
versions: false,

View File

@@ -2,6 +2,7 @@
import type { Config, SanitizedConfig } from '../../config/types.js'
import type {
CollectionConfig,
CompoundIndex,
SanitizedCollectionConfig,
SanitizedJoin,
SanitizedJoins,
@@ -26,6 +27,7 @@ import {
addDefaultsToLoginWithUsernameConfig,
} from './defaults.js'
import { sanitizeAuthFields, sanitizeUploadFields } from './reservedFieldNames.js'
import { sanitizeCompoundIndexes } from './sanitizeCompoundIndexes.js'
import { validateUseAsTitle } from './useAsTitle.js'
export const sanitizeCollection = async (
@@ -241,5 +243,10 @@ export const sanitizeCollection = async (
sanitizedConfig.flattenedFields = flattenAllFields({ fields: sanitizedConfig.fields })
sanitizedConfig.sanitizedIndexes = sanitizeCompoundIndexes({
fields: sanitizedConfig.flattenedFields,
indexes: sanitizedConfig.indexes,
})
return sanitizedConfig
}

View File

@@ -0,0 +1,40 @@
import type { FlattenedField } from '../../fields/config/types.js'
import type { CompoundIndex, SanitizedCompoundIndex } from './types.js'
import { InvalidConfiguration } from '../../errors/InvalidConfiguration.js'
import { getFieldByPath } from '../../utilities/getFieldByPath.js'
export const sanitizeCompoundIndexes = ({
fields,
indexes,
}: {
fields: FlattenedField[]
indexes: CompoundIndex[]
}): SanitizedCompoundIndex[] => {
const sanitizedCompoundIndexes: SanitizedCompoundIndex[] = []
for (const index of indexes) {
const sanitized: SanitizedCompoundIndex = { fields: [], unique: index.unique ?? false }
for (const path of index.fields) {
const result = getFieldByPath({ fields, path })
if (!result) {
throw new InvalidConfiguration(`Field ${path} was not found`)
}
const { field, localizedPath, pathHasLocalized } = result
if (['array', 'blocks', 'group', 'tab'].includes(field.type)) {
throw new InvalidConfiguration(
`Compound index on ${field.type} cannot be set. Path: ${localizedPath}`,
)
}
sanitized.fields.push({ field, localizedPath, path, pathHasLocalized })
}
sanitizedCompoundIndexes.push(sanitized)
}
return sanitizedCompoundIndexes
}

View File

@@ -464,6 +464,16 @@ export type CollectionConfig<TSlug extends CollectionSlug = any> = {
*/
refresh?: RefreshHook[]
}
/**
* Define compound indexes for this collection.
* This can be used to either speed up querying/sorting by 2 or more fields at the same time or
* to ensure uniqueness between several fields.
* Specify field paths
* @example
* [{ unique: true, fields: ['title', 'group.name'] }]
* @default []
*/
indexes?: CompoundIndex[]
/**
* Label configuration
*/
@@ -542,7 +552,6 @@ export interface SanitizedCollectionConfig
auth: Auth
endpoints: Endpoint[] | false
fields: Field[]
/**
* Fields in the database schema structure
* Rows / collapsible / tabs w/o name `fields` merged to top, UIs are excluded
@@ -559,6 +568,8 @@ export interface SanitizedCollectionConfig
*/
polymorphicJoins: SanitizedJoin[]
sanitizedIndexes: SanitizedCompoundIndex[]
slug: CollectionSlug
upload: SanitizedUploadConfig
versions: SanitizedCollectionVersions
@@ -602,3 +613,18 @@ export type TypeWithTimestamps = {
id: number | string
updatedAt: string
}
export type CompoundIndex = {
fields: string[]
unique?: boolean
}
export type SanitizedCompoundIndex = {
fields: {
field: FlattenedField
localizedPath: string
path: string
pathHasLocalized: boolean
}[]
unique: boolean
}

View File

@@ -1058,6 +1058,8 @@ export type {
TypeWithID,
TypeWithTimestamps,
} from './collections/config/types.js'
export type { CompoundIndex } from './collections/config/types.js'
export type { SanitizedCompoundIndex } from './collections/config/types.js'
export { createDataloaderCacheKey, getDataLoader } from './collections/dataloader.js'
export { countOperation } from './collections/operations/count.js'
export { createOperation } from './collections/operations/create.js'
@@ -1072,6 +1074,7 @@ export { findVersionsOperation } from './collections/operations/findVersions.js'
export { restoreVersionOperation } from './collections/operations/restoreVersion.js'
export { updateOperation } from './collections/operations/update.js'
export { updateByIDOperation } from './collections/operations/updateByID.js'
export { buildConfig } from './config/build.js'
export {
type ClientConfig,
@@ -1080,7 +1083,6 @@ export {
serverOnlyConfigProperties,
type UnsanitizedClientConfig,
} from './config/client.js'
export { defaults } from './config/defaults.js'
export { sanitizeConfig } from './config/sanitize.js'
export type * from './config/types.js'
@@ -1193,10 +1195,11 @@ export {
ValidationError,
ValidationErrorName,
} from './errors/index.js'
export type { ValidationFieldError } from './errors/index.js'
export { baseBlockFields } from './fields/baseFields/baseBlockFields.js'
export { baseIDField } from './fields/baseFields/baseIDField.js'
export {
createClientField,
createClientFields,
@@ -1308,12 +1311,12 @@ export type {
ValueWithRelation,
} from './fields/config/types.js'
export { getDefaultValue } from './fields/getDefaultValue.js'
export { traverseFields as afterChangeTraverseFields } from './fields/hooks/afterChange/traverseFields.js'
export { promise as afterReadPromise } from './fields/hooks/afterRead/promise.js'
export { traverseFields as afterReadTraverseFields } from './fields/hooks/afterRead/traverseFields.js'
export { traverseFields as beforeChangeTraverseFields } from './fields/hooks/beforeChange/traverseFields.js'
export { traverseFields as beforeValidateTraverseFields } from './fields/hooks/beforeValidate/traverseFields.js'
export { default as sortableFieldTypes } from './fields/sortableFieldTypes.js'
export { validations } from './fields/validations.js'
@@ -1348,6 +1351,7 @@ export type {
UploadFieldValidation,
UsernameFieldValidation,
} from './fields/validations.js'
export {
type ClientGlobalConfig,
createClientGlobalConfig,
@@ -1367,9 +1371,7 @@ export type {
GlobalConfig,
SanitizedGlobalConfig,
} from './globals/config/types.js'
export { docAccessOperation as docAccessOperationGlobal } from './globals/operations/docAccess.js'
export { findOneOperation } from './globals/operations/findOne.js'
export { findVersionByIDOperation as findVersionByIDOperationGlobal } from './globals/operations/findVersionByID.js'
export { findVersionsOperation as findVersionsOperationGlobal } from './globals/operations/findVersions.js'
@@ -1414,9 +1416,9 @@ export { importHandlerPath } from './queues/operations/runJobs/runJob/importHand
export { getLocalI18n } from './translations/getLocalI18n.js'
export * from './types/index.js'
export { getFileByPath } from './uploads/getFileByPath.js'
export type * from './uploads/types.js'
export { addDataAndFileToRequest } from './utilities/addDataAndFileToRequest.js'
export { addLocalesToRequestFromData, sanitizeLocales } from './utilities/addLocalesToRequest.js'
export { commitTransaction } from './utilities/commitTransaction.js'
export {
@@ -1478,6 +1480,7 @@ export { traverseFields } from './utilities/traverseFields.js'
export type { TraverseFieldsCallback } from './utilities/traverseFields.js'
export { buildVersionCollectionFields } from './versions/buildCollectionFields.js'
export { buildVersionGlobalFields } from './versions/buildGlobalFields.js'
export { buildVersionCompoundIndexes } from './versions/buildVersionCompoundIndexes.js'
export { versionDefaults } from './versions/defaults.js'
export { deleteCollectionVersions } from './versions/deleteCollectionVersions.js'
export { enforceMaxVersions } from './versions/enforceMaxVersions.js'

View File

@@ -0,0 +1,70 @@
import type { FlattenedField } from '../fields/config/types.js'
/**
* Get the field from by its path.
* Can accept nested paths, e.g: group.title, array.group.title
* If there were any localized on the path, pathHasLocalized will be true and localizedPath will look like:
* group.<locale>.title // group is localized here
*/
export const getFieldByPath = ({
fields,
localizedPath = '',
path,
}: {
fields: FlattenedField[]
localizedPath?: string
path: string
}): {
field: FlattenedField
localizedPath: string
pathHasLocalized: boolean
} | null => {
let currentFields: FlattenedField[] = fields
let currentField: FlattenedField | null = null
const segments = path.split('.')
let pathHasLocalized = false
while (segments.length > 0) {
const segment = segments.shift()
localizedPath = `${localizedPath ? `${localizedPath}.` : ''}${segment}`
const field = currentFields.find((each) => each.name === segment)
if (!field) {
return null
}
if (field.localized) {
pathHasLocalized = true
localizedPath = `${localizedPath}.<locale>`
}
if ('flattenedFields' in field) {
currentFields = field.flattenedFields
}
if ('blocks' in field) {
for (const block of field.blocks) {
const maybeField = getFieldByPath({
fields: block.flattenedFields,
localizedPath,
path: [...segments].join('.'),
})
if (maybeField) {
return maybeField
}
}
}
currentField = field
}
if (!currentField) {
return null
}
return { field: currentField, localizedPath, pathHasLocalized }
}

View File

@@ -0,0 +1,17 @@
import type { SanitizedCompoundIndex } from '../collections/config/types.js'
export const buildVersionCompoundIndexes = ({
indexes,
}: {
indexes: SanitizedCompoundIndex[]
}): SanitizedCompoundIndex[] => {
return indexes.map((each) => ({
fields: each.fields.map(({ field, localizedPath, path, pathHasLocalized }) => ({
field,
localizedPath: `version.${localizedPath}`,
path: `version.${path}`,
pathHasLocalized,
})),
unique: false,
}))
}

View File

@@ -4,10 +4,9 @@ const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
import type { TextField } from 'payload'
import { v4 as uuid } from 'uuid'
import { randomUUID } from 'crypto'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js'
import { seed } from './seed.js'
import {
customIDsSlug,
@@ -501,7 +500,7 @@ export default buildConfigWithDefaults({
beforeChange: [
({ value, operation }) => {
if (operation === 'create') {
return uuid()
return randomUUID()
}
return value
},
@@ -564,6 +563,43 @@ export default buildConfigWithDefaults({
],
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,
},
],
},
],
globals: [
{

View File

@@ -7,6 +7,7 @@ import {
migrateRelationshipsV2_V3,
migrateVersionsV1_V2,
} from '@payloadcms/db-mongodb/migration-utils'
import { randomUUID } from 'crypto'
import { type Table } from 'drizzle-orm'
import * as drizzlePg from 'drizzle-orm/pg-core'
import * as drizzleSqlite from 'drizzle-orm/sqlite-core'
@@ -305,6 +306,68 @@ describe('database', () => {
})
})
describe('Compound Indexes', () => {
beforeEach(async () => {
await payload.delete({ collection: 'compound-indexes', where: {} })
})
it('top level: should throw a unique error', async () => {
await payload.create({
collection: 'compound-indexes',
data: { three: randomUUID(), one: '1', two: '2' },
})
// does not fail
await payload.create({
collection: 'compound-indexes',
data: { three: randomUUID(), one: '1', two: '3' },
})
// does not fail
await payload.create({
collection: 'compound-indexes',
data: { three: randomUUID(), one: '-1', two: '2' },
})
// fails
await expect(
payload.create({
collection: 'compound-indexes',
data: { three: randomUUID(), one: '1', two: '2' },
}),
).rejects.toBeTruthy()
})
it('combine group and top level: should throw a unique error', async () => {
await payload.create({
collection: 'compound-indexes',
data: {
one: randomUUID(),
three: '3',
group: { four: '4' },
},
})
// does not fail
await payload.create({
collection: 'compound-indexes',
data: { one: randomUUID(), three: '3', group: { four: '5' } },
})
// does not fail
await payload.create({
collection: 'compound-indexes',
data: { one: randomUUID(), three: '4', group: { four: '4' } },
})
// fails
await expect(
payload.create({
collection: 'compound-indexes',
data: { one: randomUUID(), three: '3', group: { four: '4' } },
}),
).rejects.toBeTruthy()
})
})
describe('migrations', () => {
let ranFreshTest = false

View File

@@ -78,6 +78,7 @@ export interface Config {
'custom-ids': CustomId;
'fake-custom-ids': FakeCustomId;
'relationships-migration': RelationshipsMigration;
'compound-indexes': CompoundIndex;
users: User;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
@@ -97,6 +98,7 @@ export interface Config {
'custom-ids': CustomIdsSelect<false> | CustomIdsSelect<true>;
'fake-custom-ids': FakeCustomIdsSelect<false> | FakeCustomIdsSelect<true>;
'relationships-migration': RelationshipsMigrationSelect<false> | RelationshipsMigrationSelect<true>;
'compound-indexes': CompoundIndexesSelect<false> | CompoundIndexesSelect<true>;
users: UsersSelect<false> | UsersSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
@@ -400,6 +402,21 @@ export interface RelationshipsMigration {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "compound-indexes".
*/
export interface CompoundIndex {
id: string;
one?: string | null;
two?: string | null;
three?: string | null;
group?: {
four?: string | null;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
@@ -472,6 +489,10 @@ export interface PayloadLockedDocument {
relationTo: 'relationships-migration';
value: string | RelationshipsMigration;
} | null)
| ({
relationTo: 'compound-indexes';
value: string | CompoundIndex;
} | null)
| ({
relationTo: 'users';
value: string | User;
@@ -755,6 +776,22 @@ export interface RelationshipsMigrationSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "compound-indexes_select".
*/
export interface CompoundIndexesSelect<T extends boolean = true> {
one?: T;
two?: T;
three?: T;
group?:
| T
| {
four?: T;
};
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".