Skip to content

Commit 57a7f30

Browse files
committed
only introspection tests to go
1 parent b658d97 commit 57a7f30

File tree

14 files changed

+1421
-756
lines changed

14 files changed

+1421
-756
lines changed

Sources/GraphQL/Execution/Execute.swift

Lines changed: 164 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)