Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/graphql/src/schema/withNullableType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const withNullableType = ({
const hasReadAccessControl = field.access && field.access.read
const condition = field.admin && field.admin.condition
const isTimestamp = field.name === 'createdAt' || field.name === 'updatedAt'
// Virtual fields are computed by hooks, so they should be nullable in GraphQL inputs
const isVirtual = 'virtual' in field && field.virtual === true

if (
!forceNullable &&
Expand All @@ -25,7 +27,8 @@ export const withNullableType = ({
(!field.localized || parentIsLocalized) &&
!condition &&
!hasReadAccessControl &&
!isTimestamp
!isTimestamp &&
!isVirtual
) {
return new GraphQLNonNull(type)
}
Expand Down
61 changes: 56 additions & 5 deletions packages/payload/src/collections/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
collection: SanitizedCollectionConfig
context: RequestContext
data?: Partial<T>
/**
* If true, this operation is an autosave
*/
autosave?: boolean
/**
* If true, this operation is saving a draft
*/
draft?: boolean
/**
* Hook operation being performed
*/
Expand All @@ -191,13 +199,25 @@ export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
*/
originalDoc?: T
req: PayloadRequest
/**
* If true, this operation is a trash/restore operation
*/
trash?: boolean
}) => any

export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
/** The collection which this hook is being run on */
collection: SanitizedCollectionConfig
context: RequestContext
data: Partial<T>
/**
* If true, this operation is an autosave
*/
autosave?: boolean
/**
* If true, this operation is saving a draft
*/
draft?: boolean
/**
* Hook operation being performed
*/
Expand All @@ -209,6 +229,10 @@ export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
*/
originalDoc?: T
req: PayloadRequest
/**
* If true, this operation is a trash/restore operation
*/
trash?: boolean
}) => any

export type AfterChangeHook<T extends TypeWithID = any> = (args: {
Expand All @@ -217,6 +241,14 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
context: RequestContext
data: Partial<T>
doc: T
/**
* If true, this operation is an autosave
*/
autosave?: boolean
/**
* If true, this operation is saving a draft
*/
draft?: boolean
/**
* Hook operation being performed
*/
Expand All @@ -227,13 +259,21 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
overrideAccess?: boolean
previousDoc: T
req: PayloadRequest
/**
* If true, this operation is a trash/restore operation
*/
trash?: boolean
}) => any

export type BeforeReadHook<T extends TypeWithID = any> = (args: {
/** The collection which this hook is being run on */
collection: SanitizedCollectionConfig
context: RequestContext
doc: T
/**
* If true, this operation is reading a draft version
*/
draft?: boolean
/**
* Whether access control is being overridden for this operation
*/
Expand All @@ -247,6 +287,10 @@ export type AfterReadHook<T extends TypeWithID = any> = (args: {
collection: SanitizedCollectionConfig
context: RequestContext
doc: T
/**
* If true, this operation is reading a draft version
*/
draft?: boolean
findMany?: boolean
/**
* Whether access control is being overridden for this operation
Expand All @@ -262,6 +306,10 @@ export type BeforeDeleteHook = (args: {
context: RequestContext
id: number | string
req: PayloadRequest
/**
* If true, this operation is a trash/restore operation (soft delete)
*/
trash?: boolean
}) => any

export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
Expand All @@ -271,6 +319,10 @@ export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
doc: T
id: number | string
req: PayloadRequest
/**
* If true, this operation was a trash/restore operation (soft delete)
*/
trash?: boolean
}) => any

export type AfterOperationHook<TOperationGeneric extends CollectionSlug = string> = (
Expand Down Expand Up @@ -776,11 +828,10 @@ export type SanitizedJoins = {
* @todo remove the `DeepRequired` in v4.
* We don't actually guarantee that all properties are set when sanitizing configs.
*/
export interface SanitizedCollectionConfig
extends Omit<
DeepRequired<CollectionConfig>,
'admin' | 'auth' | 'endpoints' | 'fields' | 'folders' | 'slug' | 'upload' | 'versions'
> {
export interface SanitizedCollectionConfig extends Omit<
DeepRequired<CollectionConfig>,
'admin' | 'auth' | 'endpoints' | 'fields' | 'folders' | 'slug' | 'upload' | 'versions'
> {
admin: CollectionAdminOptions
auth: Auth
endpoints: Endpoint[] | false
Expand Down
10 changes: 9 additions & 1 deletion packages/payload/src/collections/operations/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,15 @@ export const createOperation = async <
// beforeValidate - Collections
// /////////////////////////////////////

if (collectionConfig.hooks.beforeValidate?.length) {
if (collectionConfig.hooks?.beforeValidate?.length) {
for (const hook of collectionConfig.hooks.beforeValidate) {
data =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
draft,
operation: 'create',
originalDoc: duplicatedFromDoc,
req,
Expand All @@ -215,9 +217,11 @@ export const createOperation = async <
for (const hook of collectionConfig.hooks.beforeChange) {
data =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
draft,
operation: 'create',
originalDoc: duplicatedFromDoc,
req,
Expand Down Expand Up @@ -384,9 +388,11 @@ export const createOperation = async <
for (const hook of collectionConfig.hooks.afterRead) {
result =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
doc: result,
draft,
overrideAccess,
req,
})) || result
Expand Down Expand Up @@ -416,10 +422,12 @@ export const createOperation = async <
for (const hook of collectionConfig.hooks.afterChange) {
result =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
doc: result,
draft,
operation: 'create',
overrideAccess,
previousDoc: {},
Expand Down
3 changes: 3 additions & 0 deletions packages/payload/src/collections/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export const deleteOperation = async <
collection: collectionConfig,
context: req.context,
req,
trash,
})
}
}
Expand Down Expand Up @@ -263,6 +264,7 @@ export const deleteOperation = async <
collection: collectionConfig,
context: req.context,
doc: result || doc,
draft: undefined,
overrideAccess,
req,
})) || result
Expand All @@ -282,6 +284,7 @@ export const deleteOperation = async <
context: req.context,
doc: result,
req,
trash,
})) || result
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/payload/src/collections/operations/deleteByID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const deleteByIDOperation = async <TSlug extends CollectionSlug, TSelect
collection: collectionConfig,
context: req.context,
req,
trash,
})
}
}
Expand Down Expand Up @@ -240,6 +241,7 @@ export const deleteByIDOperation = async <TSlug extends CollectionSlug, TSelect
collection: collectionConfig,
context: req.context,
doc: result,
draft: undefined,
overrideAccess,
req,
})) || result
Expand All @@ -259,6 +261,7 @@ export const deleteByIDOperation = async <TSlug extends CollectionSlug, TSelect
context: req.context,
doc: result,
req,
trash,
})) || result
}
}
Expand Down
20 changes: 15 additions & 5 deletions packages/payload/src/collections/operations/utilities/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ export const updateDocument = async <
!publishAllLocales
const shouldSavePassword = Boolean(
password &&
collectionConfig.auth &&
(!collectionConfig.auth.disableLocalStrategy ||
(typeof collectionConfig.auth.disableLocalStrategy === 'object' &&
collectionConfig.auth.disableLocalStrategy.enableFields)) &&
!isSavingDraft,
collectionConfig.auth &&
(!collectionConfig.auth.disableLocalStrategy ||
(typeof collectionConfig.auth.disableLocalStrategy === 'object' &&
collectionConfig.auth.disableLocalStrategy.enableFields)) &&
!isSavingDraft,
)

if (isSavingDraft) {
Expand Down Expand Up @@ -202,12 +202,15 @@ export const updateDocument = async <
for (const hook of collectionConfig.hooks.beforeValidate) {
data =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
draft: draftArg,
operation: 'update',
originalDoc,
req,
trash: collectionConfig.trash && (Boolean(data?.deletedAt) || isRestoringDraftFromTrash),
})) || data
}
}
Expand All @@ -228,12 +231,15 @@ export const updateDocument = async <
for (const hook of collectionConfig.hooks.beforeChange) {
data =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
draft: draftArg,
operation: 'update',
originalDoc,
req,
trash: collectionConfig.trash && (Boolean(data?.deletedAt) || isRestoringDraftFromTrash),
})) || data
}
}
Expand Down Expand Up @@ -420,6 +426,7 @@ export const updateDocument = async <
collection: collectionConfig,
context: req.context,
doc: result,
draft: draftArg,
overrideAccess,
req,
})) || result
Expand Down Expand Up @@ -449,14 +456,17 @@ export const updateDocument = async <
for (const hook of collectionConfig.hooks.afterChange) {
result =
(await hook({
autosave,
collection: collectionConfig,
context: req.context,
data,
doc: result,
draft: draftArg,
operation: 'update',
overrideAccess,
previousDoc: originalDoc,
req,
trash: collectionConfig.trash && (Boolean(data?.deletedAt) || isRestoringDraftFromTrash),
})) || result
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/payload/src/fields/config/sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
type Args = {
collectionConfig?: CollectionConfig
config: Config
dbName?: string | false
existingFieldNames?: Set<string>
fields: Field[]
globalConfig?: GlobalConfig
Expand Down Expand Up @@ -357,6 +358,7 @@ export const sanitizeFields = async ({
block.fields = await sanitizeFields({
collectionConfig,
config,
dbName: 'dbName' in field ? field.dbName : undefined,
existingFieldNames: new Set(),
fields: block.fields,
isTopLevelField: false,
Expand All @@ -374,6 +376,7 @@ export const sanitizeFields = async ({
field.fields = await sanitizeFields({
collectionConfig,
config,
dbName: 'dbName' in field ? field.dbName : undefined,
existingFieldNames: fieldAffectsData ? new Set() : existingFieldNames,
fields: field.fields,
isTopLevelField: isTopLevelField && !fieldAffectsData,
Expand Down
Loading
Loading