/
objectType.ts
230 lines (224 loc) · 7.5 KB
/
objectType.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import { assertValidName, GraphQLObjectType } from 'graphql'
import { InterfaceFieldsFor } from '../typegenTypeHelpers'
import { OutputDefinitionBlock, OutputDefinitionBuilder } from './definitionBlocks'
import { FieldModification, FieldModificationDef, Implemented } from './interfaceType'
import { AbstractTypes, NexusTypes, NonNullConfig, SourceTypingDef, withNexusSymbol } from './_types'
export interface ObjectDefinitionBuilder extends OutputDefinitionBuilder {
addInterfaces(toAdd: Implemented[]): void
addModification(toAdd: FieldModificationDef<any, any>): void
}
export class ObjectDefinitionBlock<TypeName extends string> extends OutputDefinitionBlock<TypeName> {
constructor(protected typeBuilder: ObjectDefinitionBuilder) {
super(typeBuilder)
}
/** @param interfaceName */
implements(...interfaceName: Array<Implemented>) {
this.typeBuilder.addInterfaces(interfaceName)
}
/** Modifies a field added via an interface */
modify<FieldName extends Extract<InterfaceFieldsFor<TypeName>, string>>(
field: FieldName,
modifications: FieldModification<TypeName, FieldName>
) {
this.typeBuilder.addModification({ ...modifications, field })
}
}
/** Configuration object to specify an object's name, fields, and more. */
export type NexusObjectTypeConfig<TypeName extends string> = {
/**
* [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#Name)
*
* The name of this object type. Must conform to the pattern:
*
* [_A-Za-z][_0-9A-Za-z]*
*
* From the spec: Names in GraphQL are case‐sensitive. That is to say name, Name, and NAME all refer to
* dfferent names. Underscores are significant, which means other_name and othername are two different names.
*
* @example
* 'Post'
*
* @example
* 'User2'
*
* @example
* 'comment'
*
* @example
* 'User_Timeline'
*/
name: TypeName
/**
* [Nullability Guide](https://nxs.li/guides/nullability)
*
* Configures the default nullability for fields and arguments in this object.
*
* Default :: By default inherits from the global nonNullDefaults configuration found in makeSchema.
*
* @example
* const User = objectType({
* name: 'User',
* nonNullDefaults: {
* input: true, // field args, input object type fields
* output: false, // object type fields
* },
* definition(t) {
* t.string('location', {
* args: {
* language: stringArg(),
* },
* })
* },
* })
*
* // GraphQL SDL
* // -----------
* //
* // type User {
* // location(language: String!): String
* // }
*/
nonNullDefaults?: NonNullConfig
/**
* [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Descriptions)
*
* The description for this object type.
*
* Various GraphQL tools will make use of this information but it has zero runtime impact. The value given
* here will also be included as heredocs in the generated GraphQL SDL file.
*
* Default :: By default there will be no description
*
* @example
* 'Little description to help you along!'
*
* // GraphQL SDL
* // -----------
* // """Little description to help you along!"""
* // type YOUR_TYPE_NAME {
* // # ...
* // }
*/
description?: string
/**
* [Source Types Guide](https://nxs.li/guides/backing-types)
*
* Specify the Source Type for this object type.
*
* You can give a literal TypeScript type written as a string or give the location of a module that exports a type.
*
* Default :: By default the source type of this object will be whatever you configured in makeSchema, if
* anything, otherwise simply 1:1 with how you have defined this object type.
*
* @example
* '{ foo: string; qux: number; bar: boolean }'
*
* @example
* {
* module: 'some-package',
* export: 'User',
* }
*
* @example
* {
* module: `${__dirname}/some/module.ts`,
* export: 'User',
* }
*/
sourceType?: SourceTypingDef
/**
* Data that will be added to the field-level [extensions field on the graphql-js type def
* instances](https://github.com/graphql/graphql-js/issues/1527) resulting from makeSchema. Useful for some
* graphql-js based tools like [join-monster](https://github.com/join-monster/join-monster) which rely on
* looking for special data here.
*
* @example
* // taken from: https://github.com/graphql-nexus/schema/issues/683#issuecomment-735711640
*
* const User = objectType({
* name: 'User',
* extensions: {
* joinMonster: {
* sqlTable: 'USERS',
* uniqueKey: 'USER_ID',
* },
* },
* definition(t) {
* t.id('id', {
* extensions: {
* joinMonster: {
* sqlColumn: 'USER_ID',
* },
* },
* })
* },
* })
*/
extensions?: GraphQLObjectType['extensions']
/**
* Define the fields of your object type.
*
* This method receives a type builder api that you will use to define the fields of your object type
* within. You can leverage conditionals, loops, other functions (that take the builder api as an
* argument), pull in variables from higher scopes, and so on, to help define your fields. However avoid two things:
*
* 1. Doing asynchronous work when defining fields.
*
* 2. Triggering side-effects that you would NOT want run at _build_ time––as this code will run during
* build to support [Nexus' reflection system](https://nxs.li/guides/reflection).
*
* @example
* objectType({
* name: 'User',
* definition(t) {
* t.field('name', { type: 'String' })
* t.string('status')
* t.list.list.int('foo')
* t.nullable.boolean('visible')
* t.list.nonNull.field('friends', {
* type: 'Friend',
* // ...
* })
* },
* })
*
* @param t The type builder API for object types. The primary method you'll find is "t.field" but there are
* many convenient shorthands available as well, plus anything plugins have added. Explore each one's jsDoc
* for more detail.
*/
definition(t: ObjectDefinitionBlock<TypeName>): void
} & AbstractTypes.MaybeTypeDefConfigFieldIsTypeOf<TypeName> &
NexusGenPluginTypeConfig<TypeName>
export class NexusObjectTypeDef<TypeName extends string> {
constructor(readonly name: TypeName, protected config: NexusObjectTypeConfig<TypeName>) {
assertValidName(name)
}
get value() {
return this.config
}
}
withNexusSymbol(NexusObjectTypeDef, NexusTypes.Object)
/**
* [API Docs](https://nxs.li/docs/api/object-type) | [GraphQL.org
* Docs](https://graphql.org/learn/schema/#object-types-and-fields) | [GraphQL 2018
* Spec](https://spec.graphql.org/June2018/#sec-Objects)
*
* Define a GraphQL Object Type.
*
* Object types are typically the most common kind of type present in a GraphQL schema. You give them a name
* and fields that model your domain. Fields are typed and can point to yet another object type you've defined.
*
* @example
* const Post = objectType({
* name: 'Post',
* definition(t) {
* t.int('id')
* t.string('title')
* },
* })
*
* @param config Specify your object's name, its fields, and more. See each config property's jsDoc for more detail.
*/
export function objectType<TypeName extends string>(config: NexusObjectTypeConfig<TypeName>) {
return new NexusObjectTypeDef<TypeName>(config.name, config)
}