Skip to content

Commit 045bae9

Browse files
committed
resolve using MapRepresentable instead of Map
1 parent 8a9e9dd commit 045bae9

35 files changed

+1023
-218
lines changed

Sources/GraphQL/Execution/Execute.swift

Lines changed: 78 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@
2727
final class ExecutionContext {
2828
let schema: GraphQLSchema
2929
let fragments: [String: FragmentDefinition]
30-
let rootValue: Map
31-
let contextValue: Map
30+
let rootValue: MapRepresentable
31+
let contextValue: MapRepresentable
3232
let operation: OperationDefinition
3333
let variableValues: [String: Map]
3434
var errors: [GraphQLError]
3535

3636
init(
3737
schema: GraphQLSchema,
3838
fragments: [String: FragmentDefinition],
39-
rootValue: Map,
40-
contextValue: Map,
39+
rootValue: MapRepresentable,
40+
contextValue: MapRepresentable,
4141
operation: OperationDefinition,
4242
variableValues: [String: Map],
4343
errors: [GraphQLError]
@@ -64,8 +64,8 @@ final class ExecutionContext {
6464
func execute(
6565
schema: GraphQLSchema,
6666
documentAST: Document,
67-
rootValue: Map,
68-
contextValue: Map,
67+
rootValue: MapRepresentable,
68+
contextValue: MapRepresentable,
6969
variableValues: [String: Map] = [:],
7070
operationName: String? = nil
7171
) throws -> Map {
@@ -88,7 +88,13 @@ func execute(
8888
rootValue: rootValue
8989
)
9090

91-
var result: [String: Map] = ["data": data]
91+
var dataMap: Map = [:]
92+
93+
for (key, value) in data {
94+
dataMap[key] = value.map
95+
}
96+
97+
var result: [String: Map] = ["data": dataMap]
9298

9399
if !context.errors.isEmpty {
94100
result["errors"] = context.errors.map
@@ -109,8 +115,8 @@ func execute(
109115
func buildExecutionContext(
110116
schema: GraphQLSchema,
111117
documentAST: Document,
112-
rootValue: Map,
113-
contextValue: Map,
118+
rootValue: MapRepresentable,
119+
contextValue: MapRepresentable,
114120
rawVariableValues: [String: Map],
115121
operationName: String?
116122
) throws -> ExecutionContext {
@@ -173,8 +179,8 @@ func buildExecutionContext(
173179
func executeOperation(
174180
exeContext: ExecutionContext,
175181
operation: OperationDefinition,
176-
rootValue: Map
177-
) throws -> Map {
182+
rootValue: MapRepresentable
183+
) throws -> [String : MapRepresentable] {
178184
let type = try getOperationRootType(schema: exeContext.schema, operation: operation)
179185

180186
var inputFields: [String : [Field]] = [:]
@@ -247,10 +253,10 @@ func getOperationRootType(
247253
func executeFieldsSerially(
248254
exeContext: ExecutionContext,
249255
parentType: GraphQLObjectType,
250-
sourceValue: Map,
256+
sourceValue: MapRepresentable,
251257
path: [IndexPathElement],
252258
fields: [String: [Field]]
253-
) throws -> Map {
259+
) throws -> [String: MapRepresentable] {
254260
return try fields.reduce([:]) { results, field in
255261
var results = results
256262
let fieldASTs = field.value
@@ -276,10 +282,10 @@ func executeFieldsSerially(
276282
func executeFields(
277283
exeContext: ExecutionContext,
278284
parentType: GraphQLObjectType,
279-
sourceValue: Map,
285+
sourceValue: MapRepresentable,
280286
path: [IndexPathElement],
281287
fields: [String: [Field]]
282-
) throws -> Map {
288+
) throws -> [String : MapRepresentable] {
283289
return try executeFieldsSerially(
284290
exeContext: exeContext,
285291
parentType: parentType,
@@ -398,25 +404,25 @@ func collectFields(
398404
*/
399405
func shouldIncludeNode(exeContext: ExecutionContext, directives: [Directive] = []) throws -> Bool {
400406
if let skipAST = directives.find({ $0.name.value == GraphQLSkipDirective.name }) {
401-
let skipIf = try getArgumentValues(
407+
let skip = try getArgumentValues(
402408
argDefs: GraphQLSkipDirective.args,
403409
argASTs: skipAST.arguments,
404410
variableValues: exeContext.variableValues
405-
)["if"]
411+
)
406412

407-
if let skipIf = skipIf, skipIf == .bool(true) {
413+
if skip["if"] == .bool(true) {
408414
return false
409415
}
410416
}
411417

412418
if let includeAST = directives.find({ $0.name.value == GraphQLIncludeDirective.name }) {
413-
let includeIf = try getArgumentValues(
419+
let include = try getArgumentValues(
414420
argDefs: GraphQLIncludeDirective.args,
415421
argASTs: includeAST.arguments,
416422
variableValues: exeContext.variableValues
417-
)["if"]
423+
)
418424

419-
if let includeIf = includeIf, includeIf == .bool(false) {
425+
if include["if"] == .bool(false) {
420426
return false
421427
}
422428
}
@@ -467,10 +473,10 @@ func getFieldEntryKey(node: Field) -> String {
467473
func resolveField(
468474
exeContext: ExecutionContext,
469475
parentType: GraphQLObjectType,
470-
source: Map,
476+
source: MapRepresentable,
471477
fieldASTs: [Field],
472478
path: [IndexPathElement]
473-
) throws -> Map {
479+
) throws -> MapRepresentable {
474480
let fieldAST = fieldASTs[0]
475481
let fieldName = fieldAST.name.value
476482

@@ -533,17 +539,17 @@ func resolveField(
533539
}
534540

535541
enum ResultOrError {
536-
case result(Map)
542+
case result(MapRepresentable)
537543
case error(Error)
538544
}
539545

540546
// Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField`
541547
// function. Returns the result of resolveFn or the abrupt-return Error object.
542548
func resolveOrError(
543549
resolve: GraphQLFieldResolve,
544-
source: Map,
545-
args: [String: Map],
546-
context: Map,
550+
source: MapRepresentable,
551+
args: Map,
552+
context: MapRepresentable,
547553
info: GraphQLResolveInfo
548554
)-> ResultOrError {
549555
do {
@@ -562,7 +568,7 @@ func completeValueCatchingError(
562568
info: GraphQLResolveInfo,
563569
path: [IndexPathElement],
564570
result: ResultOrError
565-
) throws -> Map {
571+
) throws -> MapRepresentable {
566572
// If the field type is non-nullable, then it is resolved without any
567573
// protection from errors, however it still properly locates the error.
568574
if let returnType = returnType as? GraphQLNonNull {
@@ -593,7 +599,7 @@ func completeValueCatchingError(
593599
// If `completeValueWithLocatedError` returned abruptly (threw an error),
594600
// log the error and return null.
595601
exeContext.errors.append(error)
596-
return .null
602+
return Map.null
597603
} catch {
598604
fatalError()
599605
}
@@ -608,7 +614,7 @@ func completeValueWithLocatedError(
608614
info: GraphQLResolveInfo,
609615
path: [IndexPathElement],
610616
result: ResultOrError
611-
) throws -> Map {
617+
) throws -> MapRepresentable {
612618
do {
613619
let completed = try completeValue(
614620
exeContext: exeContext,
@@ -657,7 +663,7 @@ func completeValue(
657663
info: GraphQLResolveInfo,
658664
path: [IndexPathElement],
659665
result: ResultOrError
660-
) throws -> Map {
666+
) throws -> MapRepresentable {
661667
switch result {
662668
case .error(let error):
663669
throw error
@@ -674,7 +680,7 @@ func completeValue(
674680
result: .result(result)
675681
)
676682

677-
guard completed != .null else {
683+
guard !isNullish(completed) else {
678684
throw GraphQLError(
679685
message: "Cannot return null for non-nullable field \(info.parentType.name).\(info.fieldName)."
680686
)
@@ -685,7 +691,7 @@ func completeValue(
685691

686692
// If result value is null-ish (null, undefined, or NaN) then return null.
687693
if isNullish(result) {
688-
return .null
694+
return Map.null
689695
}
690696

691697
// If field type is List, complete each item in the list with the inner type
@@ -748,9 +754,9 @@ func completeListValue(
748754
fieldASTs: [Field],
749755
info: GraphQLResolveInfo,
750756
path: [IndexPathElement],
751-
result: Map
752-
) throws -> Map {
753-
guard case .array(let result) = result else {
757+
result: MapRepresentable
758+
) throws -> MapRepresentable {
759+
guard let result = result as? [MapRepresentable] else {
754760
throw GraphQLError(
755761
message:
756762
"Expected Iterable, but did not find one for field " +
@@ -759,7 +765,7 @@ func completeListValue(
759765
}
760766

761767
let itemType = returnType.ofType
762-
var completedResults: [Map] = []
768+
var completedResults: [MapRepresentable] = []
763769

764770
for (index, item) in result.enumerated() {
765771
// No need to modify the info object containing the path,
@@ -778,14 +784,14 @@ func completeListValue(
778784
completedResults.append(completedItem)
779785
}
780786

781-
return .array(completedResults)
787+
return completedResults
782788
}
783789

784790
/**
785791
* Complete a Scalar or Enum by serializing to a valid value, returning
786792
* null if serialization is not possible.
787793
*/
788-
func completeLeafValue(returnType: GraphQLLeafType, result: Map) throws -> Map {
794+
func completeLeafValue(returnType: GraphQLLeafType, result: MapRepresentable) throws -> Map {
789795
let serializedResult = try returnType.serialize(value: result)
790796

791797
if isNullish(serializedResult) {
@@ -809,8 +815,8 @@ func completeAbstractValue(
809815
fieldASTs: [Field],
810816
info: GraphQLResolveInfo,
811817
path: [IndexPathElement],
812-
result: Map
813-
) throws -> Map {
818+
result: MapRepresentable
819+
) throws -> MapRepresentable {
814820
let resolveRes = try returnType.resolveType?(result, exeContext.contextValue, info) ??
815821
defaultResolveType(value: result, context: exeContext.contextValue, info: info, abstractType: returnType).map({ .type($0) })
816822

@@ -869,8 +875,8 @@ func completeObjectValue(
869875
fieldASTs: [Field],
870876
info: GraphQLResolveInfo,
871877
path: [IndexPathElement],
872-
result: Map
873-
) throws -> Map {
878+
result: MapRepresentable
879+
) throws -> MapRepresentable {
874880
// If there is an isTypeOf predicate func, call it with the
875881
// current result. If isTypeOf returns false, then raise an error rather
876882
// than continuing execution.
@@ -913,23 +919,46 @@ func completeObjectValue(
913919
* isTypeOf for the object being coerced, returning the first type that matches.
914920
*/
915921
func defaultResolveType(
916-
value: Map,
917-
context: Map,
922+
value: MapRepresentable,
923+
context: MapRepresentable,
918924
info: GraphQLResolveInfo,
919925
abstractType: GraphQLAbstractType
920926
) -> GraphQLObjectType? {
921927
let possibleTypes = info.schema.getPossibleTypes(abstractType: abstractType)
922928
return possibleTypes.find({ $0.isTypeOf?(value, context, info) ?? false })
923929
}
924930

931+
func unwrap(_ value: MapRepresentable) -> MapRepresentable? {
932+
let mirror = Mirror(reflecting: value)
933+
934+
if mirror.displayStyle != .optional {
935+
return value
936+
}
937+
938+
if mirror.children.isEmpty {
939+
return nil
940+
}
941+
942+
let child = mirror.children.first!
943+
return child.value as? MapRepresentable
944+
}
945+
925946
/**
926947
* If a resolve func is not given, then a default resolve behavior is used
927948
* which takes the property of the source object of the same name as the field
928-
* and returns it as the result, or if it's a func, returns the result
929-
* of calling that func while passing along args and context.
949+
* and returns it as the result.
930950
*/
931-
func defaultResolve(source: Map, args: [String: Map], context: Map, info: GraphQLResolveInfo) -> Map {
932-
return source[info.fieldName]
951+
func defaultResolve(source: MapRepresentable, args: Map, context: MapRepresentable, info: GraphQLResolveInfo) -> MapRepresentable {
952+
print(type(of: source))
953+
guard let source = unwrap(source) else {
954+
return Map.null
955+
}
956+
print(type(of: source))
957+
guard let anyValue = try? get(info.fieldName, from: source), let value = anyValue as? MapRepresentable else {
958+
return Map.null
959+
}
960+
961+
return value
933962
}
934963

935964
/**

Sources/GraphQL/Execution/Values.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ func getVariableValues(schema: GraphQLSchema, definitionASTs: [VariableDefinitio
2323
* Prepares an object map of argument values given a list of argument
2424
* definitions and list of argument AST nodes.
2525
*/
26-
func getArgumentValues(argDefs: [GraphQLArgumentDefinition], argASTs: [Argument]?, variableValues: [String: Map] = [:]) throws -> [String: Map] {
26+
func getArgumentValues(argDefs: [GraphQLArgumentDefinition], argASTs: [Argument]?, variableValues: [String: Map] = [:]) throws -> Map {
2727
guard let argASTs = argASTs else {
2828
return [:]
2929
}
3030

3131
let argASTMap = argASTs.keyMap({ $0.name.value })
3232

3333
return try argDefs.reduce([:]) { result, argDef in
34-
var resultCopy = result
34+
var result = result
3535
let name = argDef.name
3636
let valueAST = argASTMap[name]?.value
3737

@@ -45,11 +45,11 @@ func getArgumentValues(argDefs: [GraphQLArgumentDefinition], argASTs: [Argument]
4545
value = argDef.defaultValue
4646
}
4747

48-
if !isNullish(value) {
49-
resultCopy[name] = value
48+
if let value = value {
49+
result[name] = value
5050
}
5151

52-
return resultCopy
52+
return result
5353
}
5454
}
5555

0 commit comments

Comments
 (0)