11import Foundation
2+ import OrderedCollections
23
34/**
45 * Prepares an object map of variableValues of the correct type based on the
56 * provided variable definitions and arbitrary input. If the input cannot be
67 * parsed to match the variable definitions, a GraphQLError will be thrown.
78 */
89func getVariableValues( schema: GraphQLSchema , definitionASTs: [ VariableDefinition ] , inputs: [ String : Map ] ) throws -> [ String : Map ] {
9- return try definitionASTs. reduce ( [ : ] ) { values, defAST in
10- var valuesCopy = values
10+
11+ var vars = [ String: Map] ( )
12+ for defAST in definitionASTs {
1113 let varName = defAST. variable. name. value
12-
13- valuesCopy [ varName] = try getVariableValue (
14+
15+ let input : Map
16+ if let nonNilInput = inputs [ varName] {
17+ input = nonNilInput
18+ } else {
19+ // If variable is not in inputs it is undefined
20+ input = . undefined
21+ }
22+ vars [ varName] = try getVariableValue (
1423 schema: schema,
1524 definitionAST: defAST,
16- input: inputs [ varName ] ?? . null
25+ input: input
1726 )
18-
19- return valuesCopy
2027 }
28+ return vars
2129}
2230
2331
2432/**
2533 * Prepares an object map of argument values given a list of argument
2634 * definitions and list of argument AST nodes.
2735 */
28- func getArgumentValues( argDefs: [ GraphQLArgumentDefinition ] , argASTs: [ Argument ] ? , variableValues : [ String : Map ] = [ : ] ) throws -> Map {
36+ func getArgumentValues( argDefs: [ GraphQLArgumentDefinition ] , argASTs: [ Argument ] ? , variables : [ String : Map ] = [ : ] ) throws -> Map {
2937 guard let argASTs = argASTs else {
3038 return [ : ]
3139 }
3240
3341 let argASTMap = argASTs. keyMap ( { $0. name. value } )
34-
35- return try argDefs . reduce ( [ : ] ) { result , argDef in
36- var result = result
37- let name = argDef. name
38- let argAST = argASTMap [ name ]
42+
43+ var args = OrderedDictionary < String , Map > ( )
44+ for argDef in argDefs {
45+ let argName = argDef. name
46+ let argValue : Map
3947
40- if let argAST = argAST {
41- let valueAST = argAST. value
42-
43- let value = try valueFromAST (
44- valueAST: valueAST,
48+ if let argAST = argASTMap [ argName] {
49+ argValue = try valueFromAST (
50+ valueAST: argAST. value,
4551 type: argDef. type,
46- variables: variableValues
52+ variables: variables
4753 )
48-
49- result [ name] = value
5054 } else {
51- result [ name] = . null
55+ // If AST doesn't contain field, it is undefined
56+ if let defaultValue = argDef. defaultValue {
57+ argValue = defaultValue
58+ } else {
59+ argValue = . undefined
60+ }
5261 }
53-
54- return result
62+
63+ let errors = try validate ( value: argValue, forType: argDef. type)
64+ guard errors. isEmpty else {
65+ let message = " \n " + errors. joined ( separator: " \n " )
66+ throw GraphQLError (
67+ message:
68+ " Argument \" \( argName) \" got invalid value \( argValue) . \( message) " // TODO: "\(JSON.stringify(input)).\(message)",
69+ )
70+ }
71+ args [ argName] = argValue
5572 }
73+ return . dictionary( args)
5674}
5775
5876
@@ -64,112 +82,95 @@ func getVariableValue(schema: GraphQLSchema, definitionAST: VariableDefinition,
6482 let type = typeFromAST ( schema: schema, inputTypeAST: definitionAST. type)
6583 let variable = definitionAST. variable
6684
67- if type == nil || !isInputType ( type : type ) {
85+ guard let inputType = type as? GraphQLInputType else {
6886 throw GraphQLError (
6987 message:
7088 " Variable \" $ \( variable. name. value) \" expected value of type " +
7189 " \" \( definitionAST. type) \" which cannot be used as an input type. " ,
7290 nodes: [ definitionAST]
7391 )
7492 }
75-
76- let inputType = type as! GraphQLInputType
77- let errors = try isValidValue ( value: input, type: inputType)
78-
79- if errors. isEmpty {
80- if input == . null {
81- if let defaultValue = definitionAST. defaultValue {
82- return try valueFromAST ( valueAST: defaultValue, type: inputType)
83- }
84- else if !( inputType is GraphQLNonNull ) {
85- return . null
86- }
87- }
88-
89- return try coerceValue ( type: inputType, value: input) !
93+
94+ var toCoerce = input
95+ if input == . undefined, let defaultValue = definitionAST. defaultValue {
96+ toCoerce = try valueFromAST ( valueAST: defaultValue, type: inputType)
9097 }
91-
92- guard input != . null else {
98+
99+ let errors = try validate ( value: toCoerce, forType: inputType)
100+ guard errors. isEmpty else {
101+ let message = !errors. isEmpty ? " \n " + errors. joined ( separator: " \n " ) : " "
93102 throw GraphQLError (
94103 message:
95- " Variable \" $ \( variable. name. value) \" of required type " +
96- " \" \( definitionAST. type) \" was not provided. " ,
104+ " Variable \" $ \( variable. name. value) \" got invalid value \" \( toCoerce) \" . \( message) " , // TODO: "\(JSON.stringify(input)).\(message)",
97105 nodes: [ definitionAST]
98106 )
99107 }
100-
101- let message = !errors. isEmpty ? " \n " + errors. joined ( separator: " \n " ) : " "
102-
103- throw GraphQLError (
104- message:
105- " Variable \" $ \( variable. name. value) \" got invalid value " +
106- " \( input) . \( message) " , // TODO: "\(JSON.stringify(input)).\(message)",
107- nodes: [ definitionAST]
108- )
108+
109+ return try coerceValue ( value: toCoerce, type: inputType)
109110}
110111
111112/**
112113 * Given a type and any value, return a runtime value coerced to match the type.
113114 */
114- func coerceValue( type : GraphQLInputType , value : Map ) throws -> Map ? {
115+ func coerceValue( value : Map , type : GraphQLInputType ) throws -> Map {
115116 if let nonNull = type as? GraphQLNonNull {
116117 // Note: we're not checking that the result of coerceValue is non-null.
117- // We only call this function after calling isValidValue.
118- return try coerceValue ( type: nonNull. ofType as! GraphQLInputType , value: value) !
118+ // We only call this function after calling validate.
119+ guard let nonNullType = nonNull. ofType as? GraphQLInputType else {
120+ throw GraphQLError ( message: " NonNull must wrap an input type " )
121+ }
122+ return try coerceValue ( value: value, type: nonNullType)
119123 }
120-
121- guard value != . null else {
122- return nil
124+
125+ guard value != . undefined && value != . null else {
126+ return value
123127 }
124128
125129 if let list = type as? GraphQLList {
126- let itemType = list. ofType
130+ guard let itemType = list. ofType as? GraphQLInputType else {
131+ throw GraphQLError ( message: " Input list must wrap an input type " )
132+ }
127133
128134 if case . array( let value) = value {
129- var coercedValues : [ Map ] = [ ]
130-
131- for item in value {
132- coercedValues. append ( try coerceValue ( type: itemType as! GraphQLInputType , value: item) !)
135+ let coercedValues = try value. map { item in
136+ try coerceValue ( value: item, type: itemType)
133137 }
134-
135138 return . array( coercedValues)
136139 }
137-
138- return . array( [ try coerceValue ( type: itemType as! GraphQLInputType , value: value) !] )
140+
141+ // Convert solitary value into single-value array
142+ return . array( [ try coerceValue ( value: value, type: itemType) ] )
139143 }
140144
141- if let type = type as? GraphQLInputObjectType {
145+ if let objectType = type as? GraphQLInputObjectType {
142146 guard case . dictionary( let value) = value else {
143- return nil
147+ throw GraphQLError ( message : " Must be dictionary to extract to an input type " )
144148 }
145149
146- let fields = type. fields
147-
148- return try . dictionary( fields. keys. reduce ( [ : ] ) { obj, fieldName in
149- var objCopy = obj
150- let field = fields [ fieldName]
151-
152- var fieldValue = try coerceValue ( type: field!. type, value: value [ fieldName] ?? . null)
153-
154- if fieldValue == . null {
155- fieldValue = field. flatMap ( { $0. defaultValue } )
150+ let fields = objectType. fields
151+
152+ var object = OrderedDictionary < String , Map > ( )
153+ for (fieldName, field) in fields {
154+ if let fieldValueMap = value [ fieldName] , fieldValueMap != . undefined {
155+ object [ fieldName] = try coerceValue (
156+ value: fieldValueMap,
157+ type: field. type
158+ )
156159 } else {
157- objCopy [ fieldName] = fieldValue
160+ // If AST doesn't contain field, it is undefined
161+ if let defaultValue = field. defaultValue {
162+ object [ fieldName] = defaultValue
163+ } else {
164+ object [ fieldName] = . undefined
165+ }
158166 }
159-
160- return objCopy
161- } )
167+ }
168+ return . dictionary( object)
162169 }
163170
164- guard let type = type as? GraphQLLeafType else {
165- throw GraphQLError ( message : " Must be input type " )
171+ if let leafType = type as? GraphQLLeafType {
172+ return try leafType . parseValue ( value : value )
166173 }
167174
168- let parsed = try type. parseValue ( value: value)
169-
170- guard parsed != . null else {
171- return nil
172- }
173-
174- return parsed
175+ throw GraphQLError ( message: " Provided type is not an input type " )
175176}
0 commit comments