Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove deprecated hooks #9204

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions .changeset/chilled-moons-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@keystone-6/core": major
---

Removed deprecated list and field hooks.
Fixed field hooks of all the in built types
21 changes: 15 additions & 6 deletions examples/custom-field/2-stars-field/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,22 @@ export const stars =
...config.hooks,
// We use the `validateInput` hook to ensure that the user doesn't set an out of range value.
// This hook is the key difference on the backend between the stars field type and the integer field type.
async validateInput (args) {
const val = args.resolvedData[meta.fieldKey]
if (!(val == null || (val >= 0 && val <= maxStars))) {
args.addValidationError(`The value must be within the range of 0-${maxStars}`)
validate: {
async create (args) {
const val = args.resolvedData[meta.fieldKey]
if (!(val == null || (val >= 0 && val <= maxStars))) {
args.addValidationError(`The value must be within the range of 0-${maxStars}`)
}
await config.hooks?.validate?.create?.(args)
},
async update (args) {
const val = args.resolvedData[meta.fieldKey]
if (!(val == null || (val >= 0 && val <= maxStars))) {
args.addValidationError(`The value must be within the range of 0-${maxStars}`)
}
await config.hooks?.validate?.update?.(args)
}
await config.hooks?.validateInput?.(args)
},
}
},
// all of these inputs are optional if they don't make sense for a particular field type
input: {
Expand Down
82 changes: 59 additions & 23 deletions examples/custom-field/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,58 @@ export const lists = {
},

hooks: {
resolveInput: async ({ resolvedData, operation, inputData, item, fieldKey }) => {
console.log('Post.content.hooks.resolveInput', {
resolveInput: {
create: async ({ resolvedData, operation, inputData, item, fieldKey }) => {
console.log('Post.content.hooks.resolveInput.create', {
resolvedData,
operation,
inputData,
item,
fieldKey,
})
return resolvedData[fieldKey]
},
update: async ({ resolvedData, operation, inputData, item, fieldKey }) => {
console.log('Post.content.hooks.resolveInput.update', {
resolvedData,
operation,
inputData,
item,
fieldKey,
})
return resolvedData[fieldKey]
},
},
validate: {
create: async ({
resolvedData,
operation,
inputData,
item,
addValidationError,
fieldKey,
})
return resolvedData[fieldKey]
},

validateInput: async ({
resolvedData,
inputData,
item,
addValidationError,
fieldKey,
}) => {
console.log('Post.content.hooks.validateInput', {
}) => {
console.log('Post.content.hooks.validateInput.create', {
resolvedData,
inputData,
item,
fieldKey,
})
},
update: async ({
resolvedData,
inputData,
item,
addValidationError,
fieldKey,
})
},
}) => {
console.log('Post.content.hooks.validateInput.update', {
resolvedData,
inputData,
item,
fieldKey,
})
},
}
},
}),
rating: stars({
Expand Down Expand Up @@ -100,13 +127,22 @@ export const lists = {
},
},

validateInput: async ({ resolvedData, operation, inputData, item, addValidationError }) => {
console.log('Post.hooks.validateInput', { resolvedData, operation, inputData, item })
validate: {
create: async ({ resolvedData, operation, inputData, item, addValidationError }) => {
console.log('Post.hooks.validateInput.create', { resolvedData, operation, inputData, item })

if (Math.random() > 0.95) {
addValidationError('oh oh, try again, this is part of the example')
}
},
if (Math.random() > 0.95) {
addValidationError('oh oh, try again, this is part of the example')
}
},
update: async ({ resolvedData, operation, inputData, item, addValidationError }) => {
console.log('Post.hooks.validateInput.update', { resolvedData, operation, inputData, item })

if (Math.random() > 0.95) {
addValidationError('oh oh, try again, this is part of the example')
}
},
}
},
}),
} satisfies Lists
59 changes: 40 additions & 19 deletions examples/custom-output-paths/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,46 @@ export const lists = {
},

hooks: {
afterOperation: async ({ context }) => {
const posts = (await context.db.Post.findMany({
where: {
title: { equals: 'Home' },
},

// we use Typescript's satisfies here as way to ensure that
// this is the contextualised type - you don't need this
//
// it is helpful for us to check that the example is not
// broken by code changes
//

// TODO: FIXME, babel and pnpm issues
})) as readonly { title: string, content: string }[]
// })) satisfies readonly { title: string; content: string }[];

console.log(posts)
},
afterOperation: {
create: async ({ context }) => {
const posts = (await context.db.Post.findMany({
where: {
title: { equals: 'Home' },
},

// we use Typescript's satisfies here as way to ensure that
// this is the contextualised type - you don't need this
//
// it is helpful for us to check that the example is not
// broken by code changes
//

// TODO: FIXME, babel and pnpm issues
})) as readonly { title: string, content: string }[]
// })) satisfies readonly { title: string; content: string }[];

console.log(posts)
},
update: async ({ context }) => {
const posts = (await context.db.Post.findMany({
where: {
title: { equals: 'Home' },
},

// we use Typescript's satisfies here as way to ensure that
// this is the contextualised type - you don't need this
//
// it is helpful for us to check that the example is not
// broken by code changes
//

// TODO: FIXME, babel and pnpm issues
})) as readonly { title: string, content: string }[]
// })) satisfies readonly { title: string; content: string }[];

console.log(posts)
},
}
},
}),
} satisfies Lists
18 changes: 13 additions & 5 deletions examples/custom-session-invalidation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,19 @@ We add one new field, `passwordChangedAt`, to the `Person` list. Setting the `pa
passwordChangedAt: timestamp({
access: () => false,
hooks: {
resolveInput: ({ resolvedData }) => {
if (resolvedData.password) {
return new Date();
}
return;
resolveInput: {
create: ({ resolvedData }) => {
if (resolvedData.password) {
return new Date();
}
return;
},
update: ({ resolvedData }) => {
if (resolvedData.password) {
return new Date();
}
return;
},
},
},
ui: {
Expand Down
98 changes: 68 additions & 30 deletions examples/default-values/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,30 @@ export const lists = {
{ label: 'High', value: 'high' },
],
hooks: {
resolveInput ({ resolvedData, inputData }) {
if (inputData.priority === null) {
// default to high if "urgent" is in the label
if (inputData.label && inputData.label.toLowerCase().includes('urgent')) {
return 'high'
} else {
return 'low'
resolveInput: {
create ({ resolvedData, inputData }) {
if (inputData.priority === null) {
// default to high if "urgent" is in the label
if (inputData.label && inputData.label.toLowerCase().includes('urgent')) {
return 'high'
} else {
return 'low'
}
}
}
return resolvedData.priority
},
return resolvedData.priority
},
update ({ resolvedData, inputData }) {
if (inputData.priority === null) {
// default to high if "urgent" is in the label
if (inputData.label && inputData.label.toLowerCase().includes('urgent')) {
return 'high'
} else {
return 'low'
}
}
return resolvedData.priority
},
}
},
}),

Expand All @@ -39,33 +52,58 @@ export const lists = {
many: false,
hooks: {
// dynamic default: if unassigned, find an anonymous user and assign the task to them
async resolveInput ({ context, operation, resolvedData }) {
if (resolvedData.assignedTo === null) {
const [user] = await context.db.Person.findMany({
where: { name: { equals: 'Anonymous' } },
})

if (user) {
return { connect: { id: user.id } }
resolveInput: {
async create ({ context, operation, resolvedData }) {
if (resolvedData.assignedTo === null) {
const [user] = await context.db.Person.findMany({
where: { name: { equals: 'Anonymous' } },
})

if (user) {
return { connect: { id: user.id } }
}
}
}

return resolvedData.assignedTo
},

return resolvedData.assignedTo
},
async update ({ context, operation, resolvedData }) {
if (resolvedData.assignedTo === null) {
const [user] = await context.db.Person.findMany({
where: { name: { equals: 'Anonymous' } },
})

if (user) {
return { connect: { id: user.id } }
}
}

return resolvedData.assignedTo
},
}
},
}),

// dynamic default: we set the due date to be 7 days in the future
finishBy: timestamp({
hooks: {
resolveInput ({ resolvedData, inputData, operation }) {
if (inputData.finishBy == null) {
const date = new Date()
date.setUTCDate(new Date().getUTCDate() + 7)
return date
}
return resolvedData.finishBy
},
resolveInput: {
create ({ resolvedData, inputData, operation }) {
if (inputData.finishBy == null) {
const date = new Date()
date.setUTCDate(new Date().getUTCDate() + 7)
return date
}
return resolvedData.finishBy
},
update ({ resolvedData, inputData, operation }) {
if (inputData.finishBy == null) {
const date = new Date()
date.setUTCDate(new Date().getUTCDate() + 7)
return date
}
return resolvedData.finishBy
},
}
},
}),

Expand Down
35 changes: 24 additions & 11 deletions examples/extend-graphql-subscriptions/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@ export const lists = {
access: allowAll,
hooks: {
// this hook publishes posts to the 'POST_UPDATED' channel when a post mutated
afterOperation: async ({ item }) => {
// WARNING: passing this item directly to pubSub bypasses any contextual access control
// if you want access control, you need to use a different architecture
//
// tl;dr Keystone access filters are not respected in this scenario
console.log('POST_UPDATED', { id: item?.id })

pubSub.publish('POST_UPDATED', {
postUpdated: item,
})
},
afterOperation: {
create: async ({ item }) => {
// WARNING: passing this item directly to pubSub bypasses any contextual access control
// if you want access control, you need to use a different architecture
//
// tl;dr Keystone access filters are not respected in this scenario
console.log('POST_UPDATED', { id: item?.id })

pubSub.publish('POST_UPDATED', {
postUpdated: item,
})
},
update: async ({ item }) => {
// WARNING: passing this item directly to pubSub bypasses any contextual access control
// if you want access control, you need to use a different architecture
//
// tl;dr Keystone access filters are not respected in this scenario
console.log('POST_UPDATED', { id: item?.id })

pubSub.publish('POST_UPDATED', {
postUpdated: item,
})
},
}
},
fields: {
title: text({ validation: { isRequired: true } }),
Expand Down
Loading
Loading