Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christopherliu/903bdc2175497f5aa1b465e205ae506c to your computer and use it in GitHub Desktop.
Save christopherliu/903bdc2175497f5aa1b465e205ae506c to your computer and use it in GitHub Desktop.
Abstract Cascade Delete Hook for Keystone 6
// "@keystone-6/core": "^1.0.1",
// *******************************************************************
// Adding support for the General Availability release of Keystone 6.
// Only updated cascadeDelete.ts. Haven't updated tests.
// *******************************************************************
// The actual lib
// utils/keystone/cascadeDelete.ts
type Id = NonNullable<any>;
type IdObject = { id: Id };
type HookConfig = {
ref: string
};
// TODO this will probably need further revising to work in Keystone 6.
// Only deleteMany has been tested in a live environment
export const deleteOneBeforeDeleteHook =
({ ref }: HookConfig) =>
async ({
fieldKey,
item,
context,
}) => {
const idPath = fieldKey + "Id";
const id = (item as { [idPath: string]: Id })[idPath];
if (id) await context.lists[ref].deleteOne({ id });
};
export const deleteManyBeforeDeleteHook =
({ ref }: HookConfig) =>
async ({
listKey,
fieldKey,
operation,
item,
context,
}) => {
if (operation !== "delete") {
return;
}
const { id } = item as IdObject;
const parentWithChildren = await context.query[listKey].findOne({
where: { id },
query: `${fieldKey} { id }`,
});
const children = parentWithChildren[fieldKey] as [IdObject] | undefined;
await context.query[ref.split(".")[0]].deleteMany({ where: children });
};
// Usage examples
// lists/test/oneToMany.ts
import { list } from "@keystone-next/keystone/schema"
import { relationship, text } from "@keystone-next/fields"
import { deleteManyBeforeDeleteHook } from "../../utils/keystone/cascadeDelete"
const TestHorseOTM = list({
fields: {
name: text(),
},
})
const TestRiderOTM = list({
fields: {
name: text(),
horses: relationship({
ref: "TestHorseOTM",
many: true,
hooks: {
beforeOperation: deleteManyBeforeDeleteHook({ ref: "TestHorseOTM" }),
},
}),
},
})
export const testOneToManyList = { TestRiderOTM, TestHorseOTM }
// lists/test/oneToOne.ts
import { list } from "@keystone-next/keystone/schema"
import { relationship, text } from "@keystone-next/fields"
import { deleteOneBeforeDeleteHook } from "../../utils/keystone/cascadeDelete"
const TestRiderOTO = list({
fields: {
name: text(),
},
})
const TestHorseOTO = list({
fields: {
name: text(),
rider: relationship({
ref: "TestRiderOTO",
hooks: {
beforeOperation: deleteOneBeforeDeleteHook({ ref: "TestRiderOTO" }),
},
}),
},
})
export const testOneToOneList = { TestRiderOTO, TestHorseOTO }
// Tests
// cascadeDeleteOneToOne.test.ts
import { setupTestRunner } from "@keystone-next/testing"
import config from "./../keystone"
const runner = setupTestRunner({ config })
describe("One to One", () => {
it(
"Delete",
runner(async ({ context }) => {
const createRider = { name: "Roger" }
const createHorse = {
name: "Jumpy",
rider: { create: createRider },
}
const horse = await context.lists.TestHorseOTO.createOne({
data: createHorse,
query: "id rider { name }",
})
expect(horse).toMatchInlineSnapshot(
{
id: expect.any(String),
},
`
Object {
"id": Any<String>,
"rider": Object {
"name": "Roger",
},
}
`,
)
await context.lists.TestHorseOTO.deleteOne({ id: horse.id })
expect(await context.lists.TestRiderOTO.findMany()).toEqual([])
}),
)
})
// cascadeDeleteOneToMany.test.ts
import { setupTestRunner } from "@keystone-next/testing"
import config from "./../keystone"
const runner = setupTestRunner({ config })
describe("One to Many", () => {
it(
"Delete",
runner(async ({ context }) => {
const createHorses = [{ name: "Jumpy" }]
const createRider = {
name: "Roger",
horses: { create: createHorses },
}
const rider = await context.lists.TestRiderOTM.createOne({
data: createRider,
query: "id horses { name }",
})
expect(rider).toMatchInlineSnapshot(
{
id: expect.any(String),
},
`
Object {
"horses": Array [
Object {
"name": "Jumpy",
},
],
"id": Any<String>,
}
`,
)
await context.lists.TestRiderOTM.deleteOne({ id: rider.id })
expect(await context.lists.TestHorseOTM.findMany()).toEqual([])
}),
)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment