diff --git a/examples/extend-graphql-schema-graphql-tools/schema.graphql b/examples/extend-graphql-schema-graphql-tools/schema.graphql index 5d814f68a40..739f80a8508 100644 --- a/examples/extend-graphql-schema-graphql-tools/schema.graphql +++ b/examples/extend-graphql-schema-graphql-tools/schema.graphql @@ -234,8 +234,8 @@ type Query { authorsCount(where: AuthorWhereInput! = {}): Int keystone: KeystoneMeta! - """ Return all posts for a user from the last days """ - recentPosts(id: ID!, days: Int! = 7): [Post] + """ Return all posts for a user from the last seconds """ + recentPosts(id: ID!, seconds: Int! = 600): [Post] """ Compute statistics for a user """ stats(id: ID!): Statistics diff --git a/examples/extend-graphql-schema-graphql-tools/schema.ts b/examples/extend-graphql-schema-graphql-tools/schema.ts index 692bd285928..e2bacbdc091 100644 --- a/examples/extend-graphql-schema-graphql-tools/schema.ts +++ b/examples/extend-graphql-schema-graphql-tools/schema.ts @@ -32,9 +32,9 @@ export const lists: Lists = { }), }; -export const extendGraphqlSchema = (schema: GraphQLSchema) => - mergeSchemas({ - schemas: [schema], +export function extendGraphqlSchema(baseSchema: GraphQLSchema) { + return mergeSchemas({ + schemas: [baseSchema], typeDefs: ` type Mutation { """ Publish a post """ @@ -45,8 +45,8 @@ export const extendGraphqlSchema = (schema: GraphQLSchema) => } type Query { - """ Return all posts for a user from the last days """ - recentPosts(id: ID!, days: Int! = 7): [Post] + """ Return all posts for a user from the last seconds """ + recentPosts(id: ID!, seconds: Int! = 600): [Post] """ Compute statistics for a user """ stats(id: ID!): Statistics @@ -87,11 +87,8 @@ export const extendGraphqlSchema = (schema: GraphQLSchema) => }, }, Query: { - recentPosts: (root, { id, days }, context: Context) => { - // Create a date string in the past from now() - const cutoff = new Date( - new Date().setUTCDate(new Date().getUTCDate() - days) - ).toUTCString(); + recentPosts: (root, { id, seconds }, context: Context) => { + const cutoff = new Date(Date.now() - seconds * 1000); // Note we use `context.db.Post` here as we have a return type // of [Post], and this API provides results in the correct format. @@ -132,3 +129,4 @@ export const extendGraphqlSchema = (schema: GraphQLSchema) => }, }, }); +} diff --git a/examples/extend-graphql-schema-graphql-ts/schema.graphql b/examples/extend-graphql-schema-graphql-ts/schema.graphql index c937d0bc566..1a005548cd0 100644 --- a/examples/extend-graphql-schema-graphql-ts/schema.graphql +++ b/examples/extend-graphql-schema-graphql-ts/schema.graphql @@ -229,7 +229,7 @@ type Query { author(where: AuthorWhereUniqueInput!): Author authorsCount(where: AuthorWhereInput! = {}): Int keystone: KeystoneMeta! - recentPosts(id: ID!, days: Int! = 7): [Post!] + recentPosts(id: ID!, seconds: Int! = 600): [Post!] stats(id: ID!): Statistics } diff --git a/examples/extend-graphql-schema-graphql-ts/schema.ts b/examples/extend-graphql-schema-graphql-ts/schema.ts index 32419adfffd..7b7e40709fd 100644 --- a/examples/extend-graphql-schema-graphql-ts/schema.ts +++ b/examples/extend-graphql-schema-graphql-ts/schema.ts @@ -105,13 +105,10 @@ export const extendGraphqlSchema = graphql.extend(base => { type: graphql.list(graphql.nonNull(base.object('Post'))), args: { id: graphql.arg({ type: graphql.nonNull(graphql.ID) }), - days: graphql.arg({ type: graphql.nonNull(graphql.Int), defaultValue: 7 }), + seconds: graphql.arg({ type: graphql.nonNull(graphql.Int), defaultValue: 600 }), }, - resolve(source, { id, days }, context: Context) { - // Create a date string in the past from now() - const cutoff = new Date( - new Date().setUTCDate(new Date().getUTCDate() - days) - ).toISOString(); + resolve(source, { id, seconds }, context: Context) { + const cutoff = new Date(Date.now() - seconds * 1000); // Note we use `context.db.Post` here as we have a return type // of [Post], and this API provides results in the correct format. diff --git a/examples/extend-graphql-schema-nexus/.gitignore b/examples/extend-graphql-schema-nexus/.gitignore index 0febf01c31e..f01331b30b2 100644 --- a/examples/extend-graphql-schema-nexus/.gitignore +++ b/examples/extend-graphql-schema-nexus/.gitignore @@ -1 +1 @@ -nexus/nexus-typegen.ts +nexus-types.ts diff --git a/examples/extend-graphql-schema-nexus/keystone.ts b/examples/extend-graphql-schema-nexus/keystone.ts index e17f32f456f..b03c36e662c 100644 --- a/examples/extend-graphql-schema-nexus/keystone.ts +++ b/examples/extend-graphql-schema-nexus/keystone.ts @@ -1,8 +1,6 @@ import { config } from '@keystone-6/core'; -import { mergeSchemas } from '@graphql-tools/schema'; import { fixPrismaPath } from '../example-utils'; -import { lists } from './schema'; -import { nexusSchema } from './nexus'; +import { lists, extendGraphqlSchema } from './schema'; export default config({ db: { @@ -13,5 +11,5 @@ export default config({ ...fixPrismaPath, }, lists, - extendGraphqlSchema: keystoneSchema => mergeSchemas({ schemas: [keystoneSchema, nexusSchema] }), + extendGraphqlSchema, }); diff --git a/examples/extend-graphql-schema-nexus/nexus/index.ts b/examples/extend-graphql-schema-nexus/nexus/index.ts deleted file mode 100644 index ed551e59c02..00000000000 --- a/examples/extend-graphql-schema-nexus/nexus/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import path from 'path'; -import { makeSchema } from 'nexus'; - -import * as types from './types'; - -export const nexusSchema = makeSchema({ - types, - outputs: { - typegen: path.join(process.cwd(), 'nexus', 'nexus-typegen.ts'), - }, - // __dirname is absolute in Node but under webpack it is not so this is - // "only generate when running under webpack and not in production" - shouldGenerateArtifacts: !path.isAbsolute(__dirname) && process.env.NODE_ENV !== 'production', - // This binds the Keystone Context with correctly generated types for the - // Keystone `db` and `query` args, as well as the prisma client - contextType: { - module: path.join(process.cwd(), 'node_modules', '.keystone', 'types.d.ts'), - export: 'Context', - }, -}); diff --git a/examples/extend-graphql-schema-nexus/nexus/types/Post.ts b/examples/extend-graphql-schema-nexus/nexus/types/Post.ts deleted file mode 100644 index 00992e49ca5..00000000000 --- a/examples/extend-graphql-schema-nexus/nexus/types/Post.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* -- NOTES -- - -This example demonstrates using the prisma client (from Keystone's context) -to return posts with a custom nexus-specified type. - -Ideally, we could tell Nexus about the GraphQL schema Keystone generates and -not need to generate the output type again here, but that needs some more -research (and maybe a plugin for nexus?) -*/ - -import { extendType, intArg, list, stringArg, nonNull, objectType } from 'nexus'; - -export const NexusPost = objectType({ - name: 'NexusPost', - definition(t) { - t.string('id'); - t.string('title'); - t.string('status'); - t.string('content'); - }, -}); - -export const PostQuery = extendType({ - type: 'Query', - definition(t) { - t.field('nexusPosts', { - type: nonNull(list('NexusPost')), - args: { - authorId: stringArg(), - days: nonNull(intArg({ default: 7 })), - }, - async resolve(root, { authorId, days }, context) { - const cutoff = new Date( - new Date().setUTCDate(new Date().getUTCDate() - days) - ).toISOString(); - - return await context.prisma.post.findMany({ - where: { - ...(authorId ? { author: { id: authorId } } : null), - publishDate: { gt: cutoff }, - }, - }); - }, - }); - }, -}); diff --git a/examples/extend-graphql-schema-nexus/nexus/types/Thing.ts b/examples/extend-graphql-schema-nexus/nexus/types/Thing.ts deleted file mode 100644 index 378e90d76c9..00000000000 --- a/examples/extend-graphql-schema-nexus/nexus/types/Thing.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This demonstrates the most basic Nexus usage to query a list of things - -import { extendType, objectType } from 'nexus'; - -export const Thing = objectType({ - name: 'Thing', - definition(t) { - t.int('id'); - t.string('title'); - }, -}); - -export const ThingQuery = extendType({ - type: 'Query', - definition(t) { - t.nonNull.list.field('things', { - type: 'Thing', - resolve() { - return [ - { id: 1, title: 'Keystone' }, - { id: 2, title: 'Prisma' }, - { id: 3, title: 'Nexus' }, - ]; - }, - }); - }, -}); diff --git a/examples/extend-graphql-schema-nexus/nexus/types/index.ts b/examples/extend-graphql-schema-nexus/nexus/types/index.ts deleted file mode 100644 index 9c0147ac1bf..00000000000 --- a/examples/extend-graphql-schema-nexus/nexus/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './Post'; -export * from './Thing'; diff --git a/examples/extend-graphql-schema-nexus/package.json b/examples/extend-graphql-schema-nexus/package.json index 36decf17b0b..c1daaca384b 100644 --- a/examples/extend-graphql-schema-nexus/package.json +++ b/examples/extend-graphql-schema-nexus/package.json @@ -12,7 +12,7 @@ "@graphql-tools/schema": "^9.0.0", "@keystone-6/core": "^5.0.0", "graphql": "^16.6.0", - "nexus": "1.3.0" + "nexus": "^1.3.0" }, "repository": "https://github.com/keystonejs/keystone/tree/main/examples/extend-graphql-schema-nexus" } diff --git a/examples/extend-graphql-schema-nexus/schema.graphql b/examples/extend-graphql-schema-nexus/schema.graphql index 0c170606840..4891df18c4d 100644 --- a/examples/extend-graphql-schema-nexus/schema.graphql +++ b/examples/extend-graphql-schema-nexus/schema.graphql @@ -227,8 +227,8 @@ type Query { author(where: AuthorWhereUniqueInput!): Author authorsCount(where: AuthorWhereInput! = {}): Int keystone: KeystoneMeta! - nexusPosts(authorId: String, days: Int! = 7): [NexusPost]! - things: [Thing]! + nexusPosts(id: String!, seconds: Int! = 600): [Post]! + things: [NexusThing]! } type KeystoneMeta { @@ -338,14 +338,7 @@ enum KeystoneAdminUISortDirection { DESC } -type NexusPost { - id: String - title: String - status: String - content: String -} - -type Thing { +type NexusThing { id: Int title: String } diff --git a/examples/extend-graphql-schema-nexus/schema.ts b/examples/extend-graphql-schema-nexus/schema.ts index dbcf0ff4e6f..8423833804e 100644 --- a/examples/extend-graphql-schema-nexus/schema.ts +++ b/examples/extend-graphql-schema-nexus/schema.ts @@ -1,8 +1,12 @@ +import path from 'path'; +import type { GraphQLSchema } from 'graphql'; import { list } from '@keystone-6/core'; import { allowAll } from '@keystone-6/core/access'; import { select, relationship, text, timestamp } from '@keystone-6/core/fields'; +import * as nexus from 'nexus'; +import type { Lists } from '.keystone/types'; -export const lists = { +export const lists: Lists = { Post: list({ access: allowAll, fields: { @@ -28,3 +32,75 @@ export const lists = { }, }), }; + +export function extendGraphqlSchema(baseSchema: GraphQLSchema) { + const NexusPostQuery = nexus.extendType({ + type: 'Query', + definition(t) { + t.field('nexusPosts', { + type: nexus.nonNull(nexus.list('Post')), + args: { + id: nexus.nonNull(nexus.stringArg()), + seconds: nexus.nonNull(nexus.intArg({ default: 600 })), + }, + + async resolve(root, { id, seconds }, context) { + const cutoff = new Date(Date.now() - seconds * 1000); + + // Note we use `context.db.Post` here as we have a return type + // of [Post], and this API provides results in the correct format. + // If you accidentally use `context.query.Post` here you can expect problems + // when accessing the fields in your GraphQL client. + return context.db.Post.findMany({ + where: { author: { id: { equals: id } }, publishDate: { gt: cutoff } }, + }) as Promise; // TODO: nexus doesn't like + }, + }); + }, + }); + + const NexusThing = nexus.objectType({ + name: 'NexusThing', + definition(t) { + t.int('id'); + t.string('title'); + }, + }); + + const NexusThingQuery = nexus.extendType({ + type: 'Query', + definition(t) { + t.nonNull.list.field('things', { + type: NexusThing, + resolve() { + return [ + { id: 1, title: 'Keystone' }, + { id: 2, title: 'Prisma' }, + { id: 3, title: 'Nexus' }, + ]; + }, + }); + }, + }); + + return nexus.makeSchema({ + mergeSchema: { + schema: baseSchema, + }, + types: { + NexusThing, + NexusPostQuery, + NexusThingQuery, + }, + + // Typescript output settings, probably something you might commit in dev + shouldGenerateArtifacts: process.env.NODE_ENV !== 'production', + outputs: { + typegen: path.join(process.cwd(), 'nexus-types.ts'), + }, + contextType: { + module: path.join(process.cwd(), 'node_modules', '.keystone', 'types.d.ts'), + export: 'Context', + }, + }); +} diff --git a/yarn.lock b/yarn.lock index ffdae2de9ea..2a5fa42a869 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11174,7 +11174,7 @@ next@^13.0.3: "@next/swc-win32-ia32-msvc" "13.1.1" "@next/swc-win32-x64-msvc" "13.1.1" -nexus@1.3.0: +nexus@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/nexus/-/nexus-1.3.0.tgz#d7e2671d48bf887e30e2815f509bbf4b0ee2a02b" integrity sha512-w/s19OiNOs0LrtP7pBmD9/FqJHvZLmCipVRt6v1PM8cRUYIbhEswyNKGHVoC4eHZGPSnD+bOf5A3+gnbt0A5/A==