fix: join field works on collections with versions enabled (#8715)

- Fixes errors with drizzle when building the schema
https://github.com/payloadcms/payload/issues/8680
- Adds `joins` to `db.queryDrafts` to have them when doing `.find` with
`draft: true`
This commit is contained in:
Sasha
2024-10-22 18:05:55 +03:00
committed by GitHub
parent 4c396c720e
commit 8af00f2deb
19 changed files with 343 additions and 198 deletions

View File

@@ -6,12 +6,23 @@ import { combineQueries, flattenWhereToOperators } from 'payload'
import type { MongooseAdapter } from './index.js'
import { buildSortParam } from './queries/buildSortParam.js'
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
import { withSession } from './withSession.js'
export const queryDrafts: QueryDrafts = async function queryDrafts(
this: MongooseAdapter,
{ collection, limit, locale, page, pagination, req = {} as PayloadRequest, sort: sortArg, where },
{
collection,
joins,
limit,
locale,
page,
pagination,
req = {} as PayloadRequest,
sort: sortArg,
where,
},
) {
const VersionModel = this.versions[collection]
const collectionConfig = this.payload.collections[collection].config
@@ -89,7 +100,29 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
paginationOptions.options.limit = limit
}
const result = await VersionModel.paginate(versionQuery, paginationOptions)
let result
const aggregate = await buildJoinAggregation({
adapter: this,
collection,
collectionConfig,
joins,
limit,
locale,
query: versionQuery,
versions: true,
})
// build join aggregation
if (aggregate) {
result = await VersionModel.aggregatePaginate(
VersionModel.aggregate(aggregate),
paginationOptions,
)
} else {
result = await VersionModel.paginate(versionQuery, paginationOptions)
}
const docs = JSON.parse(JSON.stringify(result.docs))
return {

View File

@@ -15,6 +15,8 @@ type BuildJoinAggregationArgs = {
locale: string
// the where clause for the top collection
query?: Where
/** whether the query is from drafts */
versions?: boolean
}
export const buildJoinAggregation = async ({
@@ -25,6 +27,7 @@ export const buildJoinAggregation = async ({
limit,
locale,
query,
versions,
}: BuildJoinAggregationArgs): Promise<PipelineStage[] | undefined> => {
if (Object.keys(collectionConfig.joins).length === 0 || joins === false) {
return
@@ -90,7 +93,7 @@ export const buildJoinAggregation = async ({
if (adapter.payload.config.localization && locale === 'all') {
adapter.payload.config.localization.localeCodes.forEach((code) => {
const as = `${join.schemaPath}${code}`
const as = `${versions ? `version.${join.schemaPath}` : join.schemaPath}${code}`
aggregate.push(
{
@@ -98,7 +101,7 @@ export const buildJoinAggregation = async ({
as: `${as}.docs`,
foreignField: `${join.field.on}${code}`,
from: slug,
localField: '_id',
localField: versions ? 'parent' : '_id',
pipeline,
},
},
@@ -131,7 +134,7 @@ export const buildJoinAggregation = async ({
} else {
const localeSuffix =
join.field.localized && adapter.payload.config.localization && locale ? `.${locale}` : ''
const as = `${join.schemaPath}${localeSuffix}`
const as = `${versions ? `version.${join.schemaPath}` : join.schemaPath}${localeSuffix}`
aggregate.push(
{
@@ -139,7 +142,7 @@ export const buildJoinAggregation = async ({
as: `${as}.docs`,
foreignField: `${join.field.on}${localeSuffix}`,
from: slug,
localField: '_id',
localField: versions ? 'parent' : '_id',
pipeline,
},
},

View File

@@ -70,7 +70,6 @@ export const init: Init = async function init(this: SQLiteAdapter) {
disableNotNull: !!collection?.versions?.drafts,
disableUnique: false,
fields: collection.fields,
joins: collection.joins,
locales,
tableName,
timestamps: collection.timestamps,

View File

@@ -61,7 +61,6 @@ type Args = {
disableRelsTableUnique?: boolean
disableUnique: boolean
fields: Field[]
joins?: SanitizedJoins
locales?: [string, ...string[]]
rootRelationships?: Set<string>
rootRelationsToBuild?: RelationMap
@@ -95,7 +94,6 @@ export const buildTable = ({
disableRelsTableUnique,
disableUnique = false,
fields,
joins,
locales,
rootRelationships,
rootRelationsToBuild,
@@ -144,7 +142,6 @@ export const buildTable = ({
disableUnique,
fields,
indexes,
joins,
locales,
localesColumns,
localesIndexes,

View File

@@ -44,7 +44,6 @@ type Args = {
fields: (Field | TabAsField)[]
forceLocalized?: boolean
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
joins?: SanitizedJoins
locales: [string, ...string[]]
localesColumns: Record<string, SQLiteColumnBuilder>
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
@@ -84,7 +83,6 @@ export const traverseFields = ({
fields,
forceLocalized,
indexes,
joins,
locales,
localesColumns,
localesIndexes,
@@ -669,7 +667,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized,
indexes,
joins,
locales,
localesColumns,
localesIndexes,
@@ -725,7 +722,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized: field.localized,
indexes,
joins,
locales,
localesColumns,
localesIndexes,
@@ -782,7 +778,6 @@ export const traverseFields = ({
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
forceLocalized,
indexes,
joins,
locales,
localesColumns,
localesIndexes,
@@ -839,7 +834,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized,
indexes,
joins,
locales,
localesColumns,
localesIndexes,
@@ -937,30 +931,6 @@ export const traverseFields = ({
break
case 'join': {
// fieldName could be 'posts' or 'group_posts'
// using `on` as the key for the relation
const localized = adapter.payload.config.localization && field.localized
const fieldSchemaPath = `${fieldPrefix || ''}${field.name}`
let target: string
const joinConfig = joins[field.collection].find(
({ schemaPath }) => fieldSchemaPath === schemaPath,
)
if (joinConfig.targetField.hasMany) {
target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${adapter.relationshipsSuffix}`
} else {
target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${localized ? adapter.localesSuffix : ''}`
}
relationsToBuild.set(fieldName, {
type: 'many',
// joins are not localized on the parent table
localized: false,
relationName: field.on.replaceAll('.', '_'),
target,
})
break
}
default:
break
}

View File

@@ -16,6 +16,7 @@ type BuildFindQueryArgs = {
joins?: BuildQueryJoinAliases
locale?: string
tableName: string
versions?: boolean
}
export type Result = {
@@ -34,6 +35,7 @@ export const buildFindManyArgs = ({
joins = [],
locale,
tableName,
versions,
}: BuildFindQueryArgs): Record<string, unknown> => {
const result: Result = {
extras: {},
@@ -97,6 +99,7 @@ export const buildFindManyArgs = ({
tablePath: '',
topLevelArgs: result,
topLevelTableName: tableName,
versions,
})
return result

View File

@@ -14,6 +14,7 @@ type Args = {
adapter: DrizzleAdapter
fields: Field[]
tableName: string
versions?: boolean
} & Omit<FindArgs, 'collection'>
export const findMany = async function find({
@@ -28,6 +29,7 @@ export const findMany = async function find({
skip,
sort,
tableName,
versions,
where: whereArg,
}: Args) {
const db = adapter.sessions[await req.transactionID]?.db || adapter.drizzle
@@ -71,6 +73,7 @@ export const findMany = async function find({
joinQuery,
joins,
tableName,
versions,
})
selectDistinctMethods.push({ args: [offset], method: 'offset' })

View File

@@ -1,4 +1,3 @@
import type { DBQueryConfig } from 'drizzle-orm'
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
import type { Field, JoinQuery } from 'payload'
@@ -26,6 +25,7 @@ type TraverseFieldArgs = {
tablePath: string
topLevelArgs: Record<string, unknown>
topLevelTableName: string
versions?: boolean
}
export const traverseFields = ({
@@ -42,6 +42,7 @@ export const traverseFields = ({
tablePath,
topLevelArgs,
topLevelTableName,
versions,
}: TraverseFieldArgs) => {
fields.forEach((field) => {
if (fieldIsVirtual(field)) {
@@ -99,6 +100,7 @@ export const traverseFields = ({
tablePath: tabTablePath,
topLevelArgs,
topLevelTableName,
versions,
})
})
@@ -223,6 +225,7 @@ export const traverseFields = ({
tablePath: `${tablePath}${toSnakeCase(field.name)}_`,
topLevelArgs,
topLevelTableName,
versions,
})
break
@@ -233,55 +236,112 @@ export const traverseFields = ({
if (joinQuery === false) {
break
}
const {
limit: limitArg = 10,
sort,
where,
} = joinQuery[`${path.replaceAll('_', '.')}${field.name}`] || {}
let limit = limitArg
if (limit !== 0) {
// get an additional document and slice it later to determine if there is a next page
limit += 1
}
const fields = adapter.payload.collections[field.collection].config.fields
const joinCollectionTableName = adapter.tableNameMap.get(toSnakeCase(field.collection))
let joinTableName = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${
field.localized && adapter.payload.config.localization ? adapter.localesSuffix : ''
}`
if (field.hasMany) {
const db = adapter.drizzle as LibSQLDatabase
if (field.localized) {
joinTableName = adapter.tableNameMap.get(toSnakeCase(field.collection))
}
const joinTable = `${joinTableName}${adapter.relationshipsSuffix}`
const joins: BuildQueryJoinAliases = []
const joins: BuildQueryJoinAliases = [
{
type: 'innerJoin',
condition: and(
eq(adapter.tables[joinTable].parent, adapter.tables[joinTableName].id),
eq(
sql.raw(`"${joinTable}"."${topLevelTableName}_id"`),
adapter.tables[currentTableName].id,
),
eq(adapter.tables[joinTable].path, field.on),
),
table: adapter.tables[joinTable],
},
]
const { orderBy, where: subQueryWhere } = buildQuery({
const buildQueryResult = buildQuery({
adapter,
fields,
joins,
locale,
sort,
tableName: joinCollectionTableName,
where: {},
where,
})
let subQueryWhere = buildQueryResult.where
const orderBy = buildQueryResult.orderBy
let joinLocalesCollectionTableName: string | undefined
const currentIDColumn = versions
? adapter.tables[currentTableName].parent
: adapter.tables[currentTableName].id
// Handle hasMany _rels table
if (field.hasMany) {
const joinRelsCollectionTableName = `${joinCollectionTableName}${adapter.relationshipsSuffix}`
if (field.localized) {
joinLocalesCollectionTableName = joinRelsCollectionTableName
}
let columnReferenceToCurrentID: string
if (versions) {
columnReferenceToCurrentID = `${topLevelTableName.replace('_', '').replace(new RegExp(`${adapter.versionsSuffix}$`), '')}_id`
} else {
columnReferenceToCurrentID = `${topLevelTableName}_id`
}
joins.push({
type: 'innerJoin',
condition: and(
eq(
adapter.tables[joinRelsCollectionTableName].parent,
adapter.tables[joinCollectionTableName].id,
),
eq(
sql.raw(`"${joinRelsCollectionTableName}"."${columnReferenceToCurrentID}"`),
currentIDColumn,
),
eq(adapter.tables[joinRelsCollectionTableName].path, field.on),
),
table: adapter.tables[joinRelsCollectionTableName],
})
} else {
// Handle localized without hasMany
const foreignColumn = field.on.replaceAll('.', '_')
if (field.localized) {
joinLocalesCollectionTableName = `${joinCollectionTableName}${adapter.localesSuffix}`
joins.push({
type: 'innerJoin',
condition: and(
eq(
adapter.tables[joinLocalesCollectionTableName]._parentID,
adapter.tables[joinCollectionTableName].id,
),
eq(
adapter.tables[joinLocalesCollectionTableName][foreignColumn],
currentIDColumn,
),
),
table: adapter.tables[joinLocalesCollectionTableName],
})
// Handle without localized and without hasMany, just a condition append to where. With localized the inner join handles eq.
} else {
const constraint = eq(
adapter.tables[joinCollectionTableName][foreignColumn],
currentIDColumn,
)
if (subQueryWhere) {
subQueryWhere = and(subQueryWhere, constraint)
} else {
subQueryWhere = constraint
}
}
}
const chainedMethods: ChainedMethods = []
joins.forEach(({ type, condition, table }) => {
@@ -291,25 +351,37 @@ export const traverseFields = ({
})
})
if (limit !== 0) {
chainedMethods.push({
args: [limit],
method: 'limit',
})
}
const db = adapter.drizzle as LibSQLDatabase
const subQuery = chainMethods({
methods: chainedMethods,
query: db
.select({
id: adapter.tables[joinTableName].id,
...(field.localized && {
locale: adapter.tables[joinTable].locale,
id: adapter.tables[joinCollectionTableName].id,
...(joinLocalesCollectionTableName && {
locale:
adapter.tables[joinLocalesCollectionTableName].locale ||
adapter.tables[joinLocalesCollectionTableName]._locale,
}),
})
.from(adapter.tables[joinTableName])
.from(adapter.tables[joinCollectionTableName])
.where(subQueryWhere)
.orderBy(orderBy.order(orderBy.column))
.limit(limit),
.orderBy(orderBy.order(orderBy.column)),
})
const columnName = `${path.replaceAll('.', '_')}${field.name}`
const jsonObjectSelect = field.localized
? sql.raw(`'_parentID', "id", '_locale', "locale"`)
? sql.raw(
`'_parentID', "id", '_locale', "${adapter.tables[joinLocalesCollectionTableName].locale ? 'locale' : '_locale'}"`,
)
: sql.raw(`'id', "id"`)
if (adapter.name === 'sqlite') {
@@ -335,39 +407,6 @@ export const traverseFields = ({
break
}
const selectFields = {}
const withJoin: DBQueryConfig<'many', true, any, any> = {
columns: selectFields,
}
if (limit) {
withJoin.limit = limit
}
if (field.localized) {
withJoin.columns._locale = true
withJoin.columns._parentID = true
} else {
withJoin.columns.id = true
withJoin.columns.parent = true
}
const { orderBy, where: joinWhere } = buildQuery({
adapter,
fields,
joins,
locale,
sort,
tableName: joinTableName,
where,
})
if (joinWhere) {
withJoin.where = () => joinWhere
}
withJoin.orderBy = orderBy.order(orderBy.column)
currentArgs.with[`${path.replaceAll('.', '_')}${field.name}`] = withJoin
break
}
default: {
break
}

View File

@@ -57,7 +57,6 @@ export const init: Init = async function init(this: BasePostgresAdapter) {
disableNotNull: !!collection?.versions?.drafts,
disableUnique: false,
fields: collection.fields,
joins: collection.joins,
tableName,
timestamps: collection.timestamps,
versions: false,

View File

@@ -50,7 +50,6 @@ type Args = {
disableRelsTableUnique?: boolean
disableUnique: boolean
fields: Field[]
joins?: SanitizedJoins
rootRelationships?: Set<string>
rootRelationsToBuild?: RelationMap
rootTableIDColType?: string
@@ -83,7 +82,6 @@ export const buildTable = ({
disableRelsTableUnique = false,
disableUnique = false,
fields,
joins,
rootRelationships,
rootRelationsToBuild,
rootTableIDColType,
@@ -133,7 +131,6 @@ export const buildTable = ({
disableUnique,
fields,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName: tableName,

View File

@@ -50,7 +50,6 @@ type Args = {
fields: (Field | TabAsField)[]
forceLocalized?: boolean
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
joins?: SanitizedJoins
localesColumns: Record<string, PgColumnBuilder>
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
newTableName: string
@@ -89,7 +88,6 @@ export const traverseFields = ({
fields,
forceLocalized,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName,
@@ -672,7 +670,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName,
@@ -727,7 +724,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized: field.localized,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName: `${parentTableName}_${columnName}`,
@@ -783,7 +779,6 @@ export const traverseFields = ({
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
forceLocalized,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName,
@@ -839,7 +834,6 @@ export const traverseFields = ({
fields: field.fields,
forceLocalized,
indexes,
joins,
localesColumns,
localesIndexes,
newTableName,
@@ -936,30 +930,6 @@ export const traverseFields = ({
break
case 'join': {
// fieldName could be 'posts' or 'group_posts'
// using `on` as the key for the relation
const localized = adapter.payload.config.localization && field.localized
const fieldSchemaPath = `${fieldPrefix || ''}${field.name}`
let target: string
const joinConfig = joins[field.collection].find(
({ schemaPath }) => fieldSchemaPath === schemaPath,
)
if (joinConfig.targetField.hasMany) {
target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${adapter.relationshipsSuffix}`
} else {
target = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${localized ? adapter.localesSuffix : ''}`
}
relationsToBuild.set(fieldName, {
type: 'many',
// joins are not localized on the parent table
localized: false,
relationName: field.on.replaceAll('.', '_'),
target,
})
break
}
default:
break
}

View File

@@ -1,4 +1,4 @@
import type { PayloadRequest, QueryDrafts, SanitizedCollectionConfig } from 'payload'
import type { JoinQuery, PayloadRequest, QueryDrafts, SanitizedCollectionConfig } from 'payload'
import { buildVersionCollectionFields, combineQueries } from 'payload'
import toSnakeCase from 'to-snake-case'
@@ -9,7 +9,17 @@ import { findMany } from './find/findMany.js'
export const queryDrafts: QueryDrafts = async function queryDrafts(
this: DrizzleAdapter,
{ collection, limit, locale, page = 1, pagination, req = {} as PayloadRequest, sort, where },
{
collection,
joins,
limit,
locale,
page = 1,
pagination,
req = {} as PayloadRequest,
sort,
where,
},
) {
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
const tableName = this.tableNameMap.get(
@@ -22,6 +32,7 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
const result = await findMany({
adapter: this,
fields,
joins,
limit,
locale,
page,
@@ -29,6 +40,7 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
req,
sort,
tableName,
versions: true,
where: combinedWhere,
})

View File

@@ -126,6 +126,7 @@ export const findOperation = async <TSlug extends CollectionSlug>(
result = await payload.db.queryDrafts<DataFromCollectionSlug<TSlug>>({
collection: collectionConfig.slug,
joins: req.payloadAPI === 'GraphQL' ? false : joins,
limit: sanitizedLimit,
locale,
page: sanitizedPage,

View File

@@ -174,6 +174,7 @@ export type CommitTransaction = (id: number | Promise<number | string> | string)
export type QueryDraftsArgs = {
collection: string
joins?: JoinQuery
limit?: number
locale?: string
page?: number

View File

@@ -0,0 +1,20 @@
import type { CollectionConfig } from 'payload'
import { versionsSlug } from './Versions.js'
export const categoriesVersionsSlug = 'categories-versions'
export const CategoriesVersions: CollectionConfig = {
slug: categoriesVersionsSlug,
fields: [
{
name: 'relatedVersions',
type: 'join',
collection: versionsSlug,
on: 'categoryVersion',
},
],
versions: {
drafts: true,
},
}

View File

@@ -0,0 +1,22 @@
import type { CollectionConfig } from 'payload'
export const versionsSlug = 'versions'
export const Versions: CollectionConfig = {
slug: versionsSlug,
fields: [
{
name: 'category',
relationTo: 'categories',
type: 'relationship',
},
{
name: 'categoryVersion',
relationTo: 'categories-versions',
type: 'relationship',
},
],
versions: {
drafts: true,
},
}

View File

@@ -3,8 +3,10 @@ import path from 'path'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { Categories } from './collections/Categories.js'
import { CategoriesVersions } from './collections/CategoriesVersions.js'
import { Posts } from './collections/Posts.js'
import { Uploads } from './collections/Uploads.js'
import { Versions } from './collections/Versions.js'
import { seed } from './seed.js'
import { localizedCategoriesSlug, localizedPostsSlug } from './shared.js'
@@ -16,6 +18,8 @@ export default buildConfigWithDefaults({
Posts,
Categories,
Uploads,
Versions,
CategoriesVersions,
{
slug: localizedPostsSlug,
admin: {

View File

@@ -1,4 +1,4 @@
import type { Payload } from 'payload'
import type { Payload, TypeWithID } from 'payload'
import path from 'path'
import { getFileByPath } from 'payload'
@@ -373,6 +373,42 @@ describe('Joins Field', () => {
})
})
describe('Joins with versions', () => {
afterEach(async () => {
await payload.delete({ collection: 'versions', where: {} })
await payload.delete({ collection: 'categories-versions', where: {} })
})
it('should populate joins when versions on both sides draft false', async () => {
const category = await payload.create({ collection: 'categories-versions', data: {} })
const version = await payload.create({
collection: 'versions',
data: { categoryVersion: category.id },
})
const res = await payload.find({ collection: 'categories-versions', draft: false })
expect(res.docs[0].relatedVersions.docs[0].id).toBe(version.id)
})
it('should populate joins when versions on both sides draft true payload.db.queryDrafts', async () => {
const category = await payload.create({ collection: 'categories-versions', data: {} })
const version = await payload.create({
collection: 'versions',
data: { categoryVersion: category.id },
})
const res = await payload.find({
collection: 'categories-versions',
draft: true,
})
expect(res.docs[0].relatedVersions.docs[0].id).toBe(version.id)
})
})
describe('REST', () => {
it('should have simple paginate for joins', async () => {
const query = {

View File

@@ -14,6 +14,8 @@ export interface Config {
posts: Post;
categories: Category;
uploads: Upload;
versions: Version;
'categories-versions': CategoriesVersion;
'localized-posts': LocalizedPost;
'localized-categories': LocalizedCategory;
users: User;
@@ -22,7 +24,7 @@ export interface Config {
'payload-migrations': PayloadMigration;
};
db: {
defaultIDType: number;
defaultIDType: string;
};
globals: {};
locale: 'en' | 'es';
@@ -53,15 +55,15 @@ export interface UserAuthOperations {
* via the `definition` "posts".
*/
export interface Post {
id: number;
id: string;
title?: string | null;
upload?: (number | null) | Upload;
category?: (number | null) | Category;
categories?: (number | Category)[] | null;
categoriesLocalized?: (number | Category)[] | null;
upload?: (string | null) | Upload;
category?: (string | null) | Category;
categories?: (string | Category)[] | null;
categoriesLocalized?: (string | Category)[] | null;
group?: {
category?: (number | null) | Category;
camelCaseCategory?: (number | null) | Category;
category?: (string | null) | Category;
camelCaseCategory?: (string | null) | Category;
};
updatedAt: string;
createdAt: string;
@@ -71,9 +73,9 @@ export interface Post {
* via the `definition` "uploads".
*/
export interface Upload {
id: number;
id: string;
relatedPosts?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
@@ -93,41 +95,67 @@ export interface Upload {
* via the `definition` "categories".
*/
export interface Category {
id: number;
id: string;
name?: string | null;
relatedPosts?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
hasManyPosts?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
hasManyPostsLocalized?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
group?: {
relatedPosts?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
camelCasePosts?: {
docs?: (number | Post)[] | null;
docs?: (string | Post)[] | null;
hasNextPage?: boolean | null;
} | null;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "versions".
*/
export interface Version {
id: string;
category?: (string | null) | Category;
categoryVersion?: (string | null) | CategoriesVersion;
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "categories-versions".
*/
export interface CategoriesVersion {
id: string;
relatedVersions?: {
docs?: (string | Version)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
createdAt: string;
_status?: ('draft' | 'published') | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "localized-posts".
*/
export interface LocalizedPost {
id: number;
id: string;
title?: string | null;
category?: (number | null) | LocalizedCategory;
category?: (string | null) | LocalizedCategory;
updatedAt: string;
createdAt: string;
}
@@ -136,10 +164,10 @@ export interface LocalizedPost {
* via the `definition` "localized-categories".
*/
export interface LocalizedCategory {
id: number;
id: string;
name?: string | null;
relatedPosts?: {
docs?: (number | LocalizedPost)[] | null;
docs?: (string | LocalizedPost)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
@@ -150,7 +178,7 @@ export interface LocalizedCategory {
* via the `definition` "users".
*/
export interface User {
id: number;
id: string;
updatedAt: string;
createdAt: string;
email: string;
@@ -167,36 +195,44 @@ export interface User {
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: number;
id: string;
document?:
| ({
relationTo: 'posts';
value: number | Post;
value: string | Post;
} | null)
| ({
relationTo: 'categories';
value: number | Category;
value: string | Category;
} | null)
| ({
relationTo: 'uploads';
value: number | Upload;
value: string | Upload;
} | null)
| ({
relationTo: 'versions';
value: string | Version;
} | null)
| ({
relationTo: 'categories-versions';
value: string | CategoriesVersion;
} | null)
| ({
relationTo: 'localized-posts';
value: number | LocalizedPost;
value: string | LocalizedPost;
} | null)
| ({
relationTo: 'localized-categories';
value: number | LocalizedCategory;
value: string | LocalizedCategory;
} | null)
| ({
relationTo: 'users';
value: number | User;
value: string | User;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: number | User;
value: string | User;
};
updatedAt: string;
createdAt: string;
@@ -206,10 +242,10 @@ export interface PayloadLockedDocument {
* via the `definition` "payload-preferences".
*/
export interface PayloadPreference {
id: number;
id: string;
user: {
relationTo: 'users';
value: number | User;
value: string | User;
};
key?: string | null;
value?:
@@ -229,7 +265,7 @@ export interface PayloadPreference {
* via the `definition` "payload-migrations".
*/
export interface PayloadMigration {
id: number;
id: string;
name?: string | null;
batch?: number | null;
updatedAt: string;