@@ -33,7 +33,15 @@ final class ExecutionContext {
3333 let variableValues : [ String : Map ]
3434 var errors : [ GraphQLError ]
3535
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+ ) {
3745 self . schema = schema
3846 self . fragments = fragments
3947 self . rootValue = rootValue
@@ -53,7 +61,14 @@ final class ExecutionContext {
5361 * If the arguments to this func do not result in a legal execution context,
5462 * a GraphQLError will be thrown immediately explaining the invalid input.
5563 */
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 {
5772
5873 // If a valid context cannot be created due to incorrect arguments,
5974 // this will throw an error.
@@ -91,7 +106,14 @@ func execute(schema: GraphQLSchema, documentAST: Document, rootValue: Map, conte
91106 *
92107 * Throws a GraphQLError if a valid execution context cannot be created.
93108 */
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 {
95117 let errors : [ GraphQLError ] = [ ]
96118 var possibleOperation : OperationDefinition ? = nil
97119 var fragments : [ String : FragmentDefinition ] = [ : ]
@@ -148,7 +170,11 @@ func buildExecutionContext(schema: GraphQLSchema, documentAST: Document, rootVal
148170/**
149171 * Implements the "Evaluating operations" section of the spec.
150172 */
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 {
152178 let type = try getOperationRootType ( schema: exeContext. schema, operation: operation)
153179
154180 var inputFields : [ String : [ Field ] ] = [ : ]
@@ -186,7 +212,10 @@ func executeOperation(exeContext: ExecutionContext, operation: OperationDefiniti
186212/**
187213 * Extracts the root type of the operation from the schema.
188214 */
189- func getOperationRootType( schema: GraphQLSchema , operation: OperationDefinition ) throws -> GraphQLObjectType {
215+ func getOperationRootType(
216+ schema: GraphQLSchema ,
217+ operation: OperationDefinition
218+ ) throws -> GraphQLObjectType {
190219 switch operation. operation {
191220 case . query:
192221 return schema. queryType
@@ -197,6 +226,7 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
197226 nodes: [ operation]
198227 )
199228 }
229+
200230 return mutationType
201231 case . subscription:
202232 guard let subscriptionType = schema. subscriptionType else {
@@ -205,6 +235,7 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
205235 nodes: [ operation]
206236 )
207237 }
238+
208239 return subscriptionType
209240 }
210241}
@@ -213,7 +244,13 @@ func getOperationRootType(schema: GraphQLSchema, operation: OperationDefinition)
213244 * Implements the "Evaluating selection sets" section of the spec
214245 * for "write" mode.
215246 */
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 {
217254 return try fields. reduce ( [ : ] ) { results, field in
218255 var results = results
219256 let fieldASTs = field. value
@@ -253,29 +290,19 @@ func executeFields(
253290 let fieldASTs = field. value
254291 let fieldPath = path + [ field. key] as [ IndexPathElement ]
255292
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+ )
264300
265- guard let r = result else {
266- return results
267- }
301+ guard let r = result else {
302+ return results
303+ }
268304
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
279306
280307 return results
281308 }
@@ -292,68 +319,98 @@ func executeFields(
292319 * Object type returned by that field.
293320 */
294321@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 ] ] {
297329 var visitedFragmentNames = visitedFragmentNames
298330
299331 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+ )
305338
306- let name = getFieldEntryKey ( node: field)
339+ guard shouldInclude else {
340+ continue
341+ }
307342
308- if fields [ name] == nil {
309- fields [ name] = [ ]
310- }
343+ let name = getFieldEntryKey ( node: field)
311344
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+ }
318348
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+ )
326355
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+ )
329361
330- if try visitedFragmentNames [ fragName] != nil ||
331- !shouldIncludeNode( exeContext: exeContext, directives: selection. directives) {
332- continue
333- }
362+ guard shouldInclude && fragmentConditionMatches else {
363+ continue
364+ }
334365
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
339375
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+ )
343380
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+ }
355400
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
357414}
358415
359416/**
@@ -391,7 +448,11 @@ func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = [
391448/**
392449 * Determines if a fragment is applicable to the given type.
393450 */
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 {
395456 guard let typeConditionAST = fragment. getTypeCondition ( ) else {
396457 return true
397458 }
@@ -424,8 +485,13 @@ func getFieldEntryKey(node: Field) -> String {
424485 * then calls completeValue to complete promises, serialize scalars, or execute
425486 * the sub-selection-set for objects.
426487 */
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 ? {
429495 let fieldAST = fieldASTs [ 0 ]
430496 let fieldName = fieldAST. name. value
431497
@@ -615,22 +681,6 @@ func completeValue(
615681 case . error( let error) :
616682 throw error
617683 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-
634684 // If field type is NonNull, complete for inner type, and throw field error
635685 // if result is null.
636686 if let returnType = returnType as? GraphQLNonNull {
@@ -711,7 +761,14 @@ func completeValue(
711761 * Complete a list value by completing each item in the list with the
712762 * inner type
713763 */
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 {
715772 guard case . array( let result) = result else {
716773 throw GraphQLError (
717774 message:
@@ -874,7 +931,12 @@ func completeObjectValue(
874931 * used which tests each possible type for the abstract type by calling
875932 * isTypeOf for the object being coerced, returning the first type that matches.
876933 */
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 ? {
878940 let possibleTypes = info. schema. getPossibleTypes ( abstractType: abstractType)
879941 return possibleTypes. find ( { $0. isTypeOf ? ( value, context, info) ?? false } )
880942}
@@ -910,7 +972,11 @@ func defaultResolve(source: Map, args: [String: Map], context: Map, info: GraphQ
910972 * added to the query type, but that would require mutating type
911973 * definitions, which would cause issues.
912974 */
913- func getFieldDef( schema: GraphQLSchema , parentType: GraphQLObjectType , fieldName: String ) -> GraphQLFieldDefinition ? {
975+ func getFieldDef(
976+ schema: GraphQLSchema ,
977+ parentType: GraphQLObjectType ,
978+ fieldName: String
979+ ) -> GraphQLFieldDefinition ? {
914980 if fieldName == SchemaMetaFieldDef . name && schema. queryType. name == parentType. name {
915981 return SchemaMetaFieldDef
916982 } else if fieldName == TypeMetaFieldDef . name && schema. queryType. name == parentType. name {
0 commit comments