From 6c6ac9a712e869a4a6b1b14abeb1ff2887ebb65b Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:32:54 +1000 Subject: [PATCH 1/4] add examples/usecase-relationship-union --- examples/usecase-relationship-union/README.md | 38 ++ .../usecase-relationship-union/keystone.ts | 15 + .../usecase-relationship-union/package.json | 20 ++ .../sandbox.config.json | 7 + .../usecase-relationship-union/schema.graphql | 338 ++++++++++++++++++ .../usecase-relationship-union/schema.prisma | 39 ++ examples/usecase-relationship-union/schema.ts | 114 ++++++ .../usecase-versioning/sandbox.config.json | 2 +- pnpm-lock.yaml | 16 + 9 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 examples/usecase-relationship-union/README.md create mode 100644 examples/usecase-relationship-union/keystone.ts create mode 100644 examples/usecase-relationship-union/package.json create mode 100644 examples/usecase-relationship-union/sandbox.config.json create mode 100644 examples/usecase-relationship-union/schema.graphql create mode 100644 examples/usecase-relationship-union/schema.prisma create mode 100644 examples/usecase-relationship-union/schema.ts diff --git a/examples/usecase-relationship-union/README.md b/examples/usecase-relationship-union/README.md new file mode 100644 index 00000000000..e4e2e0222c5 --- /dev/null +++ b/examples/usecase-relationship-union/README.md @@ -0,0 +1,38 @@ +## Base Project - Versioning + +This project demonstrates a Posts list where a particular field is always required to be sent in a GraphQL request; this can useful for optimistic locking and versioning. + +Use it as a starting place for learning how to use Keystone. + +## Instructions + +To run this project, clone the Keystone repository locally, run `pnpm` at the root of this repository, then navigate to this directory and run: + +```shell +pnpm dev +``` + +This will start the Admin UI at [localhost:3000](http://localhost:3000). +You can use the Admin UI to create items in your database. + +You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. + +Congratulations, you're now up and running with Keystone! 🚀 + +### Optional: add sample data + +This example includes sample data. To add it to your database: + +1. Ensure you’ve initialised your project with `pnpm dev` at least once. +2. Run `pnpm seed-data`. This will populate your database with sample content. +3. Run `pnpm dev` again to startup Admin UI with sample data in place. + +## Try it out in CodeSandbox 🧪 + +You can play with this example online in a web browser using the free [codesandbox.io](https://codesandbox.io/) service. To launch this example, open the URL . You can also fork this sandbox to make your own changes. + +## Next steps + +Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground. + +When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level. diff --git a/examples/usecase-relationship-union/keystone.ts b/examples/usecase-relationship-union/keystone.ts new file mode 100644 index 00000000000..291206afbcc --- /dev/null +++ b/examples/usecase-relationship-union/keystone.ts @@ -0,0 +1,15 @@ +import { config } from '@keystone-6/core'; +import { fixPrismaPath } from '../example-utils'; +import { lists } from './schema'; +import { TypeInfo } from '.keystone/types'; + +export default config({ + db: { + provider: 'sqlite', + url: process.env.DATABASE_URL || 'file:./keystone-example.db', + + // WARNING: this is only needed for our monorepo examples, dont do this + ...fixPrismaPath, + }, + lists, +}); diff --git a/examples/usecase-relationship-union/package.json b/examples/usecase-relationship-union/package.json new file mode 100644 index 00000000000..0c060eadb8a --- /dev/null +++ b/examples/usecase-relationship-union/package.json @@ -0,0 +1,20 @@ +{ + "name": "@keystone-6/example-usecase-relationship-union", + "version": "0.0.1", + "private": true, + "license": "MIT", + "scripts": { + "dev": "keystone dev", + "start": "keystone start", + "build": "keystone build", + "postinstall": "keystone postinstall" + }, + "dependencies": { + "@keystone-6/core": "^5.0.0", + "@prisma/client": "^4.16.2" + }, + "devDependencies": { + "prisma": "^4.16.2", + "typescript": "~5.0.0" + } +} diff --git a/examples/usecase-relationship-union/sandbox.config.json b/examples/usecase-relationship-union/sandbox.config.json new file mode 100644 index 00000000000..ecd53f91829 --- /dev/null +++ b/examples/usecase-relationship-union/sandbox.config.json @@ -0,0 +1,7 @@ +{ + "template": "node", + "container": { + "startScript": "keystone dev", + "node": "18" + } +} diff --git a/examples/usecase-relationship-union/schema.graphql b/examples/usecase-relationship-union/schema.graphql new file mode 100644 index 00000000000..54ea2fbb059 --- /dev/null +++ b/examples/usecase-relationship-union/schema.graphql @@ -0,0 +1,338 @@ +# This file is automatically generated by Keystone, do not modify it manually. +# Modify your Keystone config when you want to change this. + +type Post { + id: ID! + title: String + content: String +} + +input PostWhereUniqueInput { + id: ID +} + +input PostWhereInput { + AND: [PostWhereInput!] + OR: [PostWhereInput!] + NOT: [PostWhereInput!] + id: IDFilter + title: StringFilter + content: StringFilter +} + +input IDFilter { + equals: ID + in: [ID!] + notIn: [ID!] + lt: ID + lte: ID + gt: ID + gte: ID + not: IDFilter +} + +input StringFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringFilter +} + +input NestedStringFilter { + equals: String + in: [String!] + notIn: [String!] + lt: String + lte: String + gt: String + gte: String + contains: String + startsWith: String + endsWith: String + not: NestedStringFilter +} + +input PostOrderByInput { + id: OrderDirection + title: OrderDirection + content: OrderDirection +} + +enum OrderDirection { + asc + desc +} + +input PostUpdateInput { + title: String + content: String +} + +input PostUpdateArgs { + where: PostWhereUniqueInput! + data: PostUpdateInput! +} + +input PostCreateInput { + title: String + content: String +} + +type Link { + id: ID! + title: String + url: String +} + +input LinkWhereUniqueInput { + id: ID +} + +input LinkWhereInput { + AND: [LinkWhereInput!] + OR: [LinkWhereInput!] + NOT: [LinkWhereInput!] + id: IDFilter + title: StringFilter + url: StringFilter +} + +input LinkOrderByInput { + id: OrderDirection + title: OrderDirection + url: OrderDirection +} + +input LinkUpdateInput { + title: String + url: String +} + +input LinkUpdateArgs { + where: LinkWhereUniqueInput! + data: LinkUpdateInput! +} + +input LinkCreateInput { + title: String + url: String +} + +type Media { + id: ID! + label: String + description: String + post: Post + link: Link +} + +input MediaWhereUniqueInput { + id: ID +} + +input MediaWhereInput { + AND: [MediaWhereInput!] + OR: [MediaWhereInput!] + NOT: [MediaWhereInput!] + id: IDFilter + description: StringFilter + post: PostWhereInput + link: LinkWhereInput +} + +input MediaOrderByInput { + id: OrderDirection + description: OrderDirection +} + +input MediaUpdateInput { + description: String + post: PostRelateToOneForUpdateInput + link: LinkRelateToOneForUpdateInput +} + +input PostRelateToOneForUpdateInput { + create: PostCreateInput + connect: PostWhereUniqueInput + disconnect: Boolean +} + +input LinkRelateToOneForUpdateInput { + create: LinkCreateInput + connect: LinkWhereUniqueInput + disconnect: Boolean +} + +input MediaUpdateArgs { + where: MediaWhereUniqueInput! + data: MediaUpdateInput! +} + +input MediaCreateInput { + description: String + post: PostRelateToOneForCreateInput + link: LinkRelateToOneForCreateInput +} + +input PostRelateToOneForCreateInput { + create: PostCreateInput + connect: PostWhereUniqueInput +} + +input LinkRelateToOneForCreateInput { + create: LinkCreateInput + connect: LinkWhereUniqueInput +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +type Mutation { + createPost(data: PostCreateInput!): Post + createPosts(data: [PostCreateInput!]!): [Post] + updatePost(where: PostWhereUniqueInput!, data: PostUpdateInput!): Post + updatePosts(data: [PostUpdateArgs!]!): [Post] + deletePost(where: PostWhereUniqueInput!): Post + deletePosts(where: [PostWhereUniqueInput!]!): [Post] + createLink(data: LinkCreateInput!): Link + createLinks(data: [LinkCreateInput!]!): [Link] + updateLink(where: LinkWhereUniqueInput!, data: LinkUpdateInput!): Link + updateLinks(data: [LinkUpdateArgs!]!): [Link] + deleteLink(where: LinkWhereUniqueInput!): Link + deleteLinks(where: [LinkWhereUniqueInput!]!): [Link] + createMedia(data: MediaCreateInput!): Media + createMedias(data: [MediaCreateInput!]!): [Media] + updateMedia(where: MediaWhereUniqueInput!, data: MediaUpdateInput!): Media + updateMedias(data: [MediaUpdateArgs!]!): [Media] + deleteMedia(where: MediaWhereUniqueInput!): Media + deleteMedias(where: [MediaWhereUniqueInput!]!): [Media] +} + +type Query { + posts(where: PostWhereInput! = {}, orderBy: [PostOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: PostWhereUniqueInput): [Post!] + post(where: PostWhereUniqueInput!): Post + postsCount(where: PostWhereInput! = {}): Int + links(where: LinkWhereInput! = {}, orderBy: [LinkOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: LinkWhereUniqueInput): [Link!] + link(where: LinkWhereUniqueInput!): Link + linksCount(where: LinkWhereInput! = {}): Int + medias(where: MediaWhereInput! = {}, orderBy: [MediaOrderByInput!]! = [], take: Int, skip: Int! = 0, cursor: MediaWhereUniqueInput): [Media!] + media(where: MediaWhereUniqueInput!): Media + mediasCount(where: MediaWhereInput! = {}): Int + keystone: KeystoneMeta! +} + +type KeystoneMeta { + adminMeta: KeystoneAdminMeta! +} + +type KeystoneAdminMeta { + lists: [KeystoneAdminUIListMeta!]! + list(key: String!): KeystoneAdminUIListMeta +} + +type KeystoneAdminUIListMeta { + key: String! + itemQueryName: String! + listQueryName: String! + hideCreate: Boolean! + hideDelete: Boolean! + path: String! + label: String! + singular: String! + plural: String! + description: String + initialColumns: [String!]! + pageSize: Int! + labelField: String! + fields: [KeystoneAdminUIFieldMeta!]! + groups: [KeystoneAdminUIFieldGroupMeta!]! + initialSort: KeystoneAdminUISort + isHidden: Boolean! + isSingleton: Boolean! +} + +type KeystoneAdminUIFieldMeta { + path: String! + label: String! + description: String + isOrderable: Boolean! + isFilterable: Boolean! + isNonNull: [KeystoneAdminUIFieldMetaIsNonNull!] + fieldMeta: JSON + viewsIndex: Int! + customViewsIndex: Int + createView: KeystoneAdminUIFieldMetaCreateView! + listView: KeystoneAdminUIFieldMetaListView! + itemView(id: ID): KeystoneAdminUIFieldMetaItemView + search: QueryMode +} + +enum KeystoneAdminUIFieldMetaIsNonNull { + read + create + update +} + +type KeystoneAdminUIFieldMetaCreateView { + fieldMode: KeystoneAdminUIFieldMetaCreateViewFieldMode! +} + +enum KeystoneAdminUIFieldMetaCreateViewFieldMode { + edit + hidden +} + +type KeystoneAdminUIFieldMetaListView { + fieldMode: KeystoneAdminUIFieldMetaListViewFieldMode! +} + +enum KeystoneAdminUIFieldMetaListViewFieldMode { + read + hidden +} + +type KeystoneAdminUIFieldMetaItemView { + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode + fieldPosition: KeystoneAdminUIFieldMetaItemViewFieldPosition +} + +enum KeystoneAdminUIFieldMetaItemViewFieldMode { + edit + read + hidden +} + +enum KeystoneAdminUIFieldMetaItemViewFieldPosition { + form + sidebar +} + +enum QueryMode { + default + insensitive +} + +type KeystoneAdminUIFieldGroupMeta { + label: String! + description: String + fields: [KeystoneAdminUIFieldMeta!]! +} + +type KeystoneAdminUISort { + field: String! + direction: KeystoneAdminUISortDirection! +} + +enum KeystoneAdminUISortDirection { + ASC + DESC +} diff --git a/examples/usecase-relationship-union/schema.prisma b/examples/usecase-relationship-union/schema.prisma new file mode 100644 index 00000000000..c07b5ab1e5e --- /dev/null +++ b/examples/usecase-relationship-union/schema.prisma @@ -0,0 +1,39 @@ +// This file is automatically generated by Keystone, do not modify it manually. +// Modify your Keystone config when you want to change this. + +datasource sqlite { + url = env("DATABASE_URL") + shadowDatabaseUrl = env("SHADOW_DATABASE_URL") + provider = "sqlite" +} + +generator client { + provider = "prisma-client-js" + output = "node_modules/.myprisma/client" +} + +model Post { + id String @id @default(cuid()) + title String @default("") + content String @default("") + from_Media_post Media[] @relation("Media_post") +} + +model Link { + id String @id @default(cuid()) + title String @default("") + url String @default("") + from_Media_link Media[] @relation("Media_link") +} + +model Media { + id String @id @default(cuid()) + description String @default("") + post Post? @relation("Media_post", fields: [postId], references: [id]) + postId String? @map("post") + link Link? @relation("Media_link", fields: [linkId], references: [id]) + linkId String? @map("link") + + @@index([postId]) + @@index([linkId]) +} diff --git a/examples/usecase-relationship-union/schema.ts b/examples/usecase-relationship-union/schema.ts new file mode 100644 index 00000000000..f605e2b7c52 --- /dev/null +++ b/examples/usecase-relationship-union/schema.ts @@ -0,0 +1,114 @@ +import { list, graphql } from '@keystone-6/core'; +import { allowAll } from '@keystone-6/core/access'; +import { text, relationship, virtual } from '@keystone-6/core/fields'; +import { Lists } from '.keystone/types'; + +function ifUnsetHideUI (field: string, mode = 'edit' as const) { + return { + itemView: { + fieldMode: ({ item }: any) => item[field] ? mode : 'hidden', + }, + listView: { + fieldMode: () => 'hidden' as const, + }, + } +} + +export const lists: Lists = { + Post: list({ + access: allowAll, + fields: { + title: text(), + content: text(), + }, + }), + + Link: list({ + access: allowAll, + fields: { + title: text(), + url: text(), + }, + }), + + // an unoptimised union relationship list type, each item represents only a Post, or a Link + Media: list({ + access: allowAll, + graphql: { + plural: 'Medias' + }, + fields: { + label: virtual({ + field: graphql.field({ + type: graphql.String, + resolve: async (item, _, context) => { + const { postId, linkId } = item; + if (postId) return (await context.db.Post.findOne({ where: { id: postId } }))?.title ?? '[missing]'; + if (linkId) return (await context.db.Link.findOne({ where: { id: linkId } }))?.title ?? '[missing]'; + return '?'; + }, + }), + }), + description: text(), + + post: relationship({ + ref: 'Post', + ui: { + ...ifUnsetHideUI('postId') + } + }), + + link: relationship({ + ref: 'Link', + ui: { + ...ifUnsetHideUI('linkId') + } + }), + }, + + hooks: { + validateInput: async ({ operation, inputData, addValidationError }) => { + if (operation === 'create') { + const { post, link } = inputData; + const values = [post, link].filter(x => x?.connect ?? x?.create) + if (values.length === 0) { + return addValidationError('A relationship is required') + } + } + + if (operation === 'update') { + const { post, link } = inputData; + if ([post, link].some(x => x?.disconnect)) { + return addValidationError('Cannot change relationship type') + } + + const values = [post, link].filter(x => x?.connect ?? x?.create) + if (values.length > 1) { + addValidationError('Only one relationship at a time') + } + + // TODO: prevent item from changing types with implicit disconnect + } + }, + resolveInput: { + update: async ({ context, operation, resolvedData }) => { + const { post, link, ...rest } = resolvedData; + for (const [key, value] of Object.entries({ post, link })) { + if (!value) continue + if (value.disconnect) continue // TODO: null should disconnect + + // disconnect everything else + return { + ...rest, + post: { disconnect: true }, + link: { disconnect: true }, + [key]: value + } + } + + return rest + } + } + } + }), +}; diff --git a/examples/usecase-versioning/sandbox.config.json b/examples/usecase-versioning/sandbox.config.json index e26e2dbe04f..ecd53f91829 100644 --- a/examples/usecase-versioning/sandbox.config.json +++ b/examples/usecase-versioning/sandbox.config.json @@ -2,6 +2,6 @@ "template": "node", "container": { "startScript": "keystone dev", - "node": "14" + "node": "18" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1acb9df994d..8a00980f549 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1731,6 +1731,22 @@ importers: specifier: ~5.0.0 version: 5.0.2 + examples/usecase-relationship-union: + dependencies: + '@keystone-6/core': + specifier: ^5.0.0 + version: link:../../packages/core + '@prisma/client': + specifier: ^4.16.2 + version: 4.16.2(prisma@4.16.2) + devDependencies: + prisma: + specifier: ^4.16.2 + version: 4.16.2 + typescript: + specifier: ~5.0.0 + version: 5.0.2 + examples/usecase-roles: dependencies: '@keystone-6/auth': From c588bff0702f4b70c0f802348f20b10af993678a Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:57:56 +1000 Subject: [PATCH 2/4] add missing error for create and group --- examples/usecase-relationship-union/schema.ts | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/examples/usecase-relationship-union/schema.ts b/examples/usecase-relationship-union/schema.ts index f605e2b7c52..76c3e628eab 100644 --- a/examples/usecase-relationship-union/schema.ts +++ b/examples/usecase-relationship-union/schema.ts @@ -1,12 +1,12 @@ -import { list, graphql } from '@keystone-6/core'; +import { list, group, graphql } from '@keystone-6/core'; import { allowAll } from '@keystone-6/core/access'; import { text, relationship, virtual } from '@keystone-6/core/fields'; import { Lists } from '.keystone/types'; -function ifUnsetHideUI (field: string, mode = 'edit' as const) { +function ifUnsetHideUI (field: string) { return { itemView: { - fieldMode: ({ item }: any) => item[field] ? mode : 'hidden', + fieldMode: ({ item }: any) => item[field] ? 'edit' : 'read', }, listView: { fieldMode: () => 'hidden' as const, @@ -51,19 +51,24 @@ export const lists: Lists = { }), description: text(), - post: relationship({ - ref: 'Post', - ui: { - ...ifUnsetHideUI('postId') - } - }), + ...group({ + label: 'Media Type', + fields: { + post: relationship({ + ref: 'Post', + ui: { + ...ifUnsetHideUI('postId') + } + }), - link: relationship({ - ref: 'Link', - ui: { - ...ifUnsetHideUI('linkId') + link: relationship({ + ref: 'Link', + ui: { + ...ifUnsetHideUI('linkId') + } + }), } - }), + }) }, hooks: { @@ -74,6 +79,9 @@ export const lists: Lists = { if (values.length === 0) { return addValidationError('A relationship is required') } + if (values.length > 1) { + return addValidationError('Only one relationship at a time') + } } if (operation === 'update') { @@ -84,7 +92,7 @@ export const lists: Lists = { const values = [post, link].filter(x => x?.connect ?? x?.create) if (values.length > 1) { - addValidationError('Only one relationship at a time') + return addValidationError('Only one relationship at a time') } // TODO: prevent item from changing types with implicit disconnect From e2764a9da1db73527ee8c42211b1656d41a05c11 Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:04:12 +1000 Subject: [PATCH 3/4] prettier --- examples/usecase-relationship-union/schema.ts | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/examples/usecase-relationship-union/schema.ts b/examples/usecase-relationship-union/schema.ts index 76c3e628eab..eacf1877c93 100644 --- a/examples/usecase-relationship-union/schema.ts +++ b/examples/usecase-relationship-union/schema.ts @@ -3,15 +3,15 @@ import { allowAll } from '@keystone-6/core/access'; import { text, relationship, virtual } from '@keystone-6/core/fields'; import { Lists } from '.keystone/types'; -function ifUnsetHideUI (field: string) { +function ifUnsetHideUI(field: string) { return { itemView: { - fieldMode: ({ item }: any) => item[field] ? 'edit' : 'read', + fieldMode: ({ item }: any) => (item[field] ? 'edit' : 'read'), }, listView: { fieldMode: () => 'hidden' as const, }, - } + }; } export const lists: Lists = { @@ -35,7 +35,7 @@ export const lists: Lists = { Media: list({ access: allowAll, graphql: { - plural: 'Medias' + plural: 'Medias', }, fields: { label: virtual({ @@ -43,8 +43,14 @@ export const lists: Lists = { type: graphql.String, resolve: async (item, _, context) => { const { postId, linkId } = item; - if (postId) return (await context.db.Post.findOne({ where: { id: postId } }))?.title ?? '[missing]'; - if (linkId) return (await context.db.Link.findOne({ where: { id: linkId } }))?.title ?? '[missing]'; + if (postId) + return ( + (await context.db.Post.findOne({ where: { id: postId } }))?.title ?? '[missing]' + ); + if (linkId) + return ( + (await context.db.Link.findOne({ where: { id: linkId } }))?.title ?? '[missing]' + ); return '?'; }, }), @@ -57,42 +63,42 @@ export const lists: Lists = { post: relationship({ ref: 'Post', ui: { - ...ifUnsetHideUI('postId') - } + ...ifUnsetHideUI('postId'), + }, }), link: relationship({ ref: 'Link', ui: { - ...ifUnsetHideUI('linkId') - } + ...ifUnsetHideUI('linkId'), + }, }), - } - }) + }, + }), }, hooks: { validateInput: async ({ operation, inputData, addValidationError }) => { if (operation === 'create') { const { post, link } = inputData; - const values = [post, link].filter(x => x?.connect ?? x?.create) + const values = [post, link].filter(x => x?.connect ?? x?.create); if (values.length === 0) { - return addValidationError('A relationship is required') + return addValidationError('A relationship is required'); } if (values.length > 1) { - return addValidationError('Only one relationship at a time') + return addValidationError('Only one relationship at a time'); } } if (operation === 'update') { const { post, link } = inputData; if ([post, link].some(x => x?.disconnect)) { - return addValidationError('Cannot change relationship type') + return addValidationError('Cannot change relationship type'); } - const values = [post, link].filter(x => x?.connect ?? x?.create) + const values = [post, link].filter(x => x?.connect ?? x?.create); if (values.length > 1) { - return addValidationError('Only one relationship at a time') + return addValidationError('Only one relationship at a time'); } // TODO: prevent item from changing types with implicit disconnect @@ -102,21 +108,21 @@ export const lists: Lists = { update: async ({ context, operation, resolvedData }) => { const { post, link, ...rest } = resolvedData; for (const [key, value] of Object.entries({ post, link })) { - if (!value) continue - if (value.disconnect) continue // TODO: null should disconnect + if (!value) continue; + if (value.disconnect) continue; // TODO: null should disconnect // disconnect everything else return { ...rest, post: { disconnect: true }, link: { disconnect: true }, - [key]: value - } + [key]: value, + }; } - return rest - } - } - } + return rest; + }, + }, + }, }), }; From 937d413778f4bd43b757cae402c4cf572157914e Mon Sep 17 00:00:00 2001 From: Daniel Cousens <413395+dcousens@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:14:14 +1000 Subject: [PATCH 4/4] fix eslint issues --- examples/usecase-relationship-union/schema.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/usecase-relationship-union/schema.ts b/examples/usecase-relationship-union/schema.ts index eacf1877c93..ddade0ec27c 100644 --- a/examples/usecase-relationship-union/schema.ts +++ b/examples/usecase-relationship-union/schema.ts @@ -43,14 +43,16 @@ export const lists: Lists = { type: graphql.String, resolve: async (item, _, context) => { const { postId, linkId } = item; - if (postId) + if (postId) { return ( (await context.db.Post.findOne({ where: { id: postId } }))?.title ?? '[missing]' ); - if (linkId) + } + if (linkId) { return ( (await context.db.Link.findOne({ where: { id: linkId } }))?.title ?? '[missing]' ); + } return '?'; }, }),