graphql 2.5.11 → 2.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/field_extractor.rb +17 -1
  4. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  5. data/lib/generators/graphql/templates/schema.erb +2 -1
  6. data/lib/graphql/analysis/query_complexity.rb +31 -15
  7. data/lib/graphql/analysis.rb +20 -13
  8. data/lib/graphql/backtrace/table.rb +10 -1
  9. data/lib/graphql/current.rb +7 -1
  10. data/lib/graphql/dashboard/application_controller.rb +45 -0
  11. data/lib/graphql/dashboard/landings_controller.rb +9 -0
  12. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  13. data/lib/graphql/dashboard/subscriptions.rb +2 -1
  14. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +1 -0
  15. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +2 -2
  16. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +1 -1
  17. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +1 -1
  18. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +1 -1
  19. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +1 -1
  20. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +1 -1
  21. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +7 -7
  22. data/lib/graphql/dashboard.rb +14 -73
  23. data/lib/graphql/dataloader/async_dataloader.rb +336 -60
  24. data/lib/graphql/dataloader/null_dataloader.rb +48 -10
  25. data/lib/graphql/dataloader/source.rb +32 -19
  26. data/lib/graphql/dataloader.rb +107 -39
  27. data/lib/graphql/date_encoding_error.rb +1 -1
  28. data/lib/graphql/execution/directive_checks.rb +2 -0
  29. data/lib/graphql/execution/field_resolve_step.rb +804 -0
  30. data/lib/graphql/execution/finalize.rb +229 -0
  31. data/lib/graphql/execution/input_values.rb +333 -0
  32. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -0
  33. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  34. data/lib/graphql/execution/interpreter/resolve.rb +7 -13
  35. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +13 -0
  36. data/lib/graphql/execution/interpreter/runtime.rb +60 -40
  37. data/lib/graphql/execution/interpreter.rb +17 -23
  38. data/lib/graphql/execution/lazy.rb +1 -1
  39. data/lib/graphql/execution/load_argument_step.rb +102 -0
  40. data/lib/graphql/execution/multiplex.rb +1 -1
  41. data/lib/graphql/execution/next.rb +98 -0
  42. data/lib/graphql/execution/prepare_object_step.rb +151 -0
  43. data/lib/graphql/execution/resolve_type_step.rb +27 -0
  44. data/lib/graphql/execution/runner.rb +457 -0
  45. data/lib/graphql/execution/selections_step.rb +95 -0
  46. data/lib/graphql/execution.rb +15 -4
  47. data/lib/graphql/execution_error.rb +17 -12
  48. data/lib/graphql/float_decoding_error.rb +13 -0
  49. data/lib/graphql/float_encoding_error.rb +28 -0
  50. data/lib/graphql/introspection/directive_type.rb +7 -3
  51. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  52. data/lib/graphql/introspection/entry_points.rb +11 -3
  53. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  54. data/lib/graphql/introspection/field_type.rb +13 -5
  55. data/lib/graphql/introspection/input_value_type.rb +21 -13
  56. data/lib/graphql/introspection/schema_type.rb +6 -2
  57. data/lib/graphql/introspection/type_type.rb +64 -28
  58. data/lib/graphql/invalid_null_error.rb +11 -5
  59. data/lib/graphql/language/block_string.rb +6 -11
  60. data/lib/graphql/language/cache.rb +84 -14
  61. data/lib/graphql/language/document_from_schema_definition.rb +2 -1
  62. data/lib/graphql/language/lexer.rb +27 -17
  63. data/lib/graphql/language/nodes.rb +2 -1
  64. data/lib/graphql/language/parser.rb +1 -1
  65. data/lib/graphql/language.rb +32 -17
  66. data/lib/graphql/pagination/connection.rb +2 -0
  67. data/lib/graphql/pagination/connections.rb +30 -0
  68. data/lib/graphql/pagination/relation_connection.rb +10 -1
  69. data/lib/graphql/query/context.rb +10 -3
  70. data/lib/graphql/query/null_context.rb +9 -3
  71. data/lib/graphql/query/partial.rb +18 -3
  72. data/lib/graphql/query/variable_validation_error.rb +16 -1
  73. data/lib/graphql/query/variables.rb +1 -1
  74. data/lib/graphql/query.rb +12 -3
  75. data/lib/graphql/railtie.rb +2 -1
  76. data/lib/graphql/runtime_error.rb +6 -0
  77. data/lib/graphql/schema/argument.rb +13 -1
  78. data/lib/graphql/schema/build_from_definition.rb +28 -1
  79. data/lib/graphql/schema/directive/feature.rb +4 -0
  80. data/lib/graphql/schema/directive/transform.rb +20 -0
  81. data/lib/graphql/schema/directive.rb +48 -13
  82. data/lib/graphql/schema/field/connection_extension.rb +4 -37
  83. data/lib/graphql/schema/field/scope_extension.rb +18 -13
  84. data/lib/graphql/schema/field.rb +79 -48
  85. data/lib/graphql/schema/field_extension.rb +11 -8
  86. data/lib/graphql/schema/has_single_input_argument.rb +24 -13
  87. data/lib/graphql/schema/input_object.rb +6 -2
  88. data/lib/graphql/schema/interface.rb +26 -0
  89. data/lib/graphql/schema/introspection_system.rb +6 -21
  90. data/lib/graphql/schema/list.rb +5 -1
  91. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -11
  92. data/lib/graphql/schema/member/has_arguments.rb +43 -14
  93. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  94. data/lib/graphql/schema/member/has_dataloader.rb +37 -0
  95. data/lib/graphql/schema/member/has_fields.rb +86 -5
  96. data/lib/graphql/schema/member.rb +5 -0
  97. data/lib/graphql/schema/non_null.rb +1 -1
  98. data/lib/graphql/schema/object.rb +1 -0
  99. data/lib/graphql/schema/printer.rb +1 -1
  100. data/lib/graphql/schema/ractor_shareable.rb +1 -0
  101. data/lib/graphql/schema/relay_classic_mutation.rb +16 -2
  102. data/lib/graphql/schema/resolver.rb +76 -1
  103. data/lib/graphql/schema/subscription.rb +53 -10
  104. data/lib/graphql/schema/timeout.rb +2 -2
  105. data/lib/graphql/schema/validator/allow_blank_validator.rb +3 -3
  106. data/lib/graphql/schema/validator/allow_null_validator.rb +3 -3
  107. data/lib/graphql/schema/validator/exclusion_validator.rb +2 -2
  108. data/lib/graphql/schema/validator/format_validator.rb +3 -3
  109. data/lib/graphql/schema/validator/inclusion_validator.rb +2 -2
  110. data/lib/graphql/schema/validator/length_validator.rb +6 -6
  111. data/lib/graphql/schema/validator/numericality_validator.rb +19 -19
  112. data/lib/graphql/schema/validator/required_validator.rb +38 -5
  113. data/lib/graphql/schema/validator.rb +9 -0
  114. data/lib/graphql/schema/visibility/profile.rb +74 -53
  115. data/lib/graphql/schema/visibility/visit.rb +1 -1
  116. data/lib/graphql/schema/visibility.rb +32 -24
  117. data/lib/graphql/schema/wrapper.rb +11 -1
  118. data/lib/graphql/schema.rb +93 -27
  119. data/lib/graphql/static_validation/base_visitor.rb +90 -66
  120. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  121. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +18 -6
  122. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +5 -2
  123. data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -2
  124. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -3
  125. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -4
  126. data/lib/graphql/static_validation/rules/fields_will_merge.rb +351 -248
  127. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +4 -4
  128. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  129. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +10 -7
  130. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +27 -7
  131. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -9
  132. data/lib/graphql/static_validation/validation_context.rb +1 -1
  133. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
  134. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -10
  135. data/lib/graphql/subscriptions/serialize.rb +10 -4
  136. data/lib/graphql/subscriptions.rb +36 -1
  137. data/lib/graphql/testing/helpers.rb +12 -9
  138. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  139. data/lib/graphql/testing.rb +1 -0
  140. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  141. data/lib/graphql/tracing/detailed_trace.rb +70 -7
  142. data/lib/graphql/tracing/perfetto_trace.rb +213 -81
  143. data/lib/graphql/tracing/sentry_trace.rb +3 -1
  144. data/lib/graphql/tracing/trace.rb +6 -0
  145. data/lib/graphql/types/float.rb +18 -4
  146. data/lib/graphql/types/relay/connection_behaviors.rb +8 -6
  147. data/lib/graphql/types/relay/edge_behaviors.rb +4 -3
  148. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  149. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  150. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  151. data/lib/graphql/unauthorized_error.rb +9 -1
  152. data/lib/graphql/version.rb +1 -1
  153. data/lib/graphql.rb +8 -2
  154. metadata +23 -59
@@ -0,0 +1,229 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class Finalize
5
+ def initialize(query, data, runner)
6
+ @query = query
7
+ @data = data
8
+ @static_type_at = runner.static_type_at
9
+ @runner = runner
10
+ @current_exec_path = query.path.dup
11
+ @current_result_path = query.path.dup
12
+ @finalizers = runner.finalizers ? runner.finalizers[query] : {}.compare_by_identity
13
+ @finalizers_count = 0
14
+ @finalizers.each do |key, values|
15
+ values.each do |key2, values2|
16
+ case values2
17
+ when Array
18
+ @finalizers_count += values2.size
19
+ else
20
+ @finalizers_count += 1
21
+ end
22
+ end
23
+ end
24
+
25
+ query.context.errors.each do |err|
26
+ err_path = err.path - @current_exec_path
27
+ key = err_path.pop
28
+ targets = [data]
29
+ while (part = err_path.shift)
30
+ targets.map! { |t| t[part] }
31
+ targets.flatten!
32
+ end
33
+
34
+ targets.each_with_index do |target, idx|
35
+ if target.is_a?(Hash)
36
+ value_at_key = target[key]
37
+ if value_at_key.equal?(err)
38
+ tf = @finalizers[target] ||= {}.compare_by_identity
39
+ tf[key] = err
40
+ @finalizers_count += 1
41
+ elsif value_at_key.is_a?(Array)
42
+ value_at_key.each_with_index do |el, idx|
43
+ if el.equal?(err)
44
+ tf = @finalizers[value_at_key] ||= {}.compare_by_identity
45
+ tf[idx] = err
46
+ @finalizers_count += 1
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def run
56
+ if (selected_operation = @query.selected_operation) && @data
57
+ if @data.is_a?(Hash)
58
+ check_object_result(@data, @query.root_type, selected_operation.selections)
59
+ elsif @data.is_a?(Array)
60
+ check_list_result(@data, @query.root_type, selected_operation.selections)
61
+ elsif @data.is_a?(Finalizer)
62
+ dummy_data = {}
63
+ dummy_key = "__dummy"
64
+ @data.path = @query.path
65
+ @data.finalize_graphql_result(@query, dummy_data, dummy_key)
66
+ dummy_data[dummy_key]
67
+ else
68
+ raise ArgumentError, "Unexpected @data: #{@data.inspect}"
69
+ end
70
+ else
71
+ @data
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def run_finalizers(result_path, finalizer_or_finalizers, result_data, result_key)
78
+ if finalizer_or_finalizers.is_a?(Array)
79
+ finalizer_or_finalizers.each { |f|
80
+ f.path = result_path
81
+ f.finalize_graphql_result(@query, result_data, result_key)
82
+ }
83
+ @finalizers_count -= finalizer_or_finalizers.size
84
+ else
85
+ f = finalizer_or_finalizers
86
+ f.path = result_path
87
+ f.finalize_graphql_result(@query, result_data, result_key)
88
+ @finalizers_count -= 1
89
+ end
90
+ end
91
+
92
+ def finalizers(result_value, key)
93
+ finalizers_for_value = @finalizers[result_value]
94
+ finalizers_for_value && finalizers_for_value[key]
95
+ end
96
+
97
+ def check_object_result(result_h, parent_type, ast_selections)
98
+ if (f = finalizers(result_h, nil))
99
+ run_finalizers(@current_result_path.dup, f, result_h, nil)
100
+ return result_h if @finalizers_count == 0
101
+ end
102
+
103
+ if parent_type.kind.abstract?
104
+ parent_type = @runner.runtime_type_at[result_h]
105
+ end
106
+
107
+ ast_selections.each do |ast_selection|
108
+ case ast_selection
109
+ when Language::Nodes::Field
110
+ key = ast_selection.alias || ast_selection.name
111
+ if (f = finalizers(result_h, key))
112
+ result_value = result_h[key]
113
+ run_finalizers(@current_result_path.dup << key, f, result_h, key)
114
+ new_result_value = result_h.key?(key) ? result_h[key] : :unassigned
115
+ end
116
+ next if !(f || result_h.key?(key))
117
+ begin
118
+ @current_exec_path << key
119
+ @current_result_path << key
120
+
121
+ field_defn = @query.context.types.field(parent_type, ast_selection.name) || raise("Invariant: No field found for #{parent_type.to_type_signature}.#{ast_selection.name}")
122
+ result_type = field_defn.type
123
+ if (result_type_non_null = result_type.non_null?)
124
+ result_type = result_type.of_type
125
+ end
126
+
127
+ if !f
128
+ result_value = result_h[key]
129
+ new_result_value = if result_type.list? && result_value
130
+ check_list_result(result_value, result_type.of_type, ast_selection.selections)
131
+ elsif !result_type.kind.leaf? && result_value
132
+ check_object_result(result_value, result_type, ast_selection.selections)
133
+ else
134
+ result_value
135
+ end
136
+ end
137
+
138
+ if new_result_value.nil? && result_type_non_null
139
+ return nil
140
+ elsif :unassigned.equal?(new_result_value)
141
+ # Do nothing
142
+ break if @finalizers_count == 0
143
+ elsif !new_result_value.equal?(result_value)
144
+ result_h[key] = new_result_value
145
+ break if @finalizers_count == 0
146
+ end
147
+ ensure
148
+ @current_exec_path.pop
149
+ @current_result_path.pop
150
+ end
151
+ when Language::Nodes::InlineFragment
152
+ static_type_at_result = @static_type_at[result_h]
153
+ if static_type_at_result && (
154
+ (t = ast_selection.type).nil? ||
155
+ @runner.type_condition_applies?(@query.context, static_type_at_result, t.name)
156
+ )
157
+ result_h = check_object_result(result_h, parent_type, ast_selection.selections)
158
+ return nil if result_h.nil?
159
+ end
160
+ when Language::Nodes::FragmentSpread
161
+ fragment_defn = @query.document.definitions.find { |defn| defn.is_a?(Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
162
+ static_type_at_result = @static_type_at[result_h]
163
+ if static_type_at_result && @runner.type_condition_applies?(@query.context, static_type_at_result, fragment_defn.type.name)
164
+ result_h = check_object_result(result_h, parent_type, fragment_defn.selections)
165
+ return nil if result_h.nil?
166
+ end
167
+ end
168
+ end
169
+
170
+ result_h
171
+ end
172
+
173
+ def check_list_result(result_arr, inner_type, ast_selections)
174
+ if (inner_type_non_null = inner_type.non_null?)
175
+ inner_type = inner_type.of_type
176
+ end
177
+
178
+ new_invalid_null = false
179
+
180
+ if (f = finalizers(result_arr, nil))
181
+ run_finalizers(@current_result_path.dup, f, result_arr, nil)
182
+ return result_arr if @finalizers_count == 0
183
+ end
184
+
185
+ effective_idx = -1
186
+ result_arr.each_with_index do |result_item, before_idx|
187
+ effective_idx += 1
188
+ @current_result_path << before_idx
189
+ new_result = if (f = finalizers(result_arr, before_idx))
190
+ before_size = result_arr.size
191
+ run_finalizers(@current_result_path.dup, f, result_arr, effective_idx)
192
+ after_size = result_arr.size
193
+ if after_size < before_size
194
+ effective_idx -= 1
195
+ :unassigned
196
+ else
197
+ result_arr[effective_idx]
198
+ end
199
+ elsif inner_type.list? && result_item
200
+ check_list_result(result_item, inner_type.of_type, ast_selections)
201
+ elsif !inner_type.kind.leaf? && result_item
202
+ check_object_result(result_item, inner_type, ast_selections)
203
+ else
204
+ result_item
205
+ end
206
+
207
+ if new_result.nil? && inner_type_non_null
208
+ new_invalid_null = true
209
+ result_arr[effective_idx] = nil
210
+ break if @finalizers_count == 0
211
+ elsif :unassigned.equal?(new_result)
212
+ break if @finalizers_count == 0
213
+ elsif !new_result.equal?(result_item)
214
+ result_arr[effective_idx] = new_result
215
+ break if @finalizers_count == 0
216
+ end
217
+ ensure
218
+ @current_result_path.pop
219
+ end
220
+
221
+ if new_invalid_null
222
+ nil
223
+ else
224
+ result_arr
225
+ end
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class InputValues
5
+ def initialize(query, runner)
6
+ @query = query
7
+ @runner = runner
8
+ @variable_values = nil
9
+ end
10
+
11
+ def variable_values
12
+ @variable_values ||= begin
13
+ variable_nodes = @query.selected_operation.variables
14
+ if variable_nodes.empty?
15
+ EmptyObjects::EMPTY_HASH
16
+ else
17
+ raw_values = @query.provided_variables
18
+ values = {}
19
+ variable_nodes.each do |var_node|
20
+ var_ast_value = if raw_values.key?(var_node.name)
21
+ raw_values[var_node.name]
22
+ elsif raw_values.key?(sym_name = var_node.name.to_sym)
23
+ raw_values[sym_name]
24
+ elsif !var_node.default_value.nil?
25
+ var_node.default_value
26
+ else
27
+ next
28
+ end
29
+
30
+ var_type = @runner.schema.type_from_ast(var_node.type, context: @query.context)
31
+ values[var_node.name] = variable_value(var_ast_value, var_type)
32
+ end
33
+ values
34
+ end
35
+ end
36
+ end
37
+
38
+ def argument_values(owner_defn, argument_nodes, field_resolve_step)
39
+ arg_defns = @query.types.arguments(owner_defn)
40
+ argument_values = {}
41
+ errors = nil
42
+
43
+ arg_defns.each do |argument_definition|
44
+ arg_ruby_key = argument_definition.keyword
45
+ arg_graphql_key = argument_definition.graphql_name
46
+ arg_node = argument_nodes.find { |a| a.name == arg_graphql_key }
47
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
48
+ if argument_definition.default_value?
49
+ arg_value = value_from_ast(argument_definition.default_value, argument_definition.type)
50
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
51
+ end
52
+ else
53
+ arg_value = value_from_ast(arg_node.value, argument_definition.type)
54
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
55
+ end
56
+ rescue GraphQL::RuntimeError => exec_err
57
+ errors ||= []
58
+ errors << exec_err
59
+ end
60
+
61
+ return argument_values, errors
62
+ end
63
+
64
+ private
65
+
66
+ def variable_value(value, type)
67
+ if type.non_null?
68
+ type = type.of_type
69
+ end
70
+
71
+ if value.is_a?(Language::Nodes::Enum)
72
+ value = value.name
73
+ end
74
+
75
+ if value.nil?
76
+ nil
77
+ elsif type.list?
78
+ inner_type = type.of_type
79
+ if value.is_a?(Array)
80
+ value.map { |v| variable_value(v, inner_type) }.freeze
81
+ else
82
+ [variable_value(value, inner_type)].freeze
83
+ end
84
+ elsif type.kind.input_object?
85
+ coerced_obj = {}
86
+
87
+ if value.is_a?(Hash)
88
+ @query.types.arguments(type).each do |arg|
89
+ arg_key = arg.keyword
90
+ if value.key?(arg.graphql_name)
91
+ arg_value = value[arg.graphql_name]
92
+ elsif value.key?(sym_name = arg.graphql_name.to_sym)
93
+ arg_value = value[sym_name]
94
+ elsif arg.default_value?
95
+ coerced_obj[arg_key] = arg.default_value
96
+ next
97
+ else
98
+ next
99
+ end
100
+
101
+ if arg_value.nil? && arg.replace_null_with_default?
102
+ arg_value = arg.default_value
103
+ end
104
+
105
+ coerced_obj[arg_key] = variable_value(arg_value, arg.type)
106
+ end
107
+ else
108
+ @query.types.arguments(type).each do |arg|
109
+ arg_key = arg.keyword
110
+ arg_name = arg.graphql_name
111
+ if (v_node = value.arguments.find { |a| a.name == arg_name }) # rubocop:disable Development/ContextIsPassedCop
112
+ arg_value = v_node.value
113
+ coerced_obj[arg_key] = if arg_value.nil? && arg.replace_null_with_default?
114
+ arg.default_value
115
+ else
116
+ variable_value(arg_value, arg.type)
117
+ end
118
+ elsif arg.default_value?
119
+ coerced_obj[arg_key] = arg.default_value
120
+ else
121
+ # Nothing
122
+ end
123
+ end
124
+ end
125
+
126
+ coerced_obj
127
+ elsif type.kind.leaf?
128
+ type.coerce_input(value, @query.context)
129
+ else
130
+ raise GraphQL::Error, "Unexpected input type: #{type.graphql_name}."
131
+ end
132
+ end
133
+
134
+ def argument_value(argument_values, argument_key, argument_definition, arg_value, override_type, field_resolve_step)
135
+ treat_as_type = override_type || argument_definition.type
136
+ if treat_as_type.non_null?
137
+ if arg_value.nil?
138
+ treat_as_type.coerce_input(arg_value, @query.context)
139
+ end
140
+ treat_as_type = treat_as_type.of_type
141
+ end
142
+
143
+ if arg_value.nil? && argument_definition.replace_null_with_default?
144
+ arg_value = argument_definition.default_value
145
+ end
146
+
147
+ if treat_as_type.kind.list? && !arg_value.nil?
148
+ inner_t = treat_as_type.of_type
149
+ arg_value = if arg_value.is_a?(Array)
150
+ values = Array.new(arg_value.size)
151
+ arg_value.each_with_index { |inner_v, idx| argument_value(values, idx, argument_definition, inner_v, inner_t, field_resolve_step)}
152
+ values
153
+ else
154
+ values = [nil]
155
+ argument_value(values, 0, argument_definition, arg_value, inner_t, field_resolve_step)
156
+ values
157
+ end
158
+ end
159
+
160
+ if arg_value && treat_as_type.kind.input_object?
161
+ arg_defns = @query.types.arguments(treat_as_type)
162
+ new_arg_value = {}
163
+ arg_defns.each do |inner_arg_defn|
164
+ inner_arg_key = inner_arg_defn.keyword
165
+ if arg_value.is_a?(Hash)
166
+ if arg_value.key?(inner_arg_key)
167
+ inner_arg_value = arg_value[inner_arg_key]
168
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
169
+ end
170
+ else
171
+ inner_arg_name = inner_arg_defn.graphql_name
172
+ inner_arg_value = arg_value.arguments.find { |a| a.name == inner_arg_name } # rubocop:disable Development/ContextIsPassedCop
173
+ if inner_arg_value
174
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
175
+ end
176
+ end
177
+ end
178
+ arg_value = treat_as_type.new(nil, ruby_kwargs: new_arg_value, context: @query.context, defaults_used: nil)
179
+ end
180
+
181
+ if override_type.nil? # only on root arguments, not list elements
182
+ arg_value = begin
183
+ argument_definition.prepare_value(nil, arg_value, context: @query.context)
184
+ rescue StandardError => err
185
+ @runner.schema.handle_or_reraise(@query.context, err, object: nil, arguments: argument_values, field: field_resolve_step&.field_definition)
186
+ end
187
+ end
188
+
189
+ if field_resolve_step && arg_value && override_type.nil? && argument_definition.loads
190
+ field_defn = field_resolve_step.field_definition
191
+ load_receiver = if (r = field_defn.resolver)
192
+ r.new(field: field_defn, context: @query.context, object: nil)
193
+ else
194
+ field_defn
195
+ end
196
+ ps = field_resolve_step.pending_steps ||= []
197
+
198
+ if argument_definition.type.list?
199
+ results = Array.new(arg_value.size, nil)
200
+ argument_values[argument_key] = results
201
+ arg_value.each_with_index do |inner_v, idx|
202
+ loads_step = LoadArgumentStep.new(
203
+ field_resolve_step: field_resolve_step,
204
+ load_receiver: load_receiver,
205
+ argument_value: inner_v,
206
+ argument_definition: argument_definition,
207
+ arguments: results,
208
+ argument_key: idx,
209
+ )
210
+ ps.push(loads_step)
211
+ @runner.add_step(loads_step)
212
+ end
213
+ else
214
+ loads_step = LoadArgumentStep.new(
215
+ field_resolve_step: field_resolve_step,
216
+ load_receiver: load_receiver,
217
+ argument_value: arg_value,
218
+ argument_definition: argument_definition,
219
+ arguments: argument_values,
220
+ argument_key: argument_key,
221
+ )
222
+ ps.push(loads_step)
223
+ @runner.add_step(loads_step)
224
+ end
225
+ else
226
+ argument_values[argument_key] = arg_value
227
+ end
228
+ nil
229
+ end
230
+
231
+ def value_from_ast(value_node, type)
232
+ if type.non_null?
233
+ type = type.of_type
234
+ end
235
+
236
+ if value_node.nil?
237
+ nil
238
+ elsif value_node.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
239
+ variable_values[value_node.name]
240
+ elsif type.list?
241
+ inner_type = type.of_type
242
+ if value_node.is_a?(Array)
243
+ coerced_items = value_node.map do |inner_value_node|
244
+ value_from_ast(inner_value_node, inner_type)
245
+ end
246
+ coerced_items.freeze
247
+ elsif value_node.is_a?(Language::Nodes::NullValue)
248
+ nil
249
+ else
250
+ item_value = value_from_ast(value_node, inner_type)
251
+ [item_value].freeze
252
+ end
253
+ elsif type.kind.input_object?
254
+ coerced_obj = {}
255
+ # TODO manually handle NullValue here?
256
+ if value_node.is_a?(Hash)
257
+ @query.types.arguments(type).each do |arg|
258
+ arg_value = value_node[arg.keyword]
259
+ arg_key = arg.keyword
260
+ if arg_value.nil?
261
+ if arg.default_value?
262
+ coerced_obj[arg_key] = arg.default_value
263
+ end
264
+ next
265
+ end
266
+
267
+ coerced_obj[arg_key] = value_from_ast(arg_value, arg.type)
268
+ end
269
+ else
270
+ arg_nodes_by_name = value_node.arguments.each_with_object({}) do |arg_node, acc| # rubocop:disable Development/ContextIsPassedCop
271
+ acc[arg_node.name] = arg_node
272
+ end
273
+
274
+ @query.types.arguments(type).each do |arg|
275
+ arg_node = arg_nodes_by_name[arg.graphql_name]
276
+ arg_key = arg.keyword
277
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
278
+ if arg.default_value?
279
+ coerced_obj[arg_key] = arg.default_value
280
+ end
281
+ next
282
+ end
283
+
284
+ arg_value = value_from_ast(arg_node.value, arg.type)
285
+ coerced_obj[arg_key] = arg_value
286
+ end
287
+ end
288
+
289
+
290
+ coerced_obj
291
+ elsif type.kind.leaf?
292
+ if value_node.is_a?(Language::Nodes::AbstractNode) || value_node.is_a?(Array)
293
+ value_node = coerce_untyped_input(value_node)
294
+ end
295
+
296
+ begin
297
+ type.coerce_input(value_node, @query.context)
298
+ rescue GraphQL::UnauthorizedEnumValueError => enum_err
299
+ @runner.schema.unauthorized_object(enum_err)
300
+ end
301
+ else
302
+ raise "Unexpected input type: #{type.to_type_signature}."
303
+ end
304
+ end
305
+
306
+ private
307
+
308
+ def coerce_untyped_input(input_value)
309
+ case input_value
310
+ when Language::Nodes::AbstractNode
311
+ case input_value
312
+ when Language::Nodes::NullValue
313
+ nil
314
+ when Language::Nodes::Enum
315
+ input_value.name
316
+ when Language::Nodes::InputObject
317
+ value_h = {}
318
+ input_value.arguments.each do |arg| # rubocop:disable Development/ContextIsPassedCop
319
+ value_h[arg.name] = coerce_untyped_input(arg.value)
320
+ end
321
+ value_h
322
+ else
323
+ raise "Unhandled untyped input AST node: #{input_value.class}"
324
+ end
325
+ when Array
326
+ input_value.map { |v| coerce_untyped_input(v) }
327
+ else
328
+ input_value
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end
@@ -30,7 +30,10 @@ module GraphQL
30
30
  @storage[argument_owner][parent_object][ast_node] = resolved_args
31
31
  end
32
32
  end
33
+ end
33
34
 
35
+ def cached_arguments_for(ast_node, argument_owner)
36
+ @storage[argument_owner][nil][ast_node]
34
37
  end
35
38
 
36
39
  # @yield [Interpreter::Arguments, Lazy<Interpreter::Arguments>] The finally-loaded arguments
@@ -5,6 +5,12 @@ module GraphQL
5
5
  class Interpreter
6
6
  # Wrapper for raw values
7
7
  class RawValue
8
+ include GraphQL::Execution::Finalizer
9
+
10
+ def finalize_graphql_result(query, result_data, result_key)
11
+ result_data[result_key] = @object
12
+ end
13
+
8
14
  def initialize(obj = nil)
9
15
  @object = obj
10
16
  end
@@ -6,12 +6,17 @@ module GraphQL
6
6
  module Resolve
7
7
  # Continue field results in `results` until there's nothing else to continue.
8
8
  # @return [void]
9
+ # @deprecated Call `dataloader.run` instead
9
10
  def self.resolve_all(results, dataloader)
11
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
10
12
  dataloader.append_job { resolve(results, dataloader) }
11
13
  nil
12
14
  end
13
15
 
16
+ # @deprecated Call `dataloader.run` instead
14
17
  def self.resolve_each_depth(lazies_at_depth, dataloader)
18
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
19
+
15
20
  smallest_depth = nil
16
21
  lazies_at_depth.each_key do |depth_key|
17
22
  smallest_depth ||= depth_key
@@ -34,20 +39,9 @@ module GraphQL
34
39
  nil
35
40
  end
36
41
 
37
- # After getting `results` back from an interpreter evaluation,
38
- # continue it until you get a response-ready Ruby value.
39
- #
40
- # `results` is one level of _depth_ of a query or multiplex.
41
- #
42
- # Resolve all lazy values in that depth before moving on
43
- # to the next level.
44
- #
45
- # It's assumed that the lazies will
46
- # return {Lazy} instances if there's more work to be done,
47
- # or return {Hash}/{Array} if the query should be continued.
48
- #
49
- # @return [void]
42
+ # @deprecated Call `dataloader.run` instead
50
43
  def self.resolve(results, dataloader)
44
+ warn "#{self}.#{__method__} is deprecated; Use `dataloader.run` instead.#{caller(1, 5).map { |l| "\n #{l}"}.join}"
51
45
  # There might be pending jobs here that _will_ write lazies
52
46
  # into the result hash. We should run them out, so we
53
47
  # can be sure that all lazies will be present in the result hashes.
@@ -42,6 +42,14 @@ module GraphQL
42
42
  end
43
43
  end
44
44
 
45
+ def depth
46
+ @depth ||= if @graphql_parent
47
+ @graphql_parent.depth + 1
48
+ else
49
+ 1
50
+ end
51
+ end
52
+
45
53
  attr_accessor :graphql_dead
46
54
  attr_reader :graphql_parent, :graphql_result_name, :graphql_is_non_null_in_parent,
47
55
  :graphql_application_value, :graphql_result_type, :graphql_selections, :graphql_is_eager, :ast_node, :graphql_arguments, :graphql_field
@@ -157,6 +165,11 @@ module GraphQL
157
165
  end
158
166
  end
159
167
  end
168
+
169
+ # hook for breadth-first implementations to signal when collecting results.
170
+ def collect_result(result_name, result_value)
171
+ false
172
+ end
160
173
  end
161
174
 
162
175
  class GraphQLResultArray