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:
@@ -6,12 +6,23 @@ import { combineQueries, flattenWhereToOperators } from 'payload'
|
|||||||
import type { MongooseAdapter } from './index.js'
|
import type { MongooseAdapter } from './index.js'
|
||||||
|
|
||||||
import { buildSortParam } from './queries/buildSortParam.js'
|
import { buildSortParam } from './queries/buildSortParam.js'
|
||||||
|
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
|
||||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||||
import { withSession } from './withSession.js'
|
import { withSession } from './withSession.js'
|
||||||
|
|
||||||
export const queryDrafts: QueryDrafts = async function queryDrafts(
|
export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||||
this: MongooseAdapter,
|
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 VersionModel = this.versions[collection]
|
||||||
const collectionConfig = this.payload.collections[collection].config
|
const collectionConfig = this.payload.collections[collection].config
|
||||||
@@ -89,7 +100,29 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
|||||||
paginationOptions.options.limit = limit
|
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))
|
const docs = JSON.parse(JSON.stringify(result.docs))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type BuildJoinAggregationArgs = {
|
|||||||
locale: string
|
locale: string
|
||||||
// the where clause for the top collection
|
// the where clause for the top collection
|
||||||
query?: Where
|
query?: Where
|
||||||
|
/** whether the query is from drafts */
|
||||||
|
versions?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildJoinAggregation = async ({
|
export const buildJoinAggregation = async ({
|
||||||
@@ -25,6 +27,7 @@ export const buildJoinAggregation = async ({
|
|||||||
limit,
|
limit,
|
||||||
locale,
|
locale,
|
||||||
query,
|
query,
|
||||||
|
versions,
|
||||||
}: BuildJoinAggregationArgs): Promise<PipelineStage[] | undefined> => {
|
}: BuildJoinAggregationArgs): Promise<PipelineStage[] | undefined> => {
|
||||||
if (Object.keys(collectionConfig.joins).length === 0 || joins === false) {
|
if (Object.keys(collectionConfig.joins).length === 0 || joins === false) {
|
||||||
return
|
return
|
||||||
@@ -90,7 +93,7 @@ export const buildJoinAggregation = async ({
|
|||||||
|
|
||||||
if (adapter.payload.config.localization && locale === 'all') {
|
if (adapter.payload.config.localization && locale === 'all') {
|
||||||
adapter.payload.config.localization.localeCodes.forEach((code) => {
|
adapter.payload.config.localization.localeCodes.forEach((code) => {
|
||||||
const as = `${join.schemaPath}${code}`
|
const as = `${versions ? `version.${join.schemaPath}` : join.schemaPath}${code}`
|
||||||
|
|
||||||
aggregate.push(
|
aggregate.push(
|
||||||
{
|
{
|
||||||
@@ -98,7 +101,7 @@ export const buildJoinAggregation = async ({
|
|||||||
as: `${as}.docs`,
|
as: `${as}.docs`,
|
||||||
foreignField: `${join.field.on}${code}`,
|
foreignField: `${join.field.on}${code}`,
|
||||||
from: slug,
|
from: slug,
|
||||||
localField: '_id',
|
localField: versions ? 'parent' : '_id',
|
||||||
pipeline,
|
pipeline,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -131,7 +134,7 @@ export const buildJoinAggregation = async ({
|
|||||||
} else {
|
} else {
|
||||||
const localeSuffix =
|
const localeSuffix =
|
||||||
join.field.localized && adapter.payload.config.localization && locale ? `.${locale}` : ''
|
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(
|
aggregate.push(
|
||||||
{
|
{
|
||||||
@@ -139,7 +142,7 @@ export const buildJoinAggregation = async ({
|
|||||||
as: `${as}.docs`,
|
as: `${as}.docs`,
|
||||||
foreignField: `${join.field.on}${localeSuffix}`,
|
foreignField: `${join.field.on}${localeSuffix}`,
|
||||||
from: slug,
|
from: slug,
|
||||||
localField: '_id',
|
localField: versions ? 'parent' : '_id',
|
||||||
pipeline,
|
pipeline,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ export const init: Init = async function init(this: SQLiteAdapter) {
|
|||||||
disableNotNull: !!collection?.versions?.drafts,
|
disableNotNull: !!collection?.versions?.drafts,
|
||||||
disableUnique: false,
|
disableUnique: false,
|
||||||
fields: collection.fields,
|
fields: collection.fields,
|
||||||
joins: collection.joins,
|
|
||||||
locales,
|
locales,
|
||||||
tableName,
|
tableName,
|
||||||
timestamps: collection.timestamps,
|
timestamps: collection.timestamps,
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ type Args = {
|
|||||||
disableRelsTableUnique?: boolean
|
disableRelsTableUnique?: boolean
|
||||||
disableUnique: boolean
|
disableUnique: boolean
|
||||||
fields: Field[]
|
fields: Field[]
|
||||||
joins?: SanitizedJoins
|
|
||||||
locales?: [string, ...string[]]
|
locales?: [string, ...string[]]
|
||||||
rootRelationships?: Set<string>
|
rootRelationships?: Set<string>
|
||||||
rootRelationsToBuild?: RelationMap
|
rootRelationsToBuild?: RelationMap
|
||||||
@@ -95,7 +94,6 @@ export const buildTable = ({
|
|||||||
disableRelsTableUnique,
|
disableRelsTableUnique,
|
||||||
disableUnique = false,
|
disableUnique = false,
|
||||||
fields,
|
fields,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
rootRelationships,
|
rootRelationships,
|
||||||
rootRelationsToBuild,
|
rootRelationsToBuild,
|
||||||
@@ -144,7 +142,6 @@ export const buildTable = ({
|
|||||||
disableUnique,
|
disableUnique,
|
||||||
fields,
|
fields,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ type Args = {
|
|||||||
fields: (Field | TabAsField)[]
|
fields: (Field | TabAsField)[]
|
||||||
forceLocalized?: boolean
|
forceLocalized?: boolean
|
||||||
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
||||||
joins?: SanitizedJoins
|
|
||||||
locales: [string, ...string[]]
|
locales: [string, ...string[]]
|
||||||
localesColumns: Record<string, SQLiteColumnBuilder>
|
localesColumns: Record<string, SQLiteColumnBuilder>
|
||||||
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
||||||
@@ -84,7 +83,6 @@ export const traverseFields = ({
|
|||||||
fields,
|
fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
@@ -669,7 +667,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
@@ -725,7 +722,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized: field.localized,
|
forceLocalized: field.localized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
@@ -782,7 +778,6 @@ export const traverseFields = ({
|
|||||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
@@ -839,7 +834,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
locales,
|
locales,
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
@@ -937,30 +931,6 @@ export const traverseFields = ({
|
|||||||
|
|
||||||
break
|
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:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type BuildFindQueryArgs = {
|
|||||||
joins?: BuildQueryJoinAliases
|
joins?: BuildQueryJoinAliases
|
||||||
locale?: string
|
locale?: string
|
||||||
tableName: string
|
tableName: string
|
||||||
|
versions?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
@@ -34,6 +35,7 @@ export const buildFindManyArgs = ({
|
|||||||
joins = [],
|
joins = [],
|
||||||
locale,
|
locale,
|
||||||
tableName,
|
tableName,
|
||||||
|
versions,
|
||||||
}: BuildFindQueryArgs): Record<string, unknown> => {
|
}: BuildFindQueryArgs): Record<string, unknown> => {
|
||||||
const result: Result = {
|
const result: Result = {
|
||||||
extras: {},
|
extras: {},
|
||||||
@@ -97,6 +99,7 @@ export const buildFindManyArgs = ({
|
|||||||
tablePath: '',
|
tablePath: '',
|
||||||
topLevelArgs: result,
|
topLevelArgs: result,
|
||||||
topLevelTableName: tableName,
|
topLevelTableName: tableName,
|
||||||
|
versions,
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type Args = {
|
|||||||
adapter: DrizzleAdapter
|
adapter: DrizzleAdapter
|
||||||
fields: Field[]
|
fields: Field[]
|
||||||
tableName: string
|
tableName: string
|
||||||
|
versions?: boolean
|
||||||
} & Omit<FindArgs, 'collection'>
|
} & Omit<FindArgs, 'collection'>
|
||||||
|
|
||||||
export const findMany = async function find({
|
export const findMany = async function find({
|
||||||
@@ -28,6 +29,7 @@ export const findMany = async function find({
|
|||||||
skip,
|
skip,
|
||||||
sort,
|
sort,
|
||||||
tableName,
|
tableName,
|
||||||
|
versions,
|
||||||
where: whereArg,
|
where: whereArg,
|
||||||
}: Args) {
|
}: Args) {
|
||||||
const db = adapter.sessions[await req.transactionID]?.db || adapter.drizzle
|
const db = adapter.sessions[await req.transactionID]?.db || adapter.drizzle
|
||||||
@@ -71,6 +73,7 @@ export const findMany = async function find({
|
|||||||
joinQuery,
|
joinQuery,
|
||||||
joins,
|
joins,
|
||||||
tableName,
|
tableName,
|
||||||
|
versions,
|
||||||
})
|
})
|
||||||
|
|
||||||
selectDistinctMethods.push({ args: [offset], method: 'offset' })
|
selectDistinctMethods.push({ args: [offset], method: 'offset' })
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { DBQueryConfig } from 'drizzle-orm'
|
|
||||||
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
|
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
|
||||||
import type { Field, JoinQuery } from 'payload'
|
import type { Field, JoinQuery } from 'payload'
|
||||||
|
|
||||||
@@ -26,6 +25,7 @@ type TraverseFieldArgs = {
|
|||||||
tablePath: string
|
tablePath: string
|
||||||
topLevelArgs: Record<string, unknown>
|
topLevelArgs: Record<string, unknown>
|
||||||
topLevelTableName: string
|
topLevelTableName: string
|
||||||
|
versions?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traverseFields = ({
|
export const traverseFields = ({
|
||||||
@@ -42,6 +42,7 @@ export const traverseFields = ({
|
|||||||
tablePath,
|
tablePath,
|
||||||
topLevelArgs,
|
topLevelArgs,
|
||||||
topLevelTableName,
|
topLevelTableName,
|
||||||
|
versions,
|
||||||
}: TraverseFieldArgs) => {
|
}: TraverseFieldArgs) => {
|
||||||
fields.forEach((field) => {
|
fields.forEach((field) => {
|
||||||
if (fieldIsVirtual(field)) {
|
if (fieldIsVirtual(field)) {
|
||||||
@@ -99,6 +100,7 @@ export const traverseFields = ({
|
|||||||
tablePath: tabTablePath,
|
tablePath: tabTablePath,
|
||||||
topLevelArgs,
|
topLevelArgs,
|
||||||
topLevelTableName,
|
topLevelTableName,
|
||||||
|
versions,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -223,6 +225,7 @@ export const traverseFields = ({
|
|||||||
tablePath: `${tablePath}${toSnakeCase(field.name)}_`,
|
tablePath: `${tablePath}${toSnakeCase(field.name)}_`,
|
||||||
topLevelArgs,
|
topLevelArgs,
|
||||||
topLevelTableName,
|
topLevelTableName,
|
||||||
|
versions,
|
||||||
})
|
})
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -233,87 +236,156 @@ export const traverseFields = ({
|
|||||||
if (joinQuery === false) {
|
if (joinQuery === false) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
limit: limitArg = 10,
|
limit: limitArg = 10,
|
||||||
sort,
|
sort,
|
||||||
where,
|
where,
|
||||||
} = joinQuery[`${path.replaceAll('_', '.')}${field.name}`] || {}
|
} = joinQuery[`${path.replaceAll('_', '.')}${field.name}`] || {}
|
||||||
let limit = limitArg
|
let limit = limitArg
|
||||||
|
|
||||||
if (limit !== 0) {
|
if (limit !== 0) {
|
||||||
// get an additional document and slice it later to determine if there is a next page
|
// get an additional document and slice it later to determine if there is a next page
|
||||||
limit += 1
|
limit += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = adapter.payload.collections[field.collection].config.fields
|
const fields = adapter.payload.collections[field.collection].config.fields
|
||||||
|
|
||||||
const joinCollectionTableName = adapter.tableNameMap.get(toSnakeCase(field.collection))
|
const joinCollectionTableName = adapter.tableNameMap.get(toSnakeCase(field.collection))
|
||||||
let joinTableName = `${adapter.tableNameMap.get(toSnakeCase(field.collection))}${
|
|
||||||
field.localized && adapter.payload.config.localization ? adapter.localesSuffix : ''
|
|
||||||
}`
|
|
||||||
|
|
||||||
|
const joins: BuildQueryJoinAliases = []
|
||||||
|
|
||||||
|
const buildQueryResult = buildQuery({
|
||||||
|
adapter,
|
||||||
|
fields,
|
||||||
|
joins,
|
||||||
|
locale,
|
||||||
|
sort,
|
||||||
|
tableName: joinCollectionTableName,
|
||||||
|
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) {
|
if (field.hasMany) {
|
||||||
const db = adapter.drizzle as LibSQLDatabase
|
const joinRelsCollectionTableName = `${joinCollectionTableName}${adapter.relationshipsSuffix}`
|
||||||
if (field.localized) {
|
|
||||||
joinTableName = adapter.tableNameMap.get(toSnakeCase(field.collection))
|
|
||||||
}
|
|
||||||
const joinTable = `${joinTableName}${adapter.relationshipsSuffix}`
|
|
||||||
|
|
||||||
const joins: BuildQueryJoinAliases = [
|
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',
|
type: 'innerJoin',
|
||||||
condition: and(
|
condition: and(
|
||||||
eq(adapter.tables[joinTable].parent, adapter.tables[joinTableName].id),
|
|
||||||
eq(
|
eq(
|
||||||
sql.raw(`"${joinTable}"."${topLevelTableName}_id"`),
|
adapter.tables[joinLocalesCollectionTableName]._parentID,
|
||||||
adapter.tables[currentTableName].id,
|
adapter.tables[joinCollectionTableName].id,
|
||||||
|
),
|
||||||
|
eq(
|
||||||
|
adapter.tables[joinLocalesCollectionTableName][foreignColumn],
|
||||||
|
currentIDColumn,
|
||||||
),
|
),
|
||||||
eq(adapter.tables[joinTable].path, field.on),
|
|
||||||
),
|
),
|
||||||
table: adapter.tables[joinTable],
|
table: adapter.tables[joinLocalesCollectionTableName],
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const { orderBy, where: subQueryWhere } = buildQuery({
|
|
||||||
adapter,
|
|
||||||
fields,
|
|
||||||
joins,
|
|
||||||
locale,
|
|
||||||
sort,
|
|
||||||
tableName: joinCollectionTableName,
|
|
||||||
where: {},
|
|
||||||
})
|
|
||||||
|
|
||||||
const chainedMethods: ChainedMethods = []
|
|
||||||
|
|
||||||
joins.forEach(({ type, condition, table }) => {
|
|
||||||
chainedMethods.push({
|
|
||||||
args: [table, condition],
|
|
||||||
method: type ?? 'leftJoin',
|
|
||||||
})
|
})
|
||||||
|
// 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 }) => {
|
||||||
|
chainedMethods.push({
|
||||||
|
args: [table, condition],
|
||||||
|
method: type ?? 'leftJoin',
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const subQuery = chainMethods({
|
if (limit !== 0) {
|
||||||
methods: chainedMethods,
|
chainedMethods.push({
|
||||||
query: db
|
args: [limit],
|
||||||
.select({
|
method: 'limit',
|
||||||
id: adapter.tables[joinTableName].id,
|
|
||||||
...(field.localized && {
|
|
||||||
locale: adapter.tables[joinTable].locale,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.from(adapter.tables[joinTableName])
|
|
||||||
.where(subQueryWhere)
|
|
||||||
.orderBy(orderBy.order(orderBy.column))
|
|
||||||
.limit(limit),
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const columnName = `${path.replaceAll('.', '_')}${field.name}`
|
const db = adapter.drizzle as LibSQLDatabase
|
||||||
|
|
||||||
const jsonObjectSelect = field.localized
|
const subQuery = chainMethods({
|
||||||
? sql.raw(`'_parentID', "id", '_locale', "locale"`)
|
methods: chainedMethods,
|
||||||
: sql.raw(`'id', "id"`)
|
query: db
|
||||||
|
.select({
|
||||||
|
id: adapter.tables[joinCollectionTableName].id,
|
||||||
|
...(joinLocalesCollectionTableName && {
|
||||||
|
locale:
|
||||||
|
adapter.tables[joinLocalesCollectionTableName].locale ||
|
||||||
|
adapter.tables[joinLocalesCollectionTableName]._locale,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.from(adapter.tables[joinCollectionTableName])
|
||||||
|
.where(subQueryWhere)
|
||||||
|
.orderBy(orderBy.order(orderBy.column)),
|
||||||
|
})
|
||||||
|
|
||||||
if (adapter.name === 'sqlite') {
|
const columnName = `${path.replaceAll('.', '_')}${field.name}`
|
||||||
currentArgs.extras[columnName] = sql`
|
|
||||||
|
const jsonObjectSelect = field.localized
|
||||||
|
? sql.raw(
|
||||||
|
`'_parentID', "id", '_locale', "${adapter.tables[joinLocalesCollectionTableName].locale ? 'locale' : '_locale'}"`,
|
||||||
|
)
|
||||||
|
: sql.raw(`'id', "id"`)
|
||||||
|
|
||||||
|
if (adapter.name === 'sqlite') {
|
||||||
|
currentArgs.extras[columnName] = sql`
|
||||||
COALESCE((
|
COALESCE((
|
||||||
SELECT json_group_array(json_object(${jsonObjectSelect}))
|
SELECT json_group_array(json_object(${jsonObjectSelect}))
|
||||||
FROM (
|
FROM (
|
||||||
@@ -321,8 +393,8 @@ export const traverseFields = ({
|
|||||||
) AS ${sql.raw(`${columnName}_sub`)}
|
) AS ${sql.raw(`${columnName}_sub`)}
|
||||||
), '[]')
|
), '[]')
|
||||||
`.as(columnName)
|
`.as(columnName)
|
||||||
} else {
|
} else {
|
||||||
currentArgs.extras[columnName] = sql`
|
currentArgs.extras[columnName] = sql`
|
||||||
COALESCE((
|
COALESCE((
|
||||||
SELECT json_agg(json_build_object(${jsonObjectSelect}))
|
SELECT json_agg(json_build_object(${jsonObjectSelect}))
|
||||||
FROM (
|
FROM (
|
||||||
@@ -330,41 +402,8 @@ export const traverseFields = ({
|
|||||||
) AS ${sql.raw(`${columnName}_sub`)}
|
) AS ${sql.raw(`${columnName}_sub`)}
|
||||||
), '[]'::json)
|
), '[]'::json)
|
||||||
`.as(columnName)
|
`.as(columnName)
|
||||||
}
|
|
||||||
|
|
||||||
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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ export const init: Init = async function init(this: BasePostgresAdapter) {
|
|||||||
disableNotNull: !!collection?.versions?.drafts,
|
disableNotNull: !!collection?.versions?.drafts,
|
||||||
disableUnique: false,
|
disableUnique: false,
|
||||||
fields: collection.fields,
|
fields: collection.fields,
|
||||||
joins: collection.joins,
|
|
||||||
tableName,
|
tableName,
|
||||||
timestamps: collection.timestamps,
|
timestamps: collection.timestamps,
|
||||||
versions: false,
|
versions: false,
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ type Args = {
|
|||||||
disableRelsTableUnique?: boolean
|
disableRelsTableUnique?: boolean
|
||||||
disableUnique: boolean
|
disableUnique: boolean
|
||||||
fields: Field[]
|
fields: Field[]
|
||||||
joins?: SanitizedJoins
|
|
||||||
rootRelationships?: Set<string>
|
rootRelationships?: Set<string>
|
||||||
rootRelationsToBuild?: RelationMap
|
rootRelationsToBuild?: RelationMap
|
||||||
rootTableIDColType?: string
|
rootTableIDColType?: string
|
||||||
@@ -83,7 +82,6 @@ export const buildTable = ({
|
|||||||
disableRelsTableUnique = false,
|
disableRelsTableUnique = false,
|
||||||
disableUnique = false,
|
disableUnique = false,
|
||||||
fields,
|
fields,
|
||||||
joins,
|
|
||||||
rootRelationships,
|
rootRelationships,
|
||||||
rootRelationsToBuild,
|
rootRelationsToBuild,
|
||||||
rootTableIDColType,
|
rootTableIDColType,
|
||||||
@@ -133,7 +131,6 @@ export const buildTable = ({
|
|||||||
disableUnique,
|
disableUnique,
|
||||||
fields,
|
fields,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName: tableName,
|
newTableName: tableName,
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ type Args = {
|
|||||||
fields: (Field | TabAsField)[]
|
fields: (Field | TabAsField)[]
|
||||||
forceLocalized?: boolean
|
forceLocalized?: boolean
|
||||||
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
indexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
||||||
joins?: SanitizedJoins
|
|
||||||
localesColumns: Record<string, PgColumnBuilder>
|
localesColumns: Record<string, PgColumnBuilder>
|
||||||
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder>
|
||||||
newTableName: string
|
newTableName: string
|
||||||
@@ -89,7 +88,6 @@ export const traverseFields = ({
|
|||||||
fields,
|
fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName,
|
newTableName,
|
||||||
@@ -672,7 +670,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName,
|
newTableName,
|
||||||
@@ -727,7 +724,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized: field.localized,
|
forceLocalized: field.localized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName: `${parentTableName}_${columnName}`,
|
newTableName: `${parentTableName}_${columnName}`,
|
||||||
@@ -783,7 +779,6 @@ export const traverseFields = ({
|
|||||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName,
|
newTableName,
|
||||||
@@ -839,7 +834,6 @@ export const traverseFields = ({
|
|||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
forceLocalized,
|
forceLocalized,
|
||||||
indexes,
|
indexes,
|
||||||
joins,
|
|
||||||
localesColumns,
|
localesColumns,
|
||||||
localesIndexes,
|
localesIndexes,
|
||||||
newTableName,
|
newTableName,
|
||||||
@@ -936,30 +930,6 @@ export const traverseFields = ({
|
|||||||
|
|
||||||
break
|
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:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { buildVersionCollectionFields, combineQueries } from 'payload'
|
||||||
import toSnakeCase from 'to-snake-case'
|
import toSnakeCase from 'to-snake-case'
|
||||||
@@ -9,7 +9,17 @@ import { findMany } from './find/findMany.js'
|
|||||||
|
|
||||||
export const queryDrafts: QueryDrafts = async function queryDrafts(
|
export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||||
this: DrizzleAdapter,
|
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 collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||||
const tableName = this.tableNameMap.get(
|
const tableName = this.tableNameMap.get(
|
||||||
@@ -22,6 +32,7 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
|||||||
const result = await findMany({
|
const result = await findMany({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
fields,
|
fields,
|
||||||
|
joins,
|
||||||
limit,
|
limit,
|
||||||
locale,
|
locale,
|
||||||
page,
|
page,
|
||||||
@@ -29,6 +40,7 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
|||||||
req,
|
req,
|
||||||
sort,
|
sort,
|
||||||
tableName,
|
tableName,
|
||||||
|
versions: true,
|
||||||
where: combinedWhere,
|
where: combinedWhere,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export const findOperation = async <TSlug extends CollectionSlug>(
|
|||||||
|
|
||||||
result = await payload.db.queryDrafts<DataFromCollectionSlug<TSlug>>({
|
result = await payload.db.queryDrafts<DataFromCollectionSlug<TSlug>>({
|
||||||
collection: collectionConfig.slug,
|
collection: collectionConfig.slug,
|
||||||
|
joins: req.payloadAPI === 'GraphQL' ? false : joins,
|
||||||
limit: sanitizedLimit,
|
limit: sanitizedLimit,
|
||||||
locale,
|
locale,
|
||||||
page: sanitizedPage,
|
page: sanitizedPage,
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ export type CommitTransaction = (id: number | Promise<number | string> | string)
|
|||||||
|
|
||||||
export type QueryDraftsArgs = {
|
export type QueryDraftsArgs = {
|
||||||
collection: string
|
collection: string
|
||||||
|
joins?: JoinQuery
|
||||||
limit?: number
|
limit?: number
|
||||||
locale?: string
|
locale?: string
|
||||||
page?: number
|
page?: number
|
||||||
|
|||||||
20
test/joins/collections/CategoriesVersions.ts
Normal file
20
test/joins/collections/CategoriesVersions.ts
Normal 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
22
test/joins/collections/Versions.ts
Normal file
22
test/joins/collections/Versions.ts
Normal 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@ import path from 'path'
|
|||||||
|
|
||||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||||
import { Categories } from './collections/Categories.js'
|
import { Categories } from './collections/Categories.js'
|
||||||
|
import { CategoriesVersions } from './collections/CategoriesVersions.js'
|
||||||
import { Posts } from './collections/Posts.js'
|
import { Posts } from './collections/Posts.js'
|
||||||
import { Uploads } from './collections/Uploads.js'
|
import { Uploads } from './collections/Uploads.js'
|
||||||
|
import { Versions } from './collections/Versions.js'
|
||||||
import { seed } from './seed.js'
|
import { seed } from './seed.js'
|
||||||
import { localizedCategoriesSlug, localizedPostsSlug } from './shared.js'
|
import { localizedCategoriesSlug, localizedPostsSlug } from './shared.js'
|
||||||
|
|
||||||
@@ -16,6 +18,8 @@ export default buildConfigWithDefaults({
|
|||||||
Posts,
|
Posts,
|
||||||
Categories,
|
Categories,
|
||||||
Uploads,
|
Uploads,
|
||||||
|
Versions,
|
||||||
|
CategoriesVersions,
|
||||||
{
|
{
|
||||||
slug: localizedPostsSlug,
|
slug: localizedPostsSlug,
|
||||||
admin: {
|
admin: {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Payload } from 'payload'
|
import type { Payload, TypeWithID } from 'payload'
|
||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getFileByPath } from 'payload'
|
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', () => {
|
describe('REST', () => {
|
||||||
it('should have simple paginate for joins', async () => {
|
it('should have simple paginate for joins', async () => {
|
||||||
const query = {
|
const query = {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export interface Config {
|
|||||||
posts: Post;
|
posts: Post;
|
||||||
categories: Category;
|
categories: Category;
|
||||||
uploads: Upload;
|
uploads: Upload;
|
||||||
|
versions: Version;
|
||||||
|
'categories-versions': CategoriesVersion;
|
||||||
'localized-posts': LocalizedPost;
|
'localized-posts': LocalizedPost;
|
||||||
'localized-categories': LocalizedCategory;
|
'localized-categories': LocalizedCategory;
|
||||||
users: User;
|
users: User;
|
||||||
@@ -22,7 +24,7 @@ export interface Config {
|
|||||||
'payload-migrations': PayloadMigration;
|
'payload-migrations': PayloadMigration;
|
||||||
};
|
};
|
||||||
db: {
|
db: {
|
||||||
defaultIDType: number;
|
defaultIDType: string;
|
||||||
};
|
};
|
||||||
globals: {};
|
globals: {};
|
||||||
locale: 'en' | 'es';
|
locale: 'en' | 'es';
|
||||||
@@ -53,15 +55,15 @@ export interface UserAuthOperations {
|
|||||||
* via the `definition` "posts".
|
* via the `definition` "posts".
|
||||||
*/
|
*/
|
||||||
export interface Post {
|
export interface Post {
|
||||||
id: number;
|
id: string;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
upload?: (number | null) | Upload;
|
upload?: (string | null) | Upload;
|
||||||
category?: (number | null) | Category;
|
category?: (string | null) | Category;
|
||||||
categories?: (number | Category)[] | null;
|
categories?: (string | Category)[] | null;
|
||||||
categoriesLocalized?: (number | Category)[] | null;
|
categoriesLocalized?: (string | Category)[] | null;
|
||||||
group?: {
|
group?: {
|
||||||
category?: (number | null) | Category;
|
category?: (string | null) | Category;
|
||||||
camelCaseCategory?: (number | null) | Category;
|
camelCaseCategory?: (string | null) | Category;
|
||||||
};
|
};
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
@@ -71,9 +73,9 @@ export interface Post {
|
|||||||
* via the `definition` "uploads".
|
* via the `definition` "uploads".
|
||||||
*/
|
*/
|
||||||
export interface Upload {
|
export interface Upload {
|
||||||
id: number;
|
id: string;
|
||||||
relatedPosts?: {
|
relatedPosts?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
@@ -93,41 +95,67 @@ export interface Upload {
|
|||||||
* via the `definition` "categories".
|
* via the `definition` "categories".
|
||||||
*/
|
*/
|
||||||
export interface Category {
|
export interface Category {
|
||||||
id: number;
|
id: string;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
relatedPosts?: {
|
relatedPosts?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
hasManyPosts?: {
|
hasManyPosts?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
hasManyPostsLocalized?: {
|
hasManyPostsLocalized?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
group?: {
|
group?: {
|
||||||
relatedPosts?: {
|
relatedPosts?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
camelCasePosts?: {
|
camelCasePosts?: {
|
||||||
docs?: (number | Post)[] | null;
|
docs?: (string | Post)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: 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
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "localized-posts".
|
* via the `definition` "localized-posts".
|
||||||
*/
|
*/
|
||||||
export interface LocalizedPost {
|
export interface LocalizedPost {
|
||||||
id: number;
|
id: string;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
category?: (number | null) | LocalizedCategory;
|
category?: (string | null) | LocalizedCategory;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -136,10 +164,10 @@ export interface LocalizedPost {
|
|||||||
* via the `definition` "localized-categories".
|
* via the `definition` "localized-categories".
|
||||||
*/
|
*/
|
||||||
export interface LocalizedCategory {
|
export interface LocalizedCategory {
|
||||||
id: number;
|
id: string;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
relatedPosts?: {
|
relatedPosts?: {
|
||||||
docs?: (number | LocalizedPost)[] | null;
|
docs?: (string | LocalizedPost)[] | null;
|
||||||
hasNextPage?: boolean | null;
|
hasNextPage?: boolean | null;
|
||||||
} | null;
|
} | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
@@ -150,7 +178,7 @@ export interface LocalizedCategory {
|
|||||||
* via the `definition` "users".
|
* via the `definition` "users".
|
||||||
*/
|
*/
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number;
|
id: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
email: string;
|
email: string;
|
||||||
@@ -167,36 +195,44 @@ export interface User {
|
|||||||
* via the `definition` "payload-locked-documents".
|
* via the `definition` "payload-locked-documents".
|
||||||
*/
|
*/
|
||||||
export interface PayloadLockedDocument {
|
export interface PayloadLockedDocument {
|
||||||
id: number;
|
id: string;
|
||||||
document?:
|
document?:
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'posts';
|
relationTo: 'posts';
|
||||||
value: number | Post;
|
value: string | Post;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'categories';
|
relationTo: 'categories';
|
||||||
value: number | Category;
|
value: string | Category;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'uploads';
|
relationTo: 'uploads';
|
||||||
value: number | Upload;
|
value: string | Upload;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'versions';
|
||||||
|
value: string | Version;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'categories-versions';
|
||||||
|
value: string | CategoriesVersion;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'localized-posts';
|
relationTo: 'localized-posts';
|
||||||
value: number | LocalizedPost;
|
value: string | LocalizedPost;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'localized-categories';
|
relationTo: 'localized-categories';
|
||||||
value: number | LocalizedCategory;
|
value: string | LocalizedCategory;
|
||||||
} | null)
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: number | User;
|
value: string | User;
|
||||||
} | null);
|
} | null);
|
||||||
globalSlug?: string | null;
|
globalSlug?: string | null;
|
||||||
user: {
|
user: {
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: number | User;
|
value: string | User;
|
||||||
};
|
};
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
@@ -206,10 +242,10 @@ export interface PayloadLockedDocument {
|
|||||||
* via the `definition` "payload-preferences".
|
* via the `definition` "payload-preferences".
|
||||||
*/
|
*/
|
||||||
export interface PayloadPreference {
|
export interface PayloadPreference {
|
||||||
id: number;
|
id: string;
|
||||||
user: {
|
user: {
|
||||||
relationTo: 'users';
|
relationTo: 'users';
|
||||||
value: number | User;
|
value: string | User;
|
||||||
};
|
};
|
||||||
key?: string | null;
|
key?: string | null;
|
||||||
value?:
|
value?:
|
||||||
@@ -229,7 +265,7 @@ export interface PayloadPreference {
|
|||||||
* via the `definition` "payload-migrations".
|
* via the `definition` "payload-migrations".
|
||||||
*/
|
*/
|
||||||
export interface PayloadMigration {
|
export interface PayloadMigration {
|
||||||
id: number;
|
id: string;
|
||||||
name?: string | null;
|
name?: string | null;
|
||||||
batch?: number | null;
|
batch?: number | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user