Skip to content

Commit 77bfd2c

Browse files
gautamsiemmatowndcousens
authored
Remove deprecated hooks (#9204)
Co-authored-by: Emma Hamilton <[email protected]> Co-authored-by: Daniel Cousens <[email protected]>
1 parent e3e1f8d commit 77bfd2c

File tree

26 files changed

+302
-377
lines changed

26 files changed

+302
-377
lines changed

.changeset/chilled-moons-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@keystone-6/core": major
3+
---
4+
5+
Removed deprecated `validateInput` and `validateDelete` hooks and add object hook syntax to fields.

examples/custom-field/2-stars-field/index.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ export function stars <ListTypeInfo extends BaseListTypeInfo> ({
2222
maxStars = 5,
2323
...config
2424
}: StarsFieldConfig<ListTypeInfo> = {}): FieldTypeFunc<ListTypeInfo> {
25+
const validateCreate = typeof config.hooks?.validate === 'function' ? config.hooks.validate : config.hooks?.validate?.create
26+
const validateUpdate = typeof config.hooks?.validate === 'function' ? config.hooks.validate : config.hooks?.validate?.update
27+
28+
function validate (v: unknown) {
29+
if (v === null) return
30+
if (typeof v === 'number' && v >= 0 && v <= maxStars) return
31+
return `The value must be within the range of 0-${maxStars}`
32+
}
33+
2534
return meta =>
2635
fieldType({
2736
// this configures what data is stored in the database
@@ -34,15 +43,21 @@ export function stars <ListTypeInfo extends BaseListTypeInfo> ({
3443
...config,
3544
hooks: {
3645
...config.hooks,
37-
// We use the `validateInput` hook to ensure that the user doesn't set an out of range value.
46+
// We use the `validate` hooks to ensure that the user doesn't set an out of range value.
3847
// This hook is the key difference on the backend between the stars field type and the integer field type.
39-
async validateInput (args) {
40-
const val = args.resolvedData[meta.fieldKey]
41-
if (!(val == null || (val >= 0 && val <= maxStars))) {
42-
args.addValidationError(`The value must be within the range of 0-${maxStars}`)
48+
validate: {
49+
...config.hooks?.validate,
50+
async create (args) {
51+
const err = validate(args.resolvedData[meta.fieldKey])
52+
if (err) args.addValidationError(err)
53+
await validateCreate?.(args)
54+
},
55+
async update (args) {
56+
const err = validate(args.resolvedData[meta.fieldKey])
57+
if (err) args.addValidationError(err)
58+
await validateUpdate?.(args)
4359
}
44-
await config.hooks?.validateInput?.(args)
45-
},
60+
}
4661
},
4762
// all of these inputs are optional if they don't make sense for a particular field type
4863
input: {
@@ -53,16 +68,12 @@ export function stars <ListTypeInfo extends BaseListTypeInfo> ({
5368
// this function can be omitted, it is here purely to show how you could change it
5469
resolve (val, context) {
5570
// if it's null, then the value will be set to null in the database
56-
if (val === null) {
57-
return null
58-
}
71+
if (val === null) return null
5972
// if it's undefined(which means that it was omitted in the request)
6073
// returning undefined will mean "don't change the existing value"
6174
// note that this means that this function is called on every update to an item
6275
// including when the field is not updated
63-
if (val === undefined) {
64-
return undefined
65-
}
76+
if (val === undefined) return undefined
6677
// if it's not null or undefined, it must be a number
6778
return val
6879
},

examples/custom-field/schema.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ export const lists = {
3131
return resolvedData[fieldKey]
3232
},
3333

34-
validateInput: async ({
34+
validate: async ({
3535
resolvedData,
3636
inputData,
3737
item,
3838
addValidationError,
3939
fieldKey,
4040
}) => {
41-
console.log('Post.content.hooks.validateInput', {
41+
console.log('Post.content.hooks.validate', {
4242
resolvedData,
4343
inputData,
4444
item,
@@ -100,8 +100,8 @@ export const lists = {
100100
},
101101
},
102102

103-
validateInput: async ({ resolvedData, operation, inputData, item, addValidationError }) => {
104-
console.log('Post.hooks.validateInput', { resolvedData, operation, inputData, item })
103+
validate: async ({ resolvedData, operation, inputData, item, addValidationError }) => {
104+
console.log('Post.hooks.validate', { resolvedData, operation, inputData, item })
105105

106106
if (Math.random() > 0.95) {
107107
addValidationError('oh oh, try again, this is part of the example')

examples/field-groups/schema.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,12 @@ export const lists = {
2626
// for this example, we are going to use a hook for fun
2727
// defaultValue: { kind: 'now' }
2828
hooks: {
29-
resolveInput: ({ context, operation, resolvedData }) => {
30-
// TODO: text should allow you to prevent a defaultValue, then Prisma create could be non-null
31-
// if (operation === 'create') return resolvedData.title.replace(/ /g, '-').toLowerCase()
32-
if (operation === 'create') {
33-
return resolvedData.title?.replace(/ /g, '-').toLowerCase()
34-
}
35-
36-
return resolvedData.slug
37-
},
29+
resolveInput: {
30+
create: ({ context, operation, resolvedData }) => {
31+
// TODO: text should allow you to prevent a defaultValue, then Prisma create could be non-null
32+
return resolvedData.title?.replace(/ /g, '-').toLowerCase()
33+
},
34+
}
3835
},
3936
}),
4037
},

examples/hooks/schema.ts

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,10 @@ export const lists = {
7878
// defaultValue: { kind: 'now' }
7979

8080
hooks: {
81-
resolveInput: ({ context, operation, resolvedData }) => {
82-
if (operation === 'create') return new Date()
83-
return resolvedData.createdAt
84-
},
85-
},
86-
87-
// TODO: this would be nice
88-
// hooks: {
89-
// resolveInput: {
90-
// create: () => new Date()
91-
// }
92-
// }
81+
resolveInput: {
82+
create: () => new Date()
83+
}
84+
}
9385
}),
9486

9587
updatedBy: text({ ...readOnly }),
@@ -102,18 +94,10 @@ export const lists = {
10294
// },
10395

10496
hooks: {
105-
resolveInput: ({ context, operation, resolvedData }) => {
106-
if (operation === 'update') return new Date()
107-
return resolvedData.updatedAt
108-
},
109-
},
110-
111-
// TODO: this would be nice
112-
// hooks: {
113-
// resolveInput: {
114-
// update: () => new Date()
115-
// }
116-
// }
97+
resolveInput: {
98+
update: () => new Date()
99+
}
100+
}
117101
}),
118102
},
119103
}),
@@ -131,29 +115,37 @@ export const lists = {
131115
return resolvedData
132116
},
133117
},
134-
validateInput: ({ context, operation, inputData, addValidationError }) => {
135-
const { title, content } = inputData
136-
137-
if (operation === 'update' && 'feedback' in inputData) {
138-
const { feedback } = inputData
139-
if (/profanity/i.test(feedback ?? '')) return addValidationError('Unacceptable feedback')
140-
}
118+
validate: {
119+
create: ({ inputData, addValidationError }) => {
120+
const { title, content } = inputData
121+
122+
123+
// an example of a content filter, the prevents the title or content containing the word "Profanity"
124+
if (/profanity/i.test(title)) return addValidationError('Unacceptable title')
125+
if (/profanity/i.test(content)) return addValidationError('Unacceptable content')
126+
},
127+
update: ({ inputData, addValidationError }) => {
128+
const { title, content } = inputData
141129

142-
// an example of a content filter, the prevents the title or content containing the word "Profanity"
143-
if (/profanity/i.test(title)) return addValidationError('Unacceptable title')
144-
if (/profanity/i.test(content)) return addValidationError('Unacceptable content')
145-
},
146-
validateDelete: ({ context, item, addValidationError }) => {
147-
const { preventDelete } = item
130+
if ('feedback' in inputData) {
131+
const { feedback } = inputData
132+
if (/profanity/i.test(feedback ?? '')) return addValidationError('Unacceptable feedback')
133+
}
148134

149-
// an example of a content filter, the prevents the title or content containing the word "Profanity"
150-
if (preventDelete) return addValidationError('Cannot delete Post, preventDelete is true')
135+
// an example of a content filter, the prevents the title or content containing the word "Profanity"
136+
if (/profanity/i.test(title)) return addValidationError('Unacceptable title')
137+
if (/profanity/i.test(content)) return addValidationError('Unacceptable content')
138+
},
139+
delete: ({ context, item, addValidationError }) => {
140+
const { preventDelete } = item
141+
142+
// an example of a content filter, the prevents the title or content containing the word "Profanity"
143+
if (preventDelete) return addValidationError('Cannot delete Post, preventDelete is true')
144+
},
151145
},
152-
153146
beforeOperation: ({ item, resolvedData, operation }) => {
154147
console.log(`Post beforeOperation.${operation}`, resolvedData)
155148
},
156-
157149
afterOperation: {
158150
create: ({ inputData, item }) => {
159151
console.log(`Post afterOperation.create`, inputData, '->', item)
@@ -162,7 +154,6 @@ export const lists = {
162154
update: ({ originalItem, item }) => {
163155
console.log(`Post afterOperation.update`, originalItem, '->', item)
164156
},
165-
166157
delete: ({ originalItem }) => {
167158
console.log(`Post afterOperation.delete`, originalItem, '-> deleted')
168159
},

examples/reuse/schema.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,23 @@ function trackingByHooks<
5555
// FieldKey extends 'createdBy' | 'updatedBy' // TODO: refined types for the return types
5656
> (immutable: boolean = false): FieldHooks<ListTypeInfo> {
5757
return {
58-
async resolveInput ({ context, operation, resolvedData, item, fieldKey }) {
59-
if (operation === 'update') {
58+
resolveInput: {
59+
async create ({ context, operation, resolvedData, item, fieldKey }) {
60+
// TODO: refined types for the return types
61+
// FIXME: CommonFieldConfig need not always be generalised
62+
return `${context.req?.socket.remoteAddress} (${context.req?.headers['user-agent']})` as any
63+
},
64+
async update ({ context, operation, resolvedData, item, fieldKey }) {
6065
if (immutable) return undefined
6166

6267
// show we have refined types for compatible item.* fields
6368
if (isTrue(item.completed) && resolvedData.completed !== false) return undefined
64-
}
65-
66-
// TODO: refined types for the return types
67-
// FIXME: CommonFieldConfig need not always be generalised
68-
return `${context.req?.socket.remoteAddress} (${context.req?.headers['user-agent']})` as any
69-
},
69+
70+
// TODO: refined types for the return types
71+
// FIXME: CommonFieldConfig need not always be generalised
72+
return `${context.req?.socket.remoteAddress} (${context.req?.headers['user-agent']})` as any
73+
},
74+
}
7075
}
7176
}
7277

@@ -76,18 +81,23 @@ function trackingAtHooks<
7681
> (immutable: boolean = false): FieldHooks<ListTypeInfo> {
7782
return {
7883
// TODO: switch to operation routing when supported for fields
79-
async resolveInput ({ context, operation, resolvedData, item, fieldKey }) {
80-
if (operation === 'update') {
84+
resolveInput: {
85+
async create ({ context, operation, resolvedData, item, fieldKey }) {
86+
// TODO: refined types for the return types
87+
// FIXME: CommonFieldConfig need not always be generalised
88+
return new Date() as any
89+
},
90+
async update ({ context, operation, resolvedData, item, fieldKey }) {
8191
if (immutable) return undefined
8292

8393
// show we have refined types for compatible item.* fields
8494
if (isTrue(item.completed) && resolvedData.completed !== false) return undefined
85-
}
8695

87-
// TODO: refined types for the return types
88-
// FIXME: CommonFieldConfig need not always be generalised
89-
return new Date() as any
90-
},
96+
// TODO: refined types for the return types
97+
// FIXME: CommonFieldConfig need not always be generalised
98+
return new Date() as any
99+
},
100+
}
91101
}
92102
}
93103

examples/usecase-roles/schema.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,17 @@ export const lists: Lists<Session> = {
6969
},
7070
},
7171
hooks: {
72-
resolveInput ({ operation, resolvedData, context }) {
73-
if (operation === 'create' && !resolvedData.assignedTo && context.session) {
74-
// Always default new todo items to the current user; this is important because users
75-
// without canManageAllTodos don't see this field when creating new items
76-
return { connect: { id: context.session.itemId } }
72+
resolveInput: {
73+
create ({ operation, resolvedData, context }) {
74+
if (!resolvedData.assignedTo && context.session) {
75+
// Always default new todo items to the current user; this is important because users
76+
// without canManageAllTodos don't see this field when creating new items
77+
return { connect: { id: context.session.itemId } }
78+
}
79+
return resolvedData.assignedTo
7780
}
78-
return resolvedData.assignedTo
7981
},
80-
},
82+
}
8183
}),
8284
},
8385
}),

examples/usecase-versioning/schema.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ export const lists = {
2727
},
2828
},
2929
hooks: {
30-
resolveInput: async ({ resolvedData, operation, item }) => {
31-
if (operation === 'create') return resolvedData.version
32-
if (resolvedData.version !== item.version) throw new Error('Out of sync')
33-
34-
return item.version + 1
30+
resolveInput: {
31+
update: async ({ resolvedData, operation, item }) => {
32+
if (resolvedData.version !== item.version) throw new Error('Out of sync')
33+
34+
return item.version + 1
35+
},
3536
},
3637
},
3738
}),

packages/core/src/fields/non-null-graphql.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {
22
type BaseListTypeInfo,
33
type FieldData,
44
} from '../types'
5+
import type { FieldHooks } from '../types/config/hooks'
56
import {
67
type ValidateFieldHook
78
} from '../types/config/hooks'
9+
import { merge } from './resolve-hooks'
810

911
export function resolveDbNullable (
1012
validation: undefined | { isRequired?: boolean },
@@ -33,6 +35,9 @@ export function makeValidateHook <ListTypeInfo extends BaseListTypeInfo> (
3335
isRequired?: boolean
3436
[key: string]: unknown
3537
}
38+
hooks?: {
39+
validate?: FieldHooks<ListTypeInfo>['validate']
40+
}
3641
},
3742
f?: ValidateFieldHook<ListTypeInfo, 'create' | 'update' | 'delete', ListTypeInfo['fields']>
3843
) {
@@ -61,13 +66,13 @@ export function makeValidateHook <ListTypeInfo extends BaseListTypeInfo> (
6166

6267
return {
6368
mode,
64-
validate,
69+
validate: merge(validate, config.hooks?.validate)
6570
}
6671
}
6772

6873
return {
6974
mode,
70-
validate: f
75+
validate: merge(f, config.hooks?.validate)
7176
}
7277
}
7378

0 commit comments

Comments
 (0)