@@ -33,7 +33,15 @@ final class ExecutionContext {
33
33
let variableValues : [ String : Map ]
34
34
var errors : [ GraphQLError ]
35
35
36
- init ( schema: GraphQLSchema , fragments: [ String : FragmentDefinition ] , rootValue: Map , contextValue: Map , operation: OperationDefinition , variableValues: [ String : Map ] , errors: [ GraphQLError ] ) {
36
+ init (
37
+ schema: GraphQLSchema ,
38
+ fragments: [ String : FragmentDefinition ] ,
39
+ rootValue: Map ,
40
+ contextValue: Map ,
41
+ operation: OperationDefinition ,
42
+ variableValues: [ String : Map ] ,
43
+ errors: [ GraphQLError ]
44
+ ) {
37
45
self . schema = schema
38
46
self . fragments = fragments
39
47
self . rootValue = rootValue
@@ -53,7 +61,14 @@ final class ExecutionContext {
53
61
* If the arguments to this func do not result in a legal execution context,
54
62
* a GraphQLError will be thrown immediately explaining the invalid input.
55
63
*/
56
- func execute( schema: GraphQLSchema , documentAST: Document , rootValue: Map , contextValue: Map , variableValues: [ String : Map ] = [ : ] , operationName: String ? = nil ) throws -> Map {
64
+ func execute(
65
+ schema: GraphQLSchema ,
66
+ documentAST: Document ,
67
+ rootValue: Map ,
68
+ contextValue: Map ,
69
+ variableValues: [ String : Map ] = [ : ] ,
70
+ operationName: String ? = nil
71
+ ) throws -> Map {
57
72
58
73
// If a valid context cannot be created due to incorrect arguments,
59
74
// this will throw an error.
@@ -91,7 +106,14 @@ func execute(schema: GraphQLSchema, documentAST: Document, rootValue: Map, conte
91
106
*
92
107
* Throws a GraphQLError if a valid execution context cannot be created.
93
108
*/
94
- func buildExecutionContext( schema: GraphQLSchema , documentAST: Document , rootValue: Map , contextValue: Map , rawVariableValues: [ String : Map ] , operationName: String ? ) throws -> ExecutionContext {
109
+ func buildExecutionContext(
110
+ schema: GraphQLSchema ,
111
+ documentAST: Document ,
112
+ rootValue: Map ,
113
+ contextValue: Map ,
114
+ rawVariableValues: [ String : Map ] ,
115
+ operationName: String ?
116
+ ) throws -> ExecutionContext {
95
117
let errors : [ GraphQLError ] = [ ]
96
118
var possibleOperation : OperationDefinition ? = nil
97
119
var fragments : [ String : FragmentDefinition ] = [ : ]
@@ -148,7 +170,11 @@ func buildExecutionContext(schema: GraphQLSchema, documentAST: Document, rootVal
148
170
/**
149
171
* Implements the "Evaluating operations" section of the spec.
150
172
*/
151
- func executeOperation( exeContext: ExecutionContext , operation: OperationDefinition , rootValue: Map ) throws -> Map {
173
+ func executeOperation(
174
+ exeContext: ExecutionContext ,
175
+ operation: OperationDefinition ,
176
+ rootValue: Map
177
+ ) throws -> Map {
152
178
let type = try getOperationRootType ( schema: exeContext. schema, operation: operation)
153
179
154
180
var inputFields : [ String : [ Field ] ] = [ : ]
@@ -186,7 +212,10 @@ func executeOperation(exeContext: ExecutionContext, operation: OperationDefiniti
186
212
/**
187
213
* Extracts the root type of the operation from the schema.
188
214
*/
189
- func getOperationRootType( schema: GraphQLSchema , operation: OperationDefinition ) throws -> GraphQLObjectType {
215
+ func getOperationRootType(
216
+ schema: GraphQLSchema ,
217
+ operation: OperationDefinition
218
+ ) throws -> GraphQLObjectType {
190
219
switch operation. operation {
191
220
case . query:
192
221
return schema. queryType
@@ -197,6 +226,7 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
197
226
nodes: [ operation]
198
227
)
199
228
}
229
+
200
230
return mutationType
201
231
case . subscription:
202
232
guard let subscriptionType = schema. subscriptionType else {
@@ -205,6 +235,7 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
205
235
nodes: [ operation]
206
236
)
207
237
}
238
+
208
239
return subscriptionType
209
240
}
210
241
}
@@ -213,7 +244,13 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
213
244
* Implements the "Evaluating selection sets" section of the spec
214
245
* for "write" mode.
215
246
*/
216
- func executeFieldsSerially( exeContext: ExecutionContext , parentType: GraphQLObjectType , sourceValue: Map , path: [ IndexPathElement ] , fields: [ String : [ Field ] ] ) throws -> Map {
247
+ func executeFieldsSerially(
248
+ exeContext: ExecutionContext ,
249
+ parentType: GraphQLObjectType ,
250
+ sourceValue: Map ,
251
+ path: [ IndexPathElement ] ,
252
+ fields: [ String : [ Field ] ]
253
+ ) throws -> Map {
217
254
return try fields. reduce ( [ : ] ) { results, field in
218
255
var results = results
219
256
let fieldASTs = field. value
@@ -253,29 +290,19 @@ func executeFields(
253
290
let fieldASTs = field. value
254
291
let fieldPath = path + [ field. key] as [ IndexPathElement ]
255
292
256
- // do {
257
- let result = try resolveField (
258
- exeContext: exeContext,
259
- parentType: parentType,
260
- source: sourceValue,
261
- fieldASTs: fieldASTs,
262
- path: fieldPath
263
- )
293
+ let result = try resolveField (
294
+ exeContext: exeContext,
295
+ parentType: parentType,
296
+ source: sourceValue,
297
+ fieldASTs: fieldASTs,
298
+ path: fieldPath
299
+ )
264
300
265
- guard let r = result else {
266
- return results
267
- }
301
+ guard let r = result else {
302
+ return results
303
+ }
268
304
269
- results [ field. key] = r
270
- // } catch {
271
- // results[field.key] = .null
272
- // let e = locatedError(
273
- // originalError: error,
274
- // nodes: fieldASTs,
275
- // path: fieldPath
276
- // )
277
- // exeContext.errors.append(e)
278
- // }
305
+ results [ field. key] = r
279
306
280
307
return results
281
308
}
@@ -292,68 +319,98 @@ func executeFields(
292
319
* Object type returned by that field.
293
320
*/
294
321
@discardableResult
295
- func collectFields( exeContext: ExecutionContext , runtimeType: GraphQLObjectType , selectionSet: SelectionSet , fields: inout [ String : [ Field ] ] ,
296
- visitedFragmentNames: inout [ String : Bool ] ) throws -> [ String : [ Field ] ] {
322
+ func collectFields(
323
+ exeContext: ExecutionContext ,
324
+ runtimeType: GraphQLObjectType ,
325
+ selectionSet: SelectionSet ,
326
+ fields: inout [ String : [ Field ] ] ,
327
+ visitedFragmentNames: inout [ String : Bool ]
328
+ ) throws -> [ String : [ Field ] ] {
297
329
var visitedFragmentNames = visitedFragmentNames
298
330
299
331
for selection in selectionSet. selections {
300
- switch selection {
301
- case let field as Field :
302
- if try ! shouldIncludeNode( exeContext: exeContext, directives: field. directives) {
303
- continue
304
- }
332
+ switch selection {
333
+ case let field as Field :
334
+ let shouldInclude = try shouldIncludeNode (
335
+ exeContext: exeContext,
336
+ directives: field. directives
337
+ )
305
338
306
- let name = getFieldEntryKey ( node: field)
339
+ guard shouldInclude else {
340
+ continue
341
+ }
307
342
308
- if fields [ name] == nil {
309
- fields [ name] = [ ]
310
- }
343
+ let name = getFieldEntryKey ( node: field)
311
344
312
- fields [ name] ? . append ( field)
313
- case let selection as InlineFragment :
314
- if try ! shouldIncludeNode( exeContext: exeContext, directives: selection. directives) ||
315
- !doesFragmentConditionMatch( exeContext: exeContext, fragment: selection, type: runtimeType) {
316
- continue
317
- }
345
+ if fields [ name] == nil {
346
+ fields [ name] = [ ]
347
+ }
318
348
319
- try collectFields (
320
- exeContext: exeContext,
321
- runtimeType: runtimeType,
322
- selectionSet: selection. selectionSet,
323
- fields: & fields,
324
- visitedFragmentNames: & visitedFragmentNames
325
- )
349
+ fields [ name] ? . append ( field)
350
+ case let inlineFragment as InlineFragment :
351
+ let shouldInclude = try shouldIncludeNode (
352
+ exeContext: exeContext,
353
+ directives: inlineFragment. directives
354
+ )
326
355
327
- case let selection as FragmentSpread :
328
- let fragName = selection. name. value
356
+ let fragmentConditionMatches = try doesFragmentConditionMatch (
357
+ exeContext: exeContext,
358
+ fragment: inlineFragment,
359
+ type: runtimeType
360
+ )
329
361
330
- if try visitedFragmentNames [ fragName] != nil ||
331
- !shouldIncludeNode( exeContext: exeContext, directives: selection. directives) {
332
- continue
333
- }
362
+ guard shouldInclude && fragmentConditionMatches else {
363
+ continue
364
+ }
334
365
335
- visitedFragmentNames [ fragName] = true
336
- guard let fragment = exeContext. fragments [ fragName] else {
337
- continue
338
- }
366
+ try collectFields (
367
+ exeContext: exeContext,
368
+ runtimeType: runtimeType,
369
+ selectionSet: inlineFragment. selectionSet,
370
+ fields: & fields,
371
+ visitedFragmentNames: & visitedFragmentNames
372
+ )
373
+ case let fragmentSpread as FragmentSpread :
374
+ let fragmentName = fragmentSpread. name. value
339
375
340
- if try ! doesFragmentConditionMatch( exeContext: exeContext, fragment: fragment, type: runtimeType) {
341
- continue
342
- }
376
+ let shouldInclude = try shouldIncludeNode (
377
+ exeContext: exeContext,
378
+ directives: fragmentSpread. directives
379
+ )
343
380
344
- try collectFields (
345
- exeContext: exeContext,
346
- runtimeType: runtimeType,
347
- selectionSet: fragment. selectionSet,
348
- fields: & fields,
349
- visitedFragmentNames: & visitedFragmentNames
350
- )
351
- default :
352
- break
353
- }
354
- }
381
+ guard visitedFragmentNames [ fragmentName] == nil && shouldInclude else {
382
+ continue
383
+ }
384
+
385
+ visitedFragmentNames [ fragmentName] = true
386
+
387
+ guard let fragment = exeContext. fragments [ fragmentName] else {
388
+ continue
389
+ }
390
+
391
+ let fragmentConditionMatches = try doesFragmentConditionMatch (
392
+ exeContext: exeContext,
393
+ fragment: fragment,
394
+ type: runtimeType
395
+ )
396
+
397
+ guard fragmentConditionMatches else {
398
+ continue
399
+ }
355
400
356
- return fields
401
+ try collectFields (
402
+ exeContext: exeContext,
403
+ runtimeType: runtimeType,
404
+ selectionSet: fragment. selectionSet,
405
+ fields: & fields,
406
+ visitedFragmentNames: & visitedFragmentNames
407
+ )
408
+ default :
409
+ break
410
+ }
411
+ }
412
+
413
+ return fields
357
414
}
358
415
359
416
/**
@@ -391,7 +448,11 @@ func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = [
391
448
/**
392
449
* Determines if a fragment is applicable to the given type.
393
450
*/
394
- func doesFragmentConditionMatch( exeContext: ExecutionContext , fragment: HasTypeCondition , type: GraphQLObjectType ) throws -> Bool {
451
+ func doesFragmentConditionMatch(
452
+ exeContext: ExecutionContext ,
453
+ fragment: HasTypeCondition ,
454
+ type: GraphQLObjectType
455
+ ) throws -> Bool {
395
456
guard let typeConditionAST = fragment. getTypeCondition ( ) else {
396
457
return true
397
458
}
@@ -424,8 +485,13 @@ func getFieldEntryKey(node: Field) -> String {
424
485
* then calls completeValue to complete promises, serialize scalars, or execute
425
486
* the sub-selection-set for objects.
426
487
*/
427
- func resolveField( exeContext: ExecutionContext , parentType: GraphQLObjectType , source: Map ,
428
- fieldASTs: [ Field ] , path: [ IndexPathElement ] ) throws -> Map ? {
488
+ func resolveField(
489
+ exeContext: ExecutionContext ,
490
+ parentType: GraphQLObjectType ,
491
+ source: Map ,
492
+ fieldASTs: [ Field ] ,
493
+ path: [ IndexPathElement ]
494
+ ) throws -> Map ? {
429
495
let fieldAST = fieldASTs [ 0 ]
430
496
let fieldName = fieldAST. name. value
431
497
@@ -615,22 +681,6 @@ func completeValue(
615
681
case . error( let error) :
616
682
throw error
617
683
case . result( let result) :
618
- if let returnType = returnType as? GraphQLTypeReference {
619
- guard let type = exeContext. schema. getType ( name: returnType. name) else {
620
- throw GraphQLError (
621
- message: " Cannot complete value for type reference of nonexistent type \( returnType. name) . "
622
- )
623
- }
624
- return try completeValue (
625
- exeContext: exeContext,
626
- returnType: type,
627
- fieldASTs: fieldASTs,
628
- info: info,
629
- path: path,
630
- result: . result( result)
631
- )
632
- }
633
-
634
684
// If field type is NonNull, complete for inner type, and throw field error
635
685
// if result is null.
636
686
if let returnType = returnType as? GraphQLNonNull {
@@ -711,7 +761,14 @@ func completeValue(
711
761
* Complete a list value by completing each item in the list with the
712
762
* inner type
713
763
*/
714
- func completeListValue( exeContext: ExecutionContext , returnType: GraphQLList , fieldASTs: [ Field ] , info: GraphQLResolveInfo , path: [ IndexPathElement ] , result: Map ) throws -> Map {
764
+ func completeListValue(
765
+ exeContext: ExecutionContext ,
766
+ returnType: GraphQLList ,
767
+ fieldASTs: [ Field ] ,
768
+ info: GraphQLResolveInfo ,
769
+ path: [ IndexPathElement ] ,
770
+ result: Map
771
+ ) throws -> Map {
715
772
guard case . array( let result) = result else {
716
773
throw GraphQLError (
717
774
message:
@@ -874,7 +931,12 @@ func completeObjectValue(
874
931
* used which tests each possible type for the abstract type by calling
875
932
* isTypeOf for the object being coerced, returning the first type that matches.
876
933
*/
877
- func defaultResolveType( value: Map , context: Map , info: GraphQLResolveInfo , abstractType: GraphQLAbstractType ) -> GraphQLObjectType ? {
934
+ func defaultResolveType(
935
+ value: Map ,
936
+ context: Map ,
937
+ info: GraphQLResolveInfo ,
938
+ abstractType: GraphQLAbstractType
939
+ ) -> GraphQLObjectType ? {
878
940
let possibleTypes = info. schema. getPossibleTypes ( abstractType: abstractType)
879
941
return possibleTypes. find ( { $0. isTypeOf ? ( value, context, info) ?? false } )
880
942
}
@@ -910,7 +972,11 @@ func defaultResolve(source: Map, args: [String: Map], context: Map, info: GraphQ
910
972
* added to the query type, but that would require mutating type
911
973
* definitions, which would cause issues.
912
974
*/
913
- func getFieldDef( schema: GraphQLSchema , parentType: GraphQLObjectType , fieldName: String ) -> GraphQLFieldDefinition ? {
975
+ func getFieldDef(
976
+ schema: GraphQLSchema ,
977
+ parentType: GraphQLObjectType ,
978
+ fieldName: String
979
+ ) -> GraphQLFieldDefinition ? {
914
980
if fieldName == SchemaMetaFieldDef . name && schema. queryType. name == parentType. name {
915
981
return SchemaMetaFieldDef
916
982
} else if fieldName == TypeMetaFieldDef . name && schema. queryType. name == parentType. name {
0 commit comments