fix: threads draft arg through for child resolvers in GraphQL queries (#6196)

This commit is contained in:
Jarrod Flesch
2024-05-04 16:43:17 -04:00
committed by GitHub
parent 56bedb821f
commit 51149c75ff
50 changed files with 375 additions and 92 deletions

View File

@@ -19,7 +19,7 @@ export type Resolver = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => Promise<{ totalDocs: number }>
export default function countResolver(collection: Collection): Resolver {
export function countResolver(collection: Collection): Resolver {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale

View File

@@ -10,7 +10,9 @@ import type { Context } from '../types.js'
export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
_: unknown,
args: {
draft: boolean
fallbackLocale?: string
id: number | string
locale?: string
},
context: {
@@ -18,10 +20,10 @@ export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
},
) => Promise<GeneratedTypes['collections'][TSlug]>
export default function getDeleteResolver<TSlug extends keyof GeneratedTypes['collections']>(
export function getDeleteResolver<TSlug extends keyof GeneratedTypes['collections']>(
collection: Collection,
): Resolver<TSlug> {
async function resolver(_, args, context: Context) {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale
const fallbackLocale = req.fallbackLocale
@@ -29,6 +31,16 @@ export default function getDeleteResolver<TSlug extends keyof GeneratedTypes['co
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
if (!req.query) req.query = {}
const draft: boolean =
args.draft ?? req.query?.draft === 'false'
? false
: req.query?.draft === 'true'
? true
: undefined
if (typeof draft === 'boolean') req.query.draft = String(draft)
context.req = req
const options = {
@@ -42,6 +54,4 @@ export default function getDeleteResolver<TSlug extends keyof GeneratedTypes['co
return result
}
return resolver
}

View File

@@ -25,7 +25,7 @@ export type Resolver = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => Promise<PaginatedDocs<any>>
export default function findResolver(collection: Collection): Resolver {
export function findResolver(collection: Collection): Resolver {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale
@@ -34,6 +34,16 @@ export default function findResolver(collection: Collection): Resolver {
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
if (!req.query) req.query = {}
const draft: boolean =
args.draft ?? req.query?.draft === 'false'
? false
: req.query?.draft === 'true'
? true
: undefined
if (typeof draft === 'boolean') req.query.draft = String(draft)
context.req = req
const options = {

View File

@@ -20,7 +20,7 @@ export type Resolver<T> = (
},
) => Promise<T>
export default function findByIDResolver<T extends keyof GeneratedTypes['collections']>(
export function findByIDResolver<T extends keyof GeneratedTypes['collections']>(
collection: Collection,
): Resolver<GeneratedTypes['collections'][T]> {
return async function resolver(_, args, context: Context) {
@@ -31,6 +31,16 @@ export default function findByIDResolver<T extends keyof GeneratedTypes['collect
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
if (!req.query) req.query = {}
const draft: boolean =
args.draft ?? req.query?.draft === 'false'
? false
: req.query?.draft === 'true'
? true
: undefined
if (typeof draft === 'boolean') req.query.draft = String(draft)
context.req = req
const options = {

View File

@@ -10,7 +10,6 @@ import type { Context } from '../types.js'
export type Resolver<T extends TypeWithID = any> = (
_: unknown,
args: {
draft: boolean
fallbackLocale?: string
id: number | string
locale?: string
@@ -20,7 +19,7 @@ export type Resolver<T extends TypeWithID = any> = (
},
) => Promise<TypeWithVersion<T>>
export default function findVersionByIDResolver(collection: Collection): Resolver {
export function findVersionByIDResolver(collection: Collection): Resolver {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale
@@ -29,13 +28,13 @@ export default function findVersionByIDResolver(collection: Collection): Resolve
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
context.req = req
const options = {
id: args.id,
collection,
depth: 0,
draft: args.draft,
req: isolateObjectProperty(req, 'transactionID'),
}

View File

@@ -10,6 +10,7 @@ import type { Context } from '../types.js'
export type Resolver = (
_: unknown,
args: {
draft?: boolean
fallbackLocale?: string
limit?: number
locale?: string
@@ -22,8 +23,8 @@ export type Resolver = (
},
) => Promise<PaginatedDocs<any>>
export default function findVersionsResolver(collection: Collection): Resolver {
async function resolver(_, args, context: Context) {
export function findVersionsResolver(collection: Collection): Resolver {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale
const fallbackLocale = req.fallbackLocale
@@ -31,6 +32,16 @@ export default function findVersionsResolver(collection: Collection): Resolver {
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
if (!req.query) req.query = {}
const draft: boolean =
args.draft ?? req.query?.draft === 'false'
? false
: req.query?.draft === 'true'
? true
: undefined
if (typeof draft === 'boolean') req.query.draft = String(draft)
context.req = req
const options = {
@@ -47,6 +58,4 @@ export default function findVersionsResolver(collection: Collection): Resolver {
return result
}
return resolver
}

View File

@@ -13,6 +13,7 @@ export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
autosave: boolean
data: GeneratedTypes['collections'][TSlug]
draft: boolean
fallbackLocale?: string
id: number | string
locale?: string
},
@@ -21,10 +22,10 @@ export type Resolver<TSlug extends keyof GeneratedTypes['collections']> = (
},
) => Promise<GeneratedTypes['collections'][TSlug]>
export default function updateResolver<TSlug extends keyof GeneratedTypes['collections']>(
export function updateResolver<TSlug extends keyof GeneratedTypes['collections']>(
collection: Collection,
): Resolver<TSlug> {
async function resolver(_, args, context: Context) {
return async function resolver(_, args, context: Context) {
let { req } = context
const locale = req.locale
const fallbackLocale = req.fallbackLocale
@@ -32,13 +33,23 @@ export default function updateResolver<TSlug extends keyof GeneratedTypes['colle
req = isolateObjectProperty(req, 'fallbackLocale')
req.locale = args.locale || locale
req.fallbackLocale = args.fallbackLocale || fallbackLocale
if (!req.query) req.query = {}
const draft: boolean =
args.draft ?? req.query?.draft === 'false'
? false
: req.query?.draft === 'true'
? true
: undefined
if (typeof draft === 'boolean') req.query.draft = String(draft)
context.req = req
const options = {
id: args.id,
autosave: args.autosave,
collection,
data: args.data,
data: args.data as any,
depth: 0,
draft: args.draft,
req: isolateObjectProperty(req, 'transactionID'),
@@ -48,6 +59,4 @@ export default function updateResolver<TSlug extends keyof GeneratedTypes['colle
return result
}
return resolver
}

View File

@@ -42,7 +42,7 @@ import {
} from 'graphql'
import { DateTimeResolver, EmailAddressResolver } from 'graphql-scalars'
import { tabHasName } from 'payload/types'
import { toWords } from 'payload/utilities'
import { createDataloaderCacheKey, toWords } from 'payload/utilities'
import type { Context } from '../resolvers/types.js'
@@ -320,6 +320,7 @@ function buildObjectType({
type = type || newlyCreatedBlockType
const relationshipArgs: {
draft?: unknown
fallbackLocale?: unknown
limit?: unknown
locale?: unknown
@@ -327,6 +328,16 @@ function buildObjectType({
where?: unknown
} = {}
const relationsUseDrafts = (Array.isArray(relationTo) ? relationTo : [relationTo]).some(
(relation) => graphqlResult.collections[relation].config.versions?.drafts,
)
if (relationsUseDrafts) {
relationshipArgs.draft = {
type: GraphQLBoolean,
}
}
if (config.localization) {
relationshipArgs.locale = {
type: graphqlResult.types.localeInputType,
@@ -350,6 +361,7 @@ function buildObjectType({
const locale = args.locale || context.req.locale
const fallbackLocale = args.fallbackLocale || context.req.fallbackLocale
let relatedCollectionSlug = field.relationTo
const draft = args.draft ?? context.req.query?.draft
if (hasManyValues) {
const results = []
@@ -365,17 +377,18 @@ function buildObjectType({
}
const result = await context.req.payloadDataLoader.load(
JSON.stringify([
context.req.transactionID,
collectionSlug,
id,
0,
0,
locale,
createDataloaderCacheKey({
collectionSlug: collectionSlug as string,
currentDepth: 0,
depth: 0,
docID: id,
draft,
fallbackLocale,
false,
false,
]),
locale,
overrideAccess: false,
showHiddenFields: false,
transactionID: context.req.transactionID,
}),
)
if (result) {
@@ -411,17 +424,18 @@ function buildObjectType({
if (id) {
const relatedDocument = await context.req.payloadDataLoader.load(
JSON.stringify([
context.req.transactionID,
relatedCollectionSlug,
id,
0,
0,
locale,
createDataloaderCacheKey({
collectionSlug: relatedCollectionSlug as string,
currentDepth: 0,
depth: 0,
docID: id,
draft,
fallbackLocale,
false,
false,
]),
locale,
overrideAccess: false,
showHiddenFields: false,
transactionID: context.req.transactionID,
}),
)
if (relatedDocument) {
@@ -479,6 +493,7 @@ function buildObjectType({
editor?.populationPromises({
context,
depth,
draft: args.draft,
field,
fieldPromises,
findMany: false,
@@ -615,17 +630,18 @@ function buildObjectType({
if (id) {
const relatedDocument = await context.req.payloadDataLoader.load(
JSON.stringify([
context.req.transactionID,
relatedCollectionSlug,
id,
0,
0,
locale,
createDataloaderCacheKey({
collectionSlug: relatedCollectionSlug,
currentDepth: 0,
depth: 0,
docID: id,
draft: false,
fallbackLocale,
false,
false,
]),
locale,
overrideAccess: false,
showHiddenFields: false,
transactionID: context.req.transactionID,
}),
)
return relatedDocument || null

View File

@@ -24,17 +24,17 @@ import refresh from '../resolvers/auth/refresh.js'
import resetPassword from '../resolvers/auth/resetPassword.js'
import unlock from '../resolvers/auth/unlock.js'
import verifyEmail from '../resolvers/auth/verifyEmail.js'
import countResolver from '../resolvers/collections/count.js'
import { countResolver } from '../resolvers/collections/count.js'
import createResolver from '../resolvers/collections/create.js'
import getDeleteResolver from '../resolvers/collections/delete.js'
import { getDeleteResolver } from '../resolvers/collections/delete.js'
import { docAccessResolver } from '../resolvers/collections/docAccess.js'
import duplicateResolver from '../resolvers/collections/duplicate.js'
import findResolver from '../resolvers/collections/find.js'
import findByIDResolver from '../resolvers/collections/findByID.js'
import findVersionByIDResolver from '../resolvers/collections/findVersionByID.js'
import findVersionsResolver from '../resolvers/collections/findVersions.js'
import { findResolver } from '../resolvers/collections/find.js'
import { findByIDResolver } from '../resolvers/collections/findByID.js'
import { findVersionByIDResolver } from '../resolvers/collections/findVersionByID.js'
import { findVersionsResolver } from '../resolvers/collections/findVersions.js'
import restoreVersionResolver from '../resolvers/collections/restoreVersion.js'
import updateResolver from '../resolvers/collections/update.js'
import { updateResolver } from '../resolvers/collections/update.js'
import formatName from '../utilities/formatName.js'
import { buildMutationInputType, getCollectionIDType } from './buildMutationInputType.js'
import buildObjectType from './buildObjectType.js'

View File

@@ -58,6 +58,7 @@ type RichTextAdapterBase<
context: RequestContext
currentDepth?: number
depth: number
draft: boolean
field: RichTextField<Value, AdapterProps, ExtraFieldProperties>
fieldPromises: Promise<void>[]
findMany: boolean

View File

@@ -189,6 +189,7 @@ export const loginOperation = async <TSlug extends keyof GeneratedTypes['collect
context: req.context,
depth,
doc: user,
draft: undefined,
fallbackLocale,
global: null,
locale,

View File

@@ -54,6 +54,7 @@ const batchAndLoadDocs =
fallbackLocale,
overrideAccess,
showHiddenFields,
draft,
] = JSON.parse(key)
const batchKeyArray = [
@@ -65,6 +66,7 @@ const batchAndLoadDocs =
fallbackLocale,
overrideAccess,
showHiddenFields,
draft,
]
const batchKey = JSON.stringify(batchKeyArray)
@@ -98,6 +100,7 @@ const batchAndLoadDocs =
fallbackLocale,
overrideAccess,
showHiddenFields,
draft,
] = JSON.parse(batchKey)
req.transactionID = transactionID
@@ -107,6 +110,7 @@ const batchAndLoadDocs =
currentDepth,
depth,
disableErrors: true,
draft,
fallbackLocale,
locale,
overrideAccess: Boolean(overrideAccess),
@@ -124,17 +128,18 @@ const batchAndLoadDocs =
// Inject doc within docs array if index exists
result.docs.forEach((doc) => {
const docKey = JSON.stringify([
req.transactionID,
collection,
doc.id,
depth,
const docKey = createDataloaderCacheKey({
collectionSlug: collection,
currentDepth,
locale,
fallbackLocale,
depth,
docID: doc.id,
draft,
fallbackLocale: req.fallbackLocale,
locale: req.locale,
overrideAccess,
showHiddenFields,
])
transactionID: req.transactionID,
})
const docsIndex = keys.findIndex((key) => key === docKey)
if (docsIndex > -1) {
@@ -150,3 +155,40 @@ const batchAndLoadDocs =
}
export const getDataLoader = (req: PayloadRequest) => new DataLoader(batchAndLoadDocs(req))
type CreateCacheKeyArgs = {
collectionSlug: string
currentDepth: number
depth: number
docID: number | string
draft: boolean
fallbackLocale: string
locale: string
overrideAccess: boolean
showHiddenFields: boolean
transactionID: number | string
}
export const createDataloaderCacheKey = ({
collectionSlug,
currentDepth,
depth,
docID,
draft,
fallbackLocale,
locale,
overrideAccess,
showHiddenFields,
transactionID,
}: CreateCacheKeyArgs): string =>
JSON.stringify([
transactionID,
collectionSlug,
docID,
depth,
currentDepth,
locale,
fallbackLocale,
overrideAccess,
showHiddenFields,
draft,
])

View File

@@ -288,6 +288,7 @@ export const createOperation = async <TSlug extends keyof GeneratedTypes['collec
context: req.context,
depth,
doc: result,
draft,
fallbackLocale,
global: null,
locale,

View File

@@ -177,6 +177,7 @@ export const deleteOperation = async <TSlug extends keyof GeneratedTypes['collec
context: req.context,
depth,
doc: result || doc,
draft: undefined,
fallbackLocale,
global: null,
locale,

View File

@@ -156,6 +156,7 @@ export const deleteByIDOperation = async <TSlug extends keyof GeneratedTypes['co
context: req.context,
depth,
doc: result,
draft: undefined,
fallbackLocale,
global: null,
locale,

View File

@@ -120,6 +120,7 @@ export const duplicateOperation = async <TSlug extends keyof GeneratedTypes['col
context: req.context,
depth: 0,
doc: docWithLocales,
draft: draftArg,
fallbackLocale: null,
global: null,
locale: req.locale,
@@ -247,6 +248,7 @@ export const duplicateOperation = async <TSlug extends keyof GeneratedTypes['col
context: req.context,
depth,
doc: versionDoc,
draft: draftArg,
fallbackLocale,
global: null,
locale: localeArg,

View File

@@ -195,6 +195,7 @@ export const findOperation = async <T extends TypeWithID & Record<string, unknow
currentDepth,
depth,
doc,
draft: draftsEnabled,
fallbackLocale,
findMany: true,
global: null,

View File

@@ -141,6 +141,7 @@ export const findByIDOperation = async <T extends TypeWithID>(
currentDepth,
depth,
doc: result,
draft: draftEnabled,
fallbackLocale,
global: null,
locale,

View File

@@ -112,6 +112,7 @@ export const findVersionByIDOperation = async <T extends TypeWithID = any>(
currentDepth,
depth,
doc: result.version,
draft: undefined,
fallbackLocale,
global: null,
locale,

View File

@@ -124,6 +124,7 @@ export const findVersionsOperation = async <T extends TypeWithVersion<T>>(
context: req.context,
depth,
doc: data.version,
draft: undefined,
fallbackLocale,
findMany: true,
global: null,

View File

@@ -142,6 +142,7 @@ export const restoreVersionOperation = async <T extends TypeWithID = any>(
context: req.context,
depth,
doc: result,
draft: undefined,
fallbackLocale,
global: null,
locale,

View File

@@ -176,6 +176,7 @@ export const updateOperation = async <TSlug extends keyof GeneratedTypes['collec
context: req.context,
depth: 0,
doc,
draft: draftArg,
fallbackLocale,
global: null,
locale,
@@ -311,6 +312,7 @@ export const updateOperation = async <TSlug extends keyof GeneratedTypes['collec
context: req.context,
depth,
doc: result,
draft: draftArg,
fallbackLocale: null,
global: null,
locale,

View File

@@ -130,6 +130,7 @@ export const updateByIDOperation = async <TSlug extends keyof GeneratedTypes['co
context: req.context,
depth: 0,
doc: docWithLocales,
draft: draftArg,
fallbackLocale: null,
global: null,
locale,
@@ -299,6 +300,7 @@ export const updateByIDOperation = async <TSlug extends keyof GeneratedTypes['co
context: req.context,
depth,
doc: result,
draft: draftArg,
fallbackLocale,
global: null,
locale,

View File

@@ -23,6 +23,7 @@ export type ServerOnlyRootProperties = keyof Pick<
| 'editor'
| 'email'
| 'endpoints'
| 'graphQL'
| 'hooks'
| 'onInit'
| 'plugins'
@@ -70,6 +71,7 @@ export const createClientConfig = async ({
'csrf',
'email',
'custom',
'graphQL',
// `admin`, `onInit`, `localization`, `collections`, and `globals` are all handled separately
]

View File

@@ -2,7 +2,7 @@
* WARNING: This file contains exports that can only be safely used on the front-end
*/
export { getDataLoader } from '../collections/dataloader.js'
export { createDataloaderCacheKey, getDataLoader } from '../collections/dataloader.js'
export { default as 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'

View File

@@ -11,6 +11,7 @@ type Args = {
currentDepth?: number
depth: number
doc: Record<string, unknown>
draft: boolean
fallbackLocale: null | string
findMany?: boolean
flattenLocales?: boolean
@@ -38,6 +39,7 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
currentDepth: incomingCurrentDepth,
depth: incomingDepth,
doc: incomingDoc,
draft,
fallbackLocale,
findMany,
flattenLocales = true,
@@ -66,6 +68,7 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: collection?.fields || global?.fields,

View File

@@ -16,6 +16,7 @@ type Args = {
currentDepth: number
depth: number
doc: Record<string, unknown>
draft: boolean
fallbackLocale: null | string
field: Field | TabAsField
/**
@@ -49,6 +50,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
field,
fieldPromises,
@@ -152,6 +154,7 @@ export const promise = async ({
context,
currentDepth,
depth,
draft,
field,
fieldPromises,
findMany,
@@ -279,6 +282,7 @@ export const promise = async ({
relationshipPopulationPromise({
currentDepth,
depth,
draft,
fallbackLocale,
field,
locale,
@@ -302,6 +306,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.fields,
@@ -332,6 +337,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.fields,
@@ -358,6 +364,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.fields,
@@ -396,6 +403,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: block.fields,
@@ -426,6 +434,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: block.fields,
@@ -460,6 +469,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.fields,
@@ -492,6 +502,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.fields,
@@ -518,6 +529,7 @@ export const promise = async ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),

View File

@@ -1,6 +1,7 @@
import type { PayloadRequestWithData } from '../../../types/index.js'
import type { RelationshipField, UploadField } from '../../config/types.js'
import { createDataloaderCacheKey } from '../../../collections/dataloader.js'
import { fieldHasMaxDepth, fieldSupportsMany } from '../../config/types.js'
type PopulateArgs = {
@@ -8,6 +9,7 @@ type PopulateArgs = {
data: Record<string, unknown>
dataReference: Record<string, any>
depth: number
draft: boolean
fallbackLocale: null | string
field: RelationshipField | UploadField
index?: number
@@ -23,6 +25,7 @@ const populate = async ({
data,
dataReference,
depth,
draft,
fallbackLocale,
field,
index,
@@ -52,17 +55,18 @@ const populate = async ({
if (shouldPopulate) {
relationshipValue = await req.payloadDataLoader.load(
JSON.stringify([
req.transactionID,
relatedCollection.config.slug,
id,
createDataloaderCacheKey({
collectionSlug: relatedCollection.config.slug,
currentDepth: currentDepth + 1,
depth,
currentDepth + 1,
locale,
docID: id as string,
draft,
fallbackLocale,
locale,
overrideAccess,
showHiddenFields,
]),
transactionID: req.transactionID,
}),
)
}
@@ -94,6 +98,7 @@ const populate = async ({
type PromiseArgs = {
currentDepth: number
depth: number
draft: boolean
fallbackLocale: null | string
field: RelationshipField | UploadField
locale: null | string
@@ -106,6 +111,7 @@ type PromiseArgs = {
export const relationshipPopulationPromise = async ({
currentDepth,
depth,
draft,
fallbackLocale,
field,
locale,
@@ -133,6 +139,7 @@ export const relationshipPopulationPromise = async ({
data: siblingDoc[field.name][key][index],
dataReference: resultingDoc,
depth: populateDepth,
draft,
fallbackLocale,
field,
index,
@@ -156,6 +163,7 @@ export const relationshipPopulationPromise = async ({
data: relatedDoc,
dataReference: resultingDoc,
depth: populateDepth,
draft,
fallbackLocale,
field,
index,
@@ -182,6 +190,7 @@ export const relationshipPopulationPromise = async ({
data: siblingDoc[field.name][key],
dataReference: resultingDoc,
depth: populateDepth,
draft,
fallbackLocale,
field,
key,
@@ -201,6 +210,7 @@ export const relationshipPopulationPromise = async ({
data: siblingDoc[field.name],
dataReference: resultingDoc,
depth: populateDepth,
draft,
fallbackLocale,
field,
locale,

View File

@@ -11,6 +11,7 @@ type Args = {
currentDepth: number
depth: number
doc: Record<string, unknown>
draft: boolean
fallbackLocale: null | string
/**
* fieldPromises are used for things like field hooks. They should be awaited before awaiting populationPromises
@@ -36,6 +37,7 @@ export const traverseFields = ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
fieldPromises,
fields,
@@ -59,6 +61,7 @@ export const traverseFields = ({
currentDepth,
depth,
doc,
draft,
fallbackLocale,
field,
fieldPromises,

View File

@@ -101,6 +101,7 @@ export const findOneOperation = async <T extends Record<string, unknown>>(
context: req.context,
depth,
doc,
draft: draftEnabled,
fallbackLocale,
global: globalConfig,
locale,

View File

@@ -110,6 +110,7 @@ export const findVersionByIDOperation = async <T extends TypeWithVersion<T> = an
currentDepth,
depth,
doc: result.version,
draft: undefined,
fallbackLocale,
global: globalConfig,
locale,

View File

@@ -96,6 +96,7 @@ export const findVersionsOperation = async <T extends TypeWithVersion<T>>(
// Patch globalType onto version doc
globalType: globalConfig.slug,
},
draft: undefined,
fallbackLocale,
findMany: true,
global: globalConfig,

View File

@@ -107,6 +107,7 @@ export const restoreVersionOperation = async <T extends TypeWithVersion<T> = any
context: req.context,
depth,
doc: result,
draft: undefined,
fallbackLocale,
global: globalConfig,
locale,

View File

@@ -96,6 +96,7 @@ export const updateOperation = async <TSlug extends keyof GeneratedTypes['global
context: req.context,
depth: 0,
doc: globalJSON,
draft: draftArg,
fallbackLocale,
global: globalConfig,
locale,
@@ -219,6 +220,7 @@ export const updateOperation = async <TSlug extends keyof GeneratedTypes['global
context: req.context,
depth,
doc: result,
draft: draftArg,
fallbackLocale: null,
global: globalConfig,
locale,

View File

@@ -11,6 +11,7 @@ export const blockPopulationPromiseHOC = (
context,
currentDepth,
depth,
draft,
editorPopulationPromises,
fieldPromises,
findMany,
@@ -45,6 +46,7 @@ export const blockPopulationPromiseHOC = (
req,
showHiddenFields,
// The afterReadPromise gets its data from looking for field.name inside the siblingDoc. Thus, here we cannot pass the whole document's siblingDoc, but only the siblingDoc (sibling fields) of the current field.
draft,
siblingDoc: blockFieldData,
})
}

View File

@@ -11,6 +11,7 @@ export const linkPopulationPromiseHOC = (
context,
currentDepth,
depth,
draft,
editorPopulationPromises,
fieldPromises,
findMany,
@@ -34,6 +35,7 @@ export const linkPopulationPromiseHOC = (
currentDepth,
data: node.fields,
depth,
draft,
editorPopulationPromises,
fieldPromises,
fields: props.fields,

View File

@@ -6,6 +6,7 @@ import { populate } from '../../../populate/populate.js'
export const relationshipPopulationPromise: PopulationPromise<SerializedRelationshipNode> = ({
currentDepth,
depth,
draft,
field,
node,
overrideAccess,
@@ -27,6 +28,7 @@ export const relationshipPopulationPromise: PopulationPromise<SerializedRelation
currentDepth,
data: node,
depth,
draft,
field,
key: 'value',
overrideAccess,

View File

@@ -40,6 +40,7 @@ export type PopulationPromise<T extends SerializedLexicalNode = SerializedLexica
context: RequestContext
currentDepth: number
depth: number
draft: boolean
/**
* This maps all population promises to the node type
*/

View File

@@ -12,6 +12,7 @@ export const uploadPopulationPromiseHOC = (
context,
currentDepth,
depth,
draft,
editorPopulationPromises,
field,
fieldPromises,
@@ -37,6 +38,7 @@ export const uploadPopulationPromiseHOC = (
currentDepth,
data: node,
depth,
draft,
field,
key: 'value',
overrideAccess,
@@ -54,6 +56,7 @@ export const uploadPopulationPromiseHOC = (
currentDepth,
data: node.fields || {},
depth,
draft,
editorPopulationPromises,
fieldPromises,
fields: props?.collections?.[node?.relationTo]?.fields,

View File

@@ -264,6 +264,7 @@ export function lexicalEditor(props?: LexicalEditorProps): LexicalRichTextAdapte
context,
currentDepth,
depth,
draft,
field,
fieldPromises,
findMany,
@@ -280,6 +281,7 @@ export function lexicalEditor(props?: LexicalEditorProps): LexicalRichTextAdapte
context,
currentDepth,
depth,
draft,
editorPopulationPromises: finalSanitizedEditorConfig.features.populationPromises,
field,
fieldPromises,

View File

@@ -2,12 +2,15 @@ import type { SerializedEditorState } from 'lexical'
import type { PayloadRequestWithData } from 'payload/types'
import type { Collection, Field, RichTextField } from 'payload/types'
import { createDataloaderCacheKey } from 'payload/utilities'
import type { AdapterProps } from '../types.js'
type Arguments = {
currentDepth?: number
data: unknown
depth: number
draft: boolean
field: RichTextField<SerializedEditorState, AdapterProps>
key: number | string
overrideAccess?: boolean
@@ -21,6 +24,7 @@ export const populate = async ({
currentDepth,
data,
depth,
draft,
key,
overrideAccess,
req,
@@ -33,17 +37,18 @@ export const populate = async ({
const dataRef = data as Record<string, unknown>
const doc = await req.payloadDataLoader.load(
JSON.stringify([
req.transactionID,
collection.config.slug,
id,
createDataloaderCacheKey({
collectionSlug: collection.config.slug,
currentDepth: currentDepth + 1,
depth,
currentDepth + 1,
req.locale,
req.fallbackLocale,
typeof overrideAccess === 'undefined' ? false : overrideAccess,
docID: id as string,
draft,
fallbackLocale: req.fallbackLocale,
locale: req.locale,
overrideAccess: typeof overrideAccess === 'undefined' ? false : overrideAccess,
showHiddenFields,
]),
transactionID: req.transactionID,
}),
)
if (doc) {

View File

@@ -19,6 +19,7 @@ export const populateLexicalPopulationPromises = ({
context,
currentDepth,
depth,
draft,
editorPopulationPromises,
field,
fieldPromises,
@@ -42,6 +43,7 @@ export const populateLexicalPopulationPromises = ({
context,
currentDepth,
depth,
draft,
editorPopulationPromises,
field,
fieldPromises,

View File

@@ -10,6 +10,7 @@ type NestedRichTextFieldsArgs = {
currentDepth?: number
data: unknown
depth: number
draft: boolean
/**
* This maps all the population promises to the node types
*/
@@ -33,6 +34,7 @@ export const recurseNestedFields = ({
currentDepth = 0,
data,
depth,
draft,
fieldPromises,
fields,
findMany,
@@ -49,6 +51,7 @@ export const recurseNestedFields = ({
currentDepth,
depth,
doc: data as any, // Looks like it's only needed for hooks and access control, so doesn't matter what we pass here right now
draft,
fallbackLocale: req.fallbackLocale,
fieldPromises,
fields,

View File

@@ -1,12 +1,15 @@
import type { PayloadRequestWithData } from 'payload/types'
import type { Collection, Field, RichTextField } from 'payload/types'
import { createDataloaderCacheKey } from 'payload/utilities'
import type { AdapterArguments } from '../types.js'
type Arguments = {
currentDepth?: number
data: unknown
depth: number
draft: boolean
field: RichTextField<any[], AdapterArguments, AdapterArguments>
key: number | string
overrideAccess?: boolean
@@ -20,6 +23,7 @@ export const populate = async ({
currentDepth,
data,
depth,
draft,
key,
overrideAccess,
req,
@@ -32,17 +36,18 @@ export const populate = async ({
const dataRef = data as Record<string, unknown>
const doc = await req.payloadDataLoader.load(
JSON.stringify([
req.transactionID,
collection.config.slug,
id,
createDataloaderCacheKey({
collectionSlug: collection.config.slug,
currentDepth: currentDepth + 1,
depth,
currentDepth + 1,
req.locale,
req.fallbackLocale,
typeof overrideAccess === 'undefined' ? false : overrideAccess,
docID: id,
draft,
fallbackLocale: req.locale,
locale: req.fallbackLocale,
overrideAccess: typeof overrideAccess === 'undefined' ? false : overrideAccess,
showHiddenFields,
]),
transactionID: req.transactionID,
}),
)
if (doc) {

View File

@@ -9,6 +9,7 @@ type NestedRichTextFieldsArgs = {
currentDepth?: number
data: unknown
depth: number
draft: boolean
fields: Field[]
overrideAccess: boolean
populationPromises: Promise<void>[]
@@ -20,6 +21,7 @@ export const recurseNestedFields = ({
currentDepth = 0,
data,
depth,
draft,
fields,
overrideAccess = false,
populationPromises,
@@ -41,6 +43,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name],
depth,
draft,
field,
key: i,
overrideAccess,
@@ -61,6 +64,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name],
depth,
draft,
field,
key: i,
overrideAccess,
@@ -85,6 +89,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name],
depth,
draft,
field,
key: 'value',
overrideAccess,
@@ -104,6 +109,7 @@ export const recurseNestedFields = ({
currentDepth,
data,
depth,
draft,
field,
key: field.name,
overrideAccess,
@@ -118,6 +124,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name],
depth,
draft,
fields: field.fields,
overrideAccess,
populationPromises,
@@ -129,6 +136,7 @@ export const recurseNestedFields = ({
currentDepth,
data,
depth,
draft,
fields: field.fields,
overrideAccess,
populationPromises,
@@ -142,6 +150,7 @@ export const recurseNestedFields = ({
currentDepth,
data,
depth,
draft,
fields: tab.fields,
overrideAccess,
populationPromises,
@@ -158,6 +167,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name][i],
depth,
draft,
fields: block.fields,
overrideAccess,
populationPromises,
@@ -174,6 +184,7 @@ export const recurseNestedFields = ({
currentDepth,
data: data[field.name][i],
depth,
draft,
fields: field.fields,
overrideAccess,
populationPromises,
@@ -191,6 +202,7 @@ export const recurseNestedFields = ({
children: node.children,
currentDepth,
depth,
draft,
field,
overrideAccess,
populationPromises,

View File

@@ -11,6 +11,7 @@ type RecurseRichTextArgs = {
children: unknown[]
currentDepth: number
depth: number
draft: boolean
field: RichTextField<any[], AdapterArguments, AdapterArguments>
overrideAccess: boolean
populationPromises: Promise<void>[]
@@ -22,6 +23,7 @@ export const recurseRichText = ({
children,
currentDepth = 0,
depth,
draft,
field,
overrideAccess = false,
populationPromises,
@@ -45,6 +47,7 @@ export const recurseRichText = ({
currentDepth,
data: element,
depth,
draft,
field,
key: 'value',
overrideAccess,
@@ -61,6 +64,7 @@ export const recurseRichText = ({
currentDepth,
data: element.fields || {},
depth,
draft,
fields: field.admin.upload.collections[element.relationTo].fields,
overrideAccess,
populationPromises,
@@ -82,6 +86,7 @@ export const recurseRichText = ({
currentDepth,
data: element.doc,
depth,
draft,
field,
key: 'value',
overrideAccess,
@@ -97,6 +102,7 @@ export const recurseRichText = ({
currentDepth,
data: element.fields || {},
depth,
draft,
fields: field.admin?.link?.fields,
overrideAccess,
populationPromises,
@@ -111,6 +117,7 @@ export const recurseRichText = ({
children: element.children,
currentDepth,
depth,
draft,
field,
overrideAccess,
populationPromises,
@@ -125,6 +132,7 @@ export const recurseRichText = ({
export const richTextRelationshipPromise = ({
currentDepth,
depth,
draft,
field,
overrideAccess,
populationPromises,
@@ -136,6 +144,7 @@ export const richTextRelationshipPromise = ({
children: siblingDoc[field.name] as unknown[],
currentDepth,
depth,
draft,
field,
overrideAccess,
populationPromises,

View File

@@ -64,6 +64,7 @@ export function slateEditor(
context,
currentDepth,
depth,
draft,
field,
fieldPromises,
findMany,
@@ -84,6 +85,7 @@ export function slateEditor(
context,
currentDepth,
depth,
draft,
field,
fieldPromises,
findMany,

View File

@@ -1,4 +1,4 @@
import type { Config, SanitizedConfig } from 'payload/config'
import type { SanitizedConfig } from 'payload/config'
import type { Field, RichTextFieldProps } from 'payload/types'
import type { Editor } from 'slate'

View File

@@ -352,6 +352,9 @@ export default buildConfigWithDefaults({
relationTo: 'cyclical-relationship',
},
],
versions: {
drafts: true,
},
},
],
graphQL: {

View File

@@ -1001,6 +1001,79 @@ describe('collections-graphql', () => {
})
})
it('should query correctly with draft argument', async () => {
const publishValue = '1'
const draftValue = '2'
// publish doc
const newDoc = await payload.create({
collection: 'cyclical-relationship',
draft: false,
data: {
title: publishValue,
},
})
// create cyclical relationship
await payload.update({
collection: 'cyclical-relationship',
id: newDoc.id,
data: {
relationToSelf: newDoc.id,
},
})
// save new version
await payload.update({
collection: 'cyclical-relationship',
id: newDoc.id,
draft: true,
data: {
title: draftValue,
},
})
const draftParentPublishedChild = `{
CyclicalRelationships(draft: true) {
docs {
title
relationToSelf(draft: false) {
title
}
}
}
}`
const res1 = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query: draftParentPublishedChild }),
})
.then((res) => res.json())
const queriedDoc = res1.data.CyclicalRelationships.docs[0]
expect(queriedDoc.title).toEqual(draftValue)
expect(queriedDoc.relationToSelf.title).toEqual(publishValue)
const publishedParentDraftChild = `{
CyclicalRelationships(draft: false) {
docs {
title
relationToSelf(draft: true) {
title
}
}
}
}`
const res2 = await restClient
.GRAPHQL_POST({
body: JSON.stringify({ query: publishedParentDraftChild }),
})
.then((res) => res.json())
const queriedDoc2 = res2.data.CyclicalRelationships.docs[0]
expect(queriedDoc2.title).toEqual(publishValue)
expect(queriedDoc2.relationToSelf.title).toEqual(draftValue)
})
describe('Error Handler', () => {
it('should return have an array of errors when making a bad request', async () => {
const query = `query {