-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathinput_values.rb
More file actions
261 lines (236 loc) · 9.29 KB
/
input_values.rb
File metadata and controls
261 lines (236 loc) · 9.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# frozen_string_literal: true
module GraphQL
module Execution
class InputValues
def initialize(query, runner)
@query = query
@runner = runner
@variable_values = nil
end
def variable_values
@variable_values ||= begin
variable_nodes = @query.selected_operation.variables
if variable_nodes.empty?
EmptyObjects::EMPTY_HASH
else
raw_values = @query.provided_variables
values = {}
variable_nodes.each do |var_node|
var_ast_value = if raw_values.key?(var_node.name)
raw_values[var_node.name]
elsif raw_values.key?(sym_name = var_node.name.to_sym)
raw_values[sym_name]
elsif !var_node.default_value.nil?
var_node.default_value
else
next
end
var_type = @runner.schema.type_from_ast(var_node.type, context: @query.context)
values[var_node.name] = variable_value(var_ast_value, var_type)
end
values
end
end
end
def argument_values(owner_defn, argument_nodes, field_resolve_step)
arg_defns = @query.types.arguments(owner_defn)
argument_values = {}
arg_defns.each do |argument_definition|
arg_ruby_key = argument_definition.keyword
arg_graphql_key = argument_definition.graphql_name
arg_node = argument_nodes.find { |a| a.name == arg_graphql_key }
if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
if argument_definition.default_value?
arg_value = value_from_ast(argument_definition.default_value, argument_definition.type)
argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
end
else
arg_value = value_from_ast(arg_node.value, argument_definition.type)
argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
end
end
argument_values
rescue GraphQL::ExecutionError => exec_err
exec_err
end
private
def variable_value(value, type)
if type.non_null?
type = type.of_type
end
if value.is_a?(Language::Nodes::Enum)
value = value.name
end
if value.nil?
nil
elsif type.list?
inner_type = type.of_type
if value.is_a?(Array)
value.map { |v| variable_value(v, inner_type) }.freeze
else
[variable_value(value, inner_type)].freeze
end
elsif type.kind.input_object?
coerced_obj = {}
@query.types.arguments(type).each do |arg|
arg_key = arg.keyword
if value.key?(arg.graphql_name)
arg_value = value[arg.graphql_name]
elsif value.key?(sym_name = arg.graphql_name.to_sym)
arg_value = value[sym_name]
elsif arg.default_value?
coerced_obj[arg_key] = arg.default_value
next
else
next
end
coerced_obj[arg_key] = variable_value(arg_value, arg.type)
end
coerced_obj
elsif type.kind.leaf?
type.coerce_input(value, @query.context)
else
raise GraphQL::Error, "Unexpected input type: #{type.graphql_name}."
end
end
def argument_value(argument_values, argument_key, argument_definition, arg_value, override_type, field_resolve_step)
treat_as_type = override_type || argument_definition.type
if treat_as_type.non_null?
treat_as_type = treat_as_type.of_type
end
if treat_as_type.kind.list? && !arg_value.nil?
inner_t = treat_as_type.unwrap
arg_value = if arg_value.is_a?(Array)
values = Array.new(arg_value.size)
arg_value.each_with_index { |inner_v, idx| argument_value(values, idx, argument_definition, inner_v, inner_t, field_resolve_step)}
values
else
values = [nil]
argument_value(values, 0, argument_definition, arg_value, inner_t, field_resolve_step)
values
end
end
if arg_value && treat_as_type.kind.input_object?
arg_defns = @query.types.arguments(treat_as_type)
new_arg_value = {}
arg_defns.each do |inner_arg_defn|
inner_arg_key = inner_arg_defn.keyword
if arg_value.is_a?(Hash)
if arg_value.key?(inner_arg_key)
inner_arg_value = arg_value[inner_arg_key]
argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
end
else
inner_arg_name = inner_arg_defn.graphql_name
inner_arg_value = arg_value.arguments.find { |a| a.name == inner_arg_name } # rubocop:disable Development/ContextIsPassedCop
if inner_arg_value
argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
end
end
end
arg_value = treat_as_type.new(nil, ruby_kwargs: new_arg_value, context: @query.context, defaults_used: nil)
end
if override_type.nil? # only on root arguments, not list elements
arg_value = begin
argument_definition.prepare_value(nil, arg_value, context: @query.context)
rescue StandardError => err
@runner.schema.handle_or_reraise(@query.context, err)
end
end
if field_resolve_step && arg_value && override_type.nil? && argument_definition.loads
field_defn = field_resolve_step.field_definition
load_receiver = if (r = field_defn.resolver)
r.new(field: field_defn, context: @query.context, object: nil)
else
field_defn
end
ps = field_resolve_step.pending_steps ||= []
if argument_definition.type.list?
results = Array.new(arg_value.size, nil)
argument_values[argument_key] = results
arg_value.each_with_index do |inner_v, idx|
loads_step = LoadArgumentStep.new(
field_resolve_step: field_resolve_step,
load_receiver: load_receiver,
argument_value: inner_v,
argument_definition: argument_definition,
arguments: results,
argument_key: idx,
)
ps.push(loads_step)
@runner.add_step(loads_step)
end
else
loads_step = LoadArgumentStep.new(
field_resolve_step: field_resolve_step,
load_receiver: load_receiver,
argument_value: arg_value,
argument_definition: argument_definition,
arguments: argument_values,
argument_key: argument_key,
)
ps.push(loads_step)
@runner.add_step(loads_step)
end
else
argument_values[argument_key] = arg_value
end
nil
end
def value_from_ast(value_node, type)
if type.non_null?
type = type.of_type
end
if value_node.nil?
nil
elsif value_node.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
variable_values[value_node.name]
elsif value_node.is_a?(GraphQL::Language::Nodes::NullValue)
nil
elsif type.list?
inner_type = type.of_type
if value_node.is_a?(Array)
coerced_items = value_node.map do |inner_value_node|
value_from_ast(inner_value_node, inner_type)
end
coerced_items.freeze
else
item_value = value_from_ast(value_node, inner_type)
[item_value].freeze
end
elsif type.kind.input_object?
coerced_obj = {}
arg_nodes_by_name = value_node.arguments.each_with_object({}) do |arg_node, acc| # rubocop:disable Development/ContextIsPassedCop
acc[arg_node.name] = arg_node
end
@query.types.arguments(type).each do |arg|
arg_node = arg_nodes_by_name[arg.graphql_name]
arg_key = arg.keyword
if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
if arg.default_value?
coerced_obj[arg_key] = arg.default_value
end
next
end
arg_value = value_from_ast(arg_node.value, arg.type)
coerced_obj[arg_key] = arg_value
end
coerced_obj
elsif type.kind.leaf?
if type.kind.enum?
if value_node.is_a?(GraphQL::Language::Nodes::Enum)
value_node = value_node.name
end
end
begin
type.coerce_input(value_node, @query.context)
rescue GraphQL::UnauthorizedEnumValueError => enum_err
@runner.schema.unauthorized_object(enum_err)
end
else
raise "Unexpected input type: #{type.to_type_signature}."
end
end
end
end
end