forked from keystonejs/keystone
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschema.ts
134 lines (127 loc) · 5.06 KB
/
schema.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { list } from '@keystone-6/core';
import type { GraphQLSchema } from 'graphql';
import { mergeSchemas } from '@graphql-tools/schema';
import { allowAll } from '@keystone-6/core/access';
import { select, relationship, text, timestamp } from '@keystone-6/core/fields';
import { Lists, Context } from '.keystone/types';
export const lists: Lists = {
Post: list({
access: allowAll,
fields: {
title: text({ validation: { isRequired: true } }),
status: select({
type: 'enum',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
],
}),
content: text(),
publishDate: timestamp(),
author: relationship({ ref: 'Author.posts', many: false }),
},
}),
Author: list({
access: allowAll,
fields: {
name: text({ validation: { isRequired: true } }),
email: text({ isIndexed: 'unique', validation: { isRequired: true } }),
posts: relationship({ ref: 'Post.author', many: true }),
},
}),
};
export const extendGraphqlSchema = (schema: GraphQLSchema) =>
mergeSchemas({
schemas: [schema],
typeDefs: `
type Mutation {
""" Publish a post """
publishPost(id: ID!): Post
""" Create or update an author based on email """
upsertAuthor(where: AuthorWhereUniqueInput!, create: AuthorCreateInput!, update: AuthorUpdateInput!): Author
}
type Query {
""" Return all posts for a user from the last <days> days """
recentPosts(id: ID!, days: Int! = 7): [Post]
""" Compute statistics for a user """
stats(id: ID!): Statistics
}
""" A custom type to represent statistics for a user """
type Statistics {
draft: Int
published: Int
latest: Post
}`,
resolvers: {
Mutation: {
publishPost: (root, { id }, context: Context) => {
// 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.updateOne({
where: { id },
data: { status: 'published', publishDate: new Date().toUTCString() },
});
},
upsertAuthor: async (root, { where, update, create }, context: Context) => {
try {
// we need to await the update here so that if an error is thrown, it's caught
// by the try catch here and not returned through the graphql api
return await context.db.Author.updateOne({ where, data: update });
} catch (updateError: any) {
// updateOne will fail with the code KS_ACCESS_DENIED if the item isn't found,
// so we try to create it. If the item does exist, the unique constraint on
// email will prevent a duplicate being created, and we catch the error
if (updateError.extensions?.code === 'KS_ACCESS_DENIED') {
return await context.db.Author.createOne({ data: create });
}
throw updateError;
}
},
},
Query: {
recentPosts: (root, { id, days }, context: Context) => {
// Create a date string <days> in the past from now()
const cutoff = new Date(
new Date().setUTCDate(new Date().getUTCDate() - days)
).toUTCString();
// 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 } },
});
},
stats: async (root, { id }) => {
return { authorId: id };
},
},
Statistics: {
// The stats resolver returns an object which is passed to this resolver as
// the root value. We use that object to further resolve ths specific fields.
// In this case we want to take root.authorId and get the latest post for that author
//
// As above we use the context.db.Post API to achieve this.
latest: async (val, args, context: Context) => {
const [post] = await context.db.Post.findMany({
take: 1,
orderBy: { publishDate: 'desc' },
where: { author: { id: { equals: val.authorId } } },
});
return post;
},
draft: (val, args, context: Context) => {
return context.query.Post.count({
where: { author: { id: { equals: val.authorId } }, status: { equals: 'draft' } },
});
},
published: (val, args, context: Context) => {
return context.query.Post.count({
where: { author: { id: { equals: val.authorId } }, status: { equals: 'published' } },
});
},
},
},
});