27
27
final class ExecutionContext {
28
28
let schema : GraphQLSchema
29
29
let fragments : [ String : FragmentDefinition ]
30
- let rootValue : Map
31
- let contextValue : Map
30
+ let rootValue : MapRepresentable
31
+ let contextValue : MapRepresentable
32
32
let operation : OperationDefinition
33
33
let variableValues : [ String : Map ]
34
34
var errors : [ GraphQLError ]
35
35
36
36
init (
37
37
schema: GraphQLSchema ,
38
38
fragments: [ String : FragmentDefinition ] ,
39
- rootValue: Map ,
40
- contextValue: Map ,
39
+ rootValue: MapRepresentable ,
40
+ contextValue: MapRepresentable ,
41
41
operation: OperationDefinition ,
42
42
variableValues: [ String : Map ] ,
43
43
errors: [ GraphQLError ]
@@ -64,8 +64,8 @@ final class ExecutionContext {
64
64
func execute(
65
65
schema: GraphQLSchema ,
66
66
documentAST: Document ,
67
- rootValue: Map ,
68
- contextValue: Map ,
67
+ rootValue: MapRepresentable ,
68
+ contextValue: MapRepresentable ,
69
69
variableValues: [ String : Map ] = [ : ] ,
70
70
operationName: String ? = nil
71
71
) throws -> Map {
@@ -88,7 +88,13 @@ func execute(
88
88
rootValue: rootValue
89
89
)
90
90
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]
92
98
93
99
if !context. errors. isEmpty {
94
100
result [ " errors " ] = context. errors. map
@@ -109,8 +115,8 @@ func execute(
109
115
func buildExecutionContext(
110
116
schema: GraphQLSchema ,
111
117
documentAST: Document ,
112
- rootValue: Map ,
113
- contextValue: Map ,
118
+ rootValue: MapRepresentable ,
119
+ contextValue: MapRepresentable ,
114
120
rawVariableValues: [ String : Map ] ,
115
121
operationName: String ?
116
122
) throws -> ExecutionContext {
@@ -173,8 +179,8 @@ func buildExecutionContext(
173
179
func executeOperation(
174
180
exeContext: ExecutionContext ,
175
181
operation: OperationDefinition ,
176
- rootValue: Map
177
- ) throws -> Map {
182
+ rootValue: MapRepresentable
183
+ ) throws -> [ String : MapRepresentable ] {
178
184
let type = try getOperationRootType ( schema: exeContext. schema, operation: operation)
179
185
180
186
var inputFields : [ String : [ Field ] ] = [ : ]
@@ -247,10 +253,10 @@ func getOperationRootType(
247
253
func executeFieldsSerially(
248
254
exeContext: ExecutionContext ,
249
255
parentType: GraphQLObjectType ,
250
- sourceValue: Map ,
256
+ sourceValue: MapRepresentable ,
251
257
path: [ IndexPathElement ] ,
252
258
fields: [ String : [ Field ] ]
253
- ) throws -> Map {
259
+ ) throws -> [ String : MapRepresentable ] {
254
260
return try fields. reduce ( [ : ] ) { results, field in
255
261
var results = results
256
262
let fieldASTs = field. value
@@ -276,10 +282,10 @@ func executeFieldsSerially(
276
282
func executeFields(
277
283
exeContext: ExecutionContext ,
278
284
parentType: GraphQLObjectType ,
279
- sourceValue: Map ,
285
+ sourceValue: MapRepresentable ,
280
286
path: [ IndexPathElement ] ,
281
287
fields: [ String : [ Field ] ]
282
- ) throws -> Map {
288
+ ) throws -> [ String : MapRepresentable ] {
283
289
return try executeFieldsSerially (
284
290
exeContext: exeContext,
285
291
parentType: parentType,
@@ -398,25 +404,25 @@ func collectFields(
398
404
*/
399
405
func shouldIncludeNode( exeContext: ExecutionContext , directives: [ Directive ] = [ ] ) throws -> Bool {
400
406
if let skipAST = directives. find ( { $0. name. value == GraphQLSkipDirective . name } ) {
401
- let skipIf = try getArgumentValues (
407
+ let skip = try getArgumentValues (
402
408
argDefs: GraphQLSkipDirective . args,
403
409
argASTs: skipAST. arguments,
404
410
variableValues: exeContext. variableValues
405
- ) [ " if " ]
411
+ )
406
412
407
- if let skipIf = skipIf , skipIf == . bool( true ) {
413
+ if skip [ " if " ] == . bool( true ) {
408
414
return false
409
415
}
410
416
}
411
417
412
418
if let includeAST = directives. find ( { $0. name. value == GraphQLIncludeDirective . name } ) {
413
- let includeIf = try getArgumentValues (
419
+ let include = try getArgumentValues (
414
420
argDefs: GraphQLIncludeDirective . args,
415
421
argASTs: includeAST. arguments,
416
422
variableValues: exeContext. variableValues
417
- ) [ " if " ]
423
+ )
418
424
419
- if let includeIf = includeIf , includeIf == . bool( false ) {
425
+ if include [ " if " ] == . bool( false ) {
420
426
return false
421
427
}
422
428
}
@@ -467,10 +473,10 @@ func getFieldEntryKey(node: Field) -> String {
467
473
func resolveField(
468
474
exeContext: ExecutionContext ,
469
475
parentType: GraphQLObjectType ,
470
- source: Map ,
476
+ source: MapRepresentable ,
471
477
fieldASTs: [ Field ] ,
472
478
path: [ IndexPathElement ]
473
- ) throws -> Map {
479
+ ) throws -> MapRepresentable {
474
480
let fieldAST = fieldASTs [ 0 ]
475
481
let fieldName = fieldAST. name. value
476
482
@@ -533,17 +539,17 @@ func resolveField(
533
539
}
534
540
535
541
enum ResultOrError {
536
- case result( Map )
542
+ case result( MapRepresentable )
537
543
case error( Error )
538
544
}
539
545
540
546
// Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField`
541
547
// function. Returns the result of resolveFn or the abrupt-return Error object.
542
548
func resolveOrError(
543
549
resolve: GraphQLFieldResolve ,
544
- source: Map ,
545
- args: [ String : Map ] ,
546
- context: Map ,
550
+ source: MapRepresentable ,
551
+ args: Map ,
552
+ context: MapRepresentable ,
547
553
info: GraphQLResolveInfo
548
554
) -> ResultOrError {
549
555
do {
@@ -562,7 +568,7 @@ func completeValueCatchingError(
562
568
info: GraphQLResolveInfo ,
563
569
path: [ IndexPathElement ] ,
564
570
result: ResultOrError
565
- ) throws -> Map {
571
+ ) throws -> MapRepresentable {
566
572
// If the field type is non-nullable, then it is resolved without any
567
573
// protection from errors, however it still properly locates the error.
568
574
if let returnType = returnType as? GraphQLNonNull {
@@ -593,7 +599,7 @@ func completeValueCatchingError(
593
599
// If `completeValueWithLocatedError` returned abruptly (threw an error),
594
600
// log the error and return null.
595
601
exeContext. errors. append ( error)
596
- return . null
602
+ return Map . null
597
603
} catch {
598
604
fatalError ( )
599
605
}
@@ -608,7 +614,7 @@ func completeValueWithLocatedError(
608
614
info: GraphQLResolveInfo ,
609
615
path: [ IndexPathElement ] ,
610
616
result: ResultOrError
611
- ) throws -> Map {
617
+ ) throws -> MapRepresentable {
612
618
do {
613
619
let completed = try completeValue (
614
620
exeContext: exeContext,
@@ -657,7 +663,7 @@ func completeValue(
657
663
info: GraphQLResolveInfo ,
658
664
path: [ IndexPathElement ] ,
659
665
result: ResultOrError
660
- ) throws -> Map {
666
+ ) throws -> MapRepresentable {
661
667
switch result {
662
668
case . error( let error) :
663
669
throw error
@@ -674,7 +680,7 @@ func completeValue(
674
680
result: . result( result)
675
681
)
676
682
677
- guard completed != . null else {
683
+ guard !isNullish ( completed ) else {
678
684
throw GraphQLError (
679
685
message: " Cannot return null for non-nullable field \( info. parentType. name) . \( info. fieldName) . "
680
686
)
@@ -685,7 +691,7 @@ func completeValue(
685
691
686
692
// If result value is null-ish (null, undefined, or NaN) then return null.
687
693
if isNullish ( result) {
688
- return . null
694
+ return Map . null
689
695
}
690
696
691
697
// If field type is List, complete each item in the list with the inner type
@@ -748,9 +754,9 @@ func completeListValue(
748
754
fieldASTs: [ Field ] ,
749
755
info: GraphQLResolveInfo ,
750
756
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 {
754
760
throw GraphQLError (
755
761
message:
756
762
" Expected Iterable, but did not find one for field " +
@@ -759,7 +765,7 @@ func completeListValue(
759
765
}
760
766
761
767
let itemType = returnType. ofType
762
- var completedResults : [ Map ] = [ ]
768
+ var completedResults : [ MapRepresentable ] = [ ]
763
769
764
770
for (index, item) in result. enumerated ( ) {
765
771
// No need to modify the info object containing the path,
@@ -778,14 +784,14 @@ func completeListValue(
778
784
completedResults. append ( completedItem)
779
785
}
780
786
781
- return . array ( completedResults)
787
+ return completedResults
782
788
}
783
789
784
790
/**
785
791
* Complete a Scalar or Enum by serializing to a valid value, returning
786
792
* null if serialization is not possible.
787
793
*/
788
- func completeLeafValue( returnType: GraphQLLeafType , result: Map ) throws -> Map {
794
+ func completeLeafValue( returnType: GraphQLLeafType , result: MapRepresentable ) throws -> Map {
789
795
let serializedResult = try returnType. serialize ( value: result)
790
796
791
797
if isNullish ( serializedResult) {
@@ -809,8 +815,8 @@ func completeAbstractValue(
809
815
fieldASTs: [ Field ] ,
810
816
info: GraphQLResolveInfo ,
811
817
path: [ IndexPathElement ] ,
812
- result: Map
813
- ) throws -> Map {
818
+ result: MapRepresentable
819
+ ) throws -> MapRepresentable {
814
820
let resolveRes = try returnType. resolveType ? ( result, exeContext. contextValue, info) ??
815
821
defaultResolveType ( value: result, context: exeContext. contextValue, info: info, abstractType: returnType) . map ( { . type( $0) } )
816
822
@@ -869,8 +875,8 @@ func completeObjectValue(
869
875
fieldASTs: [ Field ] ,
870
876
info: GraphQLResolveInfo ,
871
877
path: [ IndexPathElement ] ,
872
- result: Map
873
- ) throws -> Map {
878
+ result: MapRepresentable
879
+ ) throws -> MapRepresentable {
874
880
// If there is an isTypeOf predicate func, call it with the
875
881
// current result. If isTypeOf returns false, then raise an error rather
876
882
// than continuing execution.
@@ -913,23 +919,46 @@ func completeObjectValue(
913
919
* isTypeOf for the object being coerced, returning the first type that matches.
914
920
*/
915
921
func defaultResolveType(
916
- value: Map ,
917
- context: Map ,
922
+ value: MapRepresentable ,
923
+ context: MapRepresentable ,
918
924
info: GraphQLResolveInfo ,
919
925
abstractType: GraphQLAbstractType
920
926
) -> GraphQLObjectType ? {
921
927
let possibleTypes = info. schema. getPossibleTypes ( abstractType: abstractType)
922
928
return possibleTypes. find ( { $0. isTypeOf ? ( value, context, info) ?? false } )
923
929
}
924
930
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
+
925
946
/**
926
947
* If a resolve func is not given, then a default resolve behavior is used
927
948
* 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.
930
950
*/
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
933
962
}
934
963
935
964
/**
0 commit comments