graphql 2.5.9 → 2.5.26

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/detailed_trace_generator.rb +77 -0
  3. data/lib/generators/graphql/templates/create_graphql_detailed_traces.erb +10 -0
  4. data/lib/graphql/analysis.rb +20 -13
  5. data/lib/graphql/dashboard/application_controller.rb +41 -0
  6. data/lib/graphql/dashboard/landings_controller.rb +9 -0
  7. data/lib/graphql/dashboard/statics_controller.rb +31 -0
  8. data/lib/graphql/dashboard/subscriptions.rb +2 -1
  9. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +1 -0
  10. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +2 -2
  11. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +1 -1
  12. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +1 -1
  13. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +1 -1
  14. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +1 -1
  15. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +1 -1
  16. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +7 -7
  17. data/lib/graphql/dashboard.rb +11 -73
  18. data/lib/graphql/dataloader/active_record_association_source.rb +14 -2
  19. data/lib/graphql/dataloader/async_dataloader.rb +22 -11
  20. data/lib/graphql/dataloader/null_dataloader.rb +54 -9
  21. data/lib/graphql/dataloader.rb +75 -23
  22. data/lib/graphql/date_encoding_error.rb +1 -1
  23. data/lib/graphql/execution/field_resolve_step.rb +631 -0
  24. data/lib/graphql/execution/finalize.rb +217 -0
  25. data/lib/graphql/execution/input_values.rb +261 -0
  26. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  27. data/lib/graphql/execution/interpreter/resolve.rb +10 -16
  28. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +13 -0
  29. data/lib/graphql/execution/interpreter/runtime.rb +28 -33
  30. data/lib/graphql/execution/interpreter.rb +8 -22
  31. data/lib/graphql/execution/lazy.rb +1 -1
  32. data/lib/graphql/execution/load_argument_step.rb +64 -0
  33. data/lib/graphql/execution/multiplex.rb +1 -1
  34. data/lib/graphql/execution/next.rb +90 -0
  35. data/lib/graphql/execution/prepare_object_step.rb +128 -0
  36. data/lib/graphql/execution/runner.rb +410 -0
  37. data/lib/graphql/execution/selections_step.rb +91 -0
  38. data/lib/graphql/execution.rb +8 -4
  39. data/lib/graphql/execution_error.rb +17 -10
  40. data/lib/graphql/introspection/directive_type.rb +7 -3
  41. data/lib/graphql/introspection/dynamic_fields.rb +5 -1
  42. data/lib/graphql/introspection/entry_points.rb +11 -3
  43. data/lib/graphql/introspection/enum_value_type.rb +5 -5
  44. data/lib/graphql/introspection/field_type.rb +13 -5
  45. data/lib/graphql/introspection/input_value_type.rb +21 -13
  46. data/lib/graphql/introspection/type_type.rb +64 -28
  47. data/lib/graphql/invalid_null_error.rb +11 -5
  48. data/lib/graphql/language/document_from_schema_definition.rb +2 -1
  49. data/lib/graphql/language/lexer.rb +20 -9
  50. data/lib/graphql/language/nodes.rb +5 -1
  51. data/lib/graphql/language/parser.rb +1 -0
  52. data/lib/graphql/language.rb +21 -12
  53. data/lib/graphql/pagination/connection.rb +2 -0
  54. data/lib/graphql/pagination/connections.rb +32 -0
  55. data/lib/graphql/query/context.rb +11 -4
  56. data/lib/graphql/query/null_context.rb +9 -3
  57. data/lib/graphql/query/partial.rb +18 -3
  58. data/lib/graphql/query.rb +10 -1
  59. data/lib/graphql/runtime_error.rb +6 -0
  60. data/lib/graphql/schema/addition.rb +3 -1
  61. data/lib/graphql/schema/argument.rb +17 -0
  62. data/lib/graphql/schema/build_from_definition.rb +15 -2
  63. data/lib/graphql/schema/directive.rb +45 -13
  64. data/lib/graphql/schema/field/connection_extension.rb +4 -37
  65. data/lib/graphql/schema/field/scope_extension.rb +18 -13
  66. data/lib/graphql/schema/field.rb +87 -48
  67. data/lib/graphql/schema/field_extension.rb +11 -8
  68. data/lib/graphql/schema/interface.rb +26 -0
  69. data/lib/graphql/schema/list.rb +5 -1
  70. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -11
  71. data/lib/graphql/schema/member/has_arguments.rb +43 -14
  72. data/lib/graphql/schema/member/has_authorization.rb +35 -0
  73. data/lib/graphql/schema/member/has_dataloader.rb +37 -0
  74. data/lib/graphql/schema/member/has_fields.rb +86 -5
  75. data/lib/graphql/schema/member/has_interfaces.rb +2 -2
  76. data/lib/graphql/schema/member/type_system_helpers.rb +16 -2
  77. data/lib/graphql/schema/member.rb +5 -0
  78. data/lib/graphql/schema/non_null.rb +1 -1
  79. data/lib/graphql/schema/object.rb +1 -0
  80. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  81. data/lib/graphql/schema/resolver.rb +60 -1
  82. data/lib/graphql/schema/subscription.rb +0 -2
  83. data/lib/graphql/schema/validator/required_validator.rb +45 -5
  84. data/lib/graphql/schema/visibility/migration.rb +2 -2
  85. data/lib/graphql/schema/visibility/profile.rb +140 -56
  86. data/lib/graphql/schema/visibility.rb +31 -18
  87. data/lib/graphql/schema/wrapper.rb +7 -1
  88. data/lib/graphql/schema.rb +108 -32
  89. data/lib/graphql/static_validation/all_rules.rb +1 -1
  90. data/lib/graphql/static_validation/base_visitor.rb +90 -66
  91. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  92. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +18 -6
  93. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +5 -2
  94. data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -2
  95. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -3
  96. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +14 -4
  97. data/lib/graphql/static_validation/rules/fields_will_merge.rb +322 -256
  98. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +4 -4
  99. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  100. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +10 -7
  101. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +27 -7
  102. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +6 -2
  103. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -9
  104. data/lib/graphql/static_validation/validation_context.rb +1 -1
  105. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
  106. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +34 -10
  107. data/lib/graphql/subscriptions/event.rb +1 -0
  108. data/lib/graphql/subscriptions.rb +36 -1
  109. data/lib/graphql/testing/helpers.rb +12 -9
  110. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  111. data/lib/graphql/testing.rb +1 -0
  112. data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
  113. data/lib/graphql/tracing/detailed_trace.rb +70 -7
  114. data/lib/graphql/tracing/null_trace.rb +1 -1
  115. data/lib/graphql/tracing/perfetto_trace.rb +209 -79
  116. data/lib/graphql/tracing/sentry_trace.rb +3 -1
  117. data/lib/graphql/tracing/trace.rb +6 -0
  118. data/lib/graphql/type_kinds.rb +1 -0
  119. data/lib/graphql/types/relay/connection_behaviors.rb +8 -6
  120. data/lib/graphql/types/relay/edge_behaviors.rb +4 -3
  121. data/lib/graphql/types/relay/has_node_field.rb +13 -8
  122. data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
  123. data/lib/graphql/types/relay/node_behaviors.rb +13 -2
  124. data/lib/graphql/unauthorized_error.rb +9 -1
  125. data/lib/graphql/version.rb +1 -1
  126. data/lib/graphql.rb +7 -3
  127. metadata +21 -3
@@ -0,0 +1,217 @@
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
+ if target[key].equal?(err)
37
+ tf = @finalizers[target] ||= {}.compare_by_identity
38
+ tf[key] = err
39
+ @finalizers_count += 1
40
+ elsif (arr = target[key]).is_a?(Array)
41
+ arr.each_with_index do |el, idx|
42
+ if el.equal?(err)
43
+ tf = @finalizers[arr] ||= {}.compare_by_identity
44
+ tf[idx] = err
45
+ @finalizers_count += 1
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def run
55
+ if (selected_operation = @query.selected_operation) && @data
56
+ if @data.is_a?(Hash)
57
+ check_object_result(@data, @query.root_type, selected_operation.selections)
58
+ elsif @data.is_a?(Array)
59
+ check_list_result(@data, @query.root_type, selected_operation.selections)
60
+ elsif @data.is_a?(Finalizer)
61
+ dummy_data = {}
62
+ dummy_key = "__dummy"
63
+ @data.path = @query.path
64
+ @data.finalize_graphql_result(@query, dummy_data, dummy_key)
65
+ dummy_data[dummy_key]
66
+ else
67
+ raise ArgumentError, "Unexpected @data: #{@data.inspect}"
68
+ end
69
+ else
70
+ @data
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def run_finalizers(result_path, finalizer_or_finalizers, result_data, result_key)
77
+ if finalizer_or_finalizers.is_a?(Array)
78
+ finalizer_or_finalizers.each { |f|
79
+ f.path = result_path
80
+ f.finalize_graphql_result(@query, result_data, result_key)
81
+ }
82
+ @finalizers_count -= finalizer_or_finalizers.size
83
+ else
84
+ f = finalizer_or_finalizers
85
+ f.path = result_path
86
+ f.finalize_graphql_result(@query, result_data, result_key)
87
+ @finalizers_count -= 1
88
+ end
89
+ end
90
+
91
+ def finalizers(result_value, key)
92
+ finalizers_for_value = @finalizers[result_value]
93
+ finalizers_for_value && finalizers_for_value[key]
94
+ end
95
+
96
+ def check_object_result(result_h, parent_type, ast_selections)
97
+ if (f = finalizers(result_h, nil))
98
+ run_finalizers(@current_result_path.dup, f, result_h, nil)
99
+ return result_h if @finalizers_count == 0
100
+ end
101
+
102
+ if parent_type.kind.abstract?
103
+ parent_type = @runner.runtime_type_at[result_h]
104
+ end
105
+
106
+ ast_selections.each do |ast_selection|
107
+ case ast_selection
108
+ when Language::Nodes::Field
109
+ key = ast_selection.alias || ast_selection.name
110
+ if (f = finalizers(result_h, key))
111
+ result_value = result_h[key]
112
+ run_finalizers(@current_result_path.dup << key, f, result_h, key)
113
+ new_result_value = result_h.key?(key) ? result_h[key] : :unassigned
114
+ end
115
+ next if !(f || result_h.key?(key))
116
+ begin
117
+ @current_exec_path << key
118
+ @current_result_path << key
119
+
120
+ field_defn = @query.context.types.field(parent_type, ast_selection.name) || raise("Invariant: No field found for #{static_type.to_type_signature}.#{ast_selection.name}")
121
+ result_type = field_defn.type
122
+ if (result_type_non_null = result_type.non_null?)
123
+ result_type = result_type.of_type
124
+ end
125
+
126
+ if !f
127
+ result_value = result_h[key]
128
+ new_result_value = if result_type.list? && result_value
129
+ check_list_result(result_value, result_type.of_type, ast_selection.selections)
130
+ elsif !result_type.kind.leaf? && result_value
131
+ check_object_result(result_value, result_type, ast_selection.selections)
132
+ else
133
+ result_value
134
+ end
135
+ end
136
+
137
+ if new_result_value.nil? && result_type_non_null
138
+ return nil
139
+ elsif :unassigned.equal?(new_result_value)
140
+ # Do nothing
141
+ break if @finalizers_count == 0
142
+ elsif !new_result_value.equal?(result_value)
143
+ result_h[key] = new_result_value
144
+ break if @finalizers_count == 0
145
+ end
146
+ ensure
147
+ @current_exec_path.pop
148
+ @current_result_path.pop
149
+ end
150
+ when Language::Nodes::InlineFragment
151
+ static_type_at_result = @static_type_at[result_h]
152
+ if static_type_at_result && (
153
+ (t = ast_selection.type).nil? ||
154
+ @runner.type_condition_applies?(@query.context, static_type_at_result, t.name)
155
+ )
156
+ result_h = check_object_result(result_h, parent_type, ast_selection.selections)
157
+ end
158
+ when Language::Nodes::FragmentSpread
159
+ fragment_defn = @query.document.definitions.find { |defn| defn.is_a?(Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
160
+ static_type_at_result = @static_type_at[result_h]
161
+ if static_type_at_result && @runner.type_condition_applies?(@query.context, static_type_at_result, fragment_defn.type.name)
162
+ result_h = check_object_result(result_h, parent_type, fragment_defn.selections)
163
+ end
164
+ end
165
+ end
166
+
167
+ result_h
168
+ end
169
+
170
+ def check_list_result(result_arr, inner_type, ast_selections)
171
+ inner_type_non_null = false
172
+ if inner_type.non_null?
173
+ inner_type_non_null = true
174
+ inner_type = inner_type.of_type
175
+ end
176
+
177
+ new_invalid_null = false
178
+
179
+ if (f = finalizers(result_arr, nil))
180
+ run_finalizers(@current_result_path.dup, f, result_arr, nil)
181
+ return result_arr if @finalizers_count == 0
182
+ end
183
+
184
+ result_arr.each_with_index do |result_item, idx|
185
+ @current_result_path << idx
186
+ new_result = if (f = finalizers(result_arr, idx))
187
+ run_finalizers(@current_result_path.dup, f, result_arr, idx)
188
+ result_arr[idx]
189
+ elsif inner_type.list? && result_item
190
+ check_list_result(result_item, inner_type.of_type, ast_selections)
191
+ elsif !inner_type.kind.leaf? && result_item
192
+ check_object_result(result_item, inner_type, ast_selections)
193
+ else
194
+ result_item
195
+ end
196
+
197
+ if new_result.nil? && inner_type_non_null
198
+ new_invalid_null = true
199
+ result_arr[idx] = nil
200
+ break if @finalizers_count == 0
201
+ elsif !new_result.equal?(result_item)
202
+ result_arr[idx] = new_result
203
+ break if @finalizers_count == 0
204
+ end
205
+ ensure
206
+ @current_result_path.pop
207
+ end
208
+
209
+ if new_invalid_null
210
+ nil
211
+ else
212
+ result_arr
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,261 @@
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
+
42
+ arg_defns.each do |argument_definition|
43
+ arg_ruby_key = argument_definition.keyword
44
+ arg_graphql_key = argument_definition.graphql_name
45
+ arg_node = argument_nodes.find { |a| a.name == arg_graphql_key }
46
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
47
+ if argument_definition.default_value?
48
+ arg_value = value_from_ast(argument_definition.default_value, argument_definition.type)
49
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
50
+ end
51
+ else
52
+ arg_value = value_from_ast(arg_node.value, argument_definition.type)
53
+ argument_value(argument_values, arg_ruby_key, argument_definition, arg_value, nil, field_resolve_step)
54
+ end
55
+ end
56
+
57
+ argument_values
58
+ rescue GraphQL::ExecutionError => exec_err
59
+ exec_err
60
+ end
61
+
62
+ private
63
+
64
+ def variable_value(value, type)
65
+ if type.non_null?
66
+ type = type.of_type
67
+ end
68
+
69
+ if value.is_a?(Language::Nodes::Enum)
70
+ value = value.name
71
+ end
72
+
73
+ if value.nil?
74
+ nil
75
+ elsif type.list?
76
+ inner_type = type.of_type
77
+ if value.is_a?(Array)
78
+ value.map { |v| variable_value(v, inner_type) }.freeze
79
+ else
80
+ [variable_value(value, inner_type)].freeze
81
+ end
82
+ elsif type.kind.input_object?
83
+ coerced_obj = {}
84
+
85
+ @query.types.arguments(type).each do |arg|
86
+ arg_key = arg.keyword
87
+ if value.key?(arg.graphql_name)
88
+ arg_value = value[arg.graphql_name]
89
+ elsif value.key?(sym_name = arg.graphql_name.to_sym)
90
+ arg_value = value[sym_name]
91
+ elsif arg.default_value?
92
+ coerced_obj[arg_key] = arg.default_value
93
+ next
94
+ else
95
+ next
96
+ end
97
+
98
+ coerced_obj[arg_key] = variable_value(arg_value, arg.type)
99
+ end
100
+
101
+ coerced_obj
102
+ elsif type.kind.leaf?
103
+ type.coerce_input(value, @query.context)
104
+ else
105
+ raise GraphQL::Error, "Unexpected input type: #{type.graphql_name}."
106
+ end
107
+ end
108
+
109
+ def argument_value(argument_values, argument_key, argument_definition, arg_value, override_type, field_resolve_step)
110
+ treat_as_type = override_type || argument_definition.type
111
+ if treat_as_type.non_null?
112
+ treat_as_type = treat_as_type.of_type
113
+ end
114
+
115
+ if treat_as_type.kind.list? && !arg_value.nil?
116
+ inner_t = treat_as_type.unwrap
117
+ arg_value = if arg_value.is_a?(Array)
118
+ values = Array.new(arg_value.size)
119
+ arg_value.each_with_index { |inner_v, idx| argument_value(values, idx, argument_definition, inner_v, inner_t, field_resolve_step)}
120
+ values
121
+ else
122
+ values = [nil]
123
+ argument_value(values, 0, argument_definition, arg_value, inner_t, field_resolve_step)
124
+ values
125
+ end
126
+ end
127
+
128
+ if arg_value && treat_as_type.kind.input_object?
129
+ arg_defns = @query.types.arguments(treat_as_type)
130
+ new_arg_value = {}
131
+ arg_defns.each do |inner_arg_defn|
132
+ inner_arg_key = inner_arg_defn.keyword
133
+ if arg_value.is_a?(Hash)
134
+ if arg_value.key?(inner_arg_key)
135
+ inner_arg_value = arg_value[inner_arg_key]
136
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
137
+ end
138
+ else
139
+ inner_arg_name = inner_arg_defn.graphql_name
140
+ inner_arg_value = arg_value.arguments.find { |a| a.name == inner_arg_name } # rubocop:disable Development/ContextIsPassedCop
141
+ if inner_arg_value
142
+ argument_value(new_arg_value, inner_arg_key, inner_arg_defn, inner_arg_value, nil, field_resolve_step)
143
+ end
144
+ end
145
+ end
146
+ arg_value = treat_as_type.new(nil, ruby_kwargs: new_arg_value, context: @query.context, defaults_used: nil)
147
+ end
148
+
149
+ if override_type.nil? # only on root arguments, not list elements
150
+ arg_value = begin
151
+ argument_definition.prepare_value(nil, arg_value, context: @query.context)
152
+ rescue StandardError => err
153
+ @runner.schema.handle_or_reraise(@query.context, err)
154
+ end
155
+ end
156
+
157
+ if field_resolve_step && arg_value && override_type.nil? && argument_definition.loads
158
+ field_defn = field_resolve_step.field_definition
159
+ load_receiver = if (r = field_defn.resolver)
160
+ r.new(field: field_defn, context: @query.context, object: nil)
161
+ else
162
+ field_defn
163
+ end
164
+ ps = field_resolve_step.pending_steps ||= []
165
+
166
+ if argument_definition.type.list?
167
+ results = Array.new(arg_value.size, nil)
168
+ argument_values[argument_key] = results
169
+ arg_value.each_with_index do |inner_v, idx|
170
+ loads_step = LoadArgumentStep.new(
171
+ field_resolve_step: field_resolve_step,
172
+ load_receiver: load_receiver,
173
+ argument_value: inner_v,
174
+ argument_definition: argument_definition,
175
+ arguments: results,
176
+ argument_key: idx,
177
+ )
178
+ ps.push(loads_step)
179
+ @runner.add_step(loads_step)
180
+ end
181
+ else
182
+ loads_step = LoadArgumentStep.new(
183
+ field_resolve_step: field_resolve_step,
184
+ load_receiver: load_receiver,
185
+ argument_value: arg_value,
186
+ argument_definition: argument_definition,
187
+ arguments: argument_values,
188
+ argument_key: argument_key,
189
+ )
190
+ ps.push(loads_step)
191
+ @runner.add_step(loads_step)
192
+ end
193
+ else
194
+ argument_values[argument_key] = arg_value
195
+ end
196
+ nil
197
+ end
198
+
199
+ def value_from_ast(value_node, type)
200
+ if type.non_null?
201
+ type = type.of_type
202
+ end
203
+
204
+ if value_node.nil?
205
+ nil
206
+ elsif value_node.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
207
+ variable_values[value_node.name]
208
+ elsif value_node.is_a?(GraphQL::Language::Nodes::NullValue)
209
+ nil
210
+ elsif type.list?
211
+ inner_type = type.of_type
212
+ if value_node.is_a?(Array)
213
+ coerced_items = value_node.map do |inner_value_node|
214
+ value_from_ast(inner_value_node, inner_type)
215
+ end
216
+ coerced_items.freeze
217
+ else
218
+ item_value = value_from_ast(value_node, inner_type)
219
+ [item_value].freeze
220
+ end
221
+
222
+ elsif type.kind.input_object?
223
+ coerced_obj = {}
224
+ arg_nodes_by_name = value_node.arguments.each_with_object({}) do |arg_node, acc| # rubocop:disable Development/ContextIsPassedCop
225
+ acc[arg_node.name] = arg_node
226
+ end
227
+
228
+ @query.types.arguments(type).each do |arg|
229
+ arg_node = arg_nodes_by_name[arg.graphql_name]
230
+ arg_key = arg.keyword
231
+ if arg_node.nil? || (arg_node.value.is_a?(Language::Nodes::VariableIdentifier) && !variable_values.key?(arg_node.value.name))
232
+ if arg.default_value?
233
+ coerced_obj[arg_key] = arg.default_value
234
+ end
235
+ next
236
+ end
237
+
238
+ arg_value = value_from_ast(arg_node.value, arg.type)
239
+ coerced_obj[arg_key] = arg_value
240
+ end
241
+
242
+ coerced_obj
243
+ elsif type.kind.leaf?
244
+ if type.kind.enum?
245
+ if value_node.is_a?(GraphQL::Language::Nodes::Enum)
246
+ value_node = value_node.name
247
+ end
248
+ end
249
+
250
+ begin
251
+ type.coerce_input(value_node, @query.context)
252
+ rescue GraphQL::UnauthorizedEnumValueError => enum_err
253
+ @runner.schema.unauthorized_object(enum_err)
254
+ end
255
+ else
256
+ raise "Unexpected input type: #{type.to_type_signature}."
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
@@ -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
@@ -23,9 +28,9 @@ module GraphQL
23
28
  if smallest_depth
24
29
  lazies = lazies_at_depth.delete(smallest_depth)
25
30
  if !lazies.empty?
26
- dataloader.append_job {
27
- lazies.each(&:value) # resolve these Lazy instances
28
- }
31
+ lazies.each do |l|
32
+ dataloader.append_job { l.value }
33
+ end
29
34
  # Run lazies _and_ dataloader, see if more are enqueued
30
35
  dataloader.run
31
36
  resolve_each_depth(lazies_at_depth, dataloader)
@@ -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