graphql 2.5.23 → 2.5.25

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis.rb +20 -13
  3. data/lib/graphql/execution/field_resolve_step.rb +631 -0
  4. data/lib/graphql/execution/finalize.rb +217 -0
  5. data/lib/graphql/execution/input_values.rb +261 -0
  6. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  7. data/lib/graphql/execution/load_argument_step.rb +64 -0
  8. data/lib/graphql/execution/next.rb +23 -5
  9. data/lib/graphql/execution/prepare_object_step.rb +128 -0
  10. data/lib/graphql/execution/runner.rb +410 -0
  11. data/lib/graphql/execution/selections_step.rb +91 -0
  12. data/lib/graphql/execution.rb +2 -2
  13. data/lib/graphql/execution_error.rb +1 -1
  14. data/lib/graphql/query/context.rb +6 -0
  15. data/lib/graphql/query/partial.rb +18 -3
  16. data/lib/graphql/query.rb +10 -1
  17. data/lib/graphql/runtime_error.rb +6 -0
  18. data/lib/graphql/schema/directive.rb +23 -9
  19. data/lib/graphql/schema/field/connection_extension.rb +2 -15
  20. data/lib/graphql/schema/field/scope_extension.rb +0 -4
  21. data/lib/graphql/schema/field.rb +20 -20
  22. data/lib/graphql/schema/field_extension.rb +11 -41
  23. data/lib/graphql/schema/interface.rb +26 -0
  24. data/lib/graphql/schema/list.rb +4 -0
  25. data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
  26. data/lib/graphql/schema/resolver.rb +2 -2
  27. data/lib/graphql/schema.rb +12 -10
  28. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +25 -25
  29. data/lib/graphql/subscriptions.rb +15 -0
  30. data/lib/graphql/tracing/trace.rb +6 -0
  31. data/lib/graphql/unauthorized_error.rb +1 -1
  32. data/lib/graphql/version.rb +1 -1
  33. data/lib/graphql.rb +1 -3
  34. metadata +10 -7
  35. data/lib/graphql/execution/next/field_resolve_step.rb +0 -743
  36. data/lib/graphql/execution/next/load_argument_step.rb +0 -64
  37. data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
  38. data/lib/graphql/execution/next/runner.rb +0 -411
  39. data/lib/graphql/execution/next/selections_step.rb +0 -37
@@ -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
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Execution
4
+ class LoadArgumentStep
5
+ def initialize(field_resolve_step:, arguments:, load_receiver:, argument_value:, argument_definition:, argument_key:)
6
+ @field_resolve_step = field_resolve_step
7
+ @load_receiver = load_receiver
8
+ @arguments = arguments
9
+ @argument_value = argument_value
10
+ @argument_definition = argument_definition
11
+ @argument_key = argument_key
12
+ @loaded_value = nil
13
+ end
14
+
15
+ def value
16
+ @loaded_value = @field_resolve_step.sync(@loaded_value)
17
+ assign_value
18
+ end
19
+
20
+ def call
21
+ context = @field_resolve_step.selections_step.query.context
22
+ @loaded_value = begin
23
+ @load_receiver.load_and_authorize_application_object(@argument_definition, @argument_value, context)
24
+ rescue GraphQL::UnauthorizedError => auth_err
25
+ context.schema.unauthorized_object(auth_err)
26
+ end
27
+ if (runner = @field_resolve_step.runner).resolves_lazies && runner.lazy?(@loaded_value)
28
+ runner.dataloader.lazy_at_depth(@field_resolve_step.path.size, self)
29
+ else
30
+ assign_value
31
+ end
32
+ rescue GraphQL::RuntimeError => err
33
+ @loaded_value = err
34
+ assign_value
35
+ rescue StandardError => stderr
36
+ @loaded_value = begin
37
+ context.query.handle_or_reraise(stderr)
38
+ rescue GraphQL::ExecutionError => ex_err
39
+ ex_err
40
+ end
41
+ assign_value
42
+ end
43
+
44
+ private
45
+
46
+ def assign_value
47
+ if @loaded_value.is_a?(GraphQL::RuntimeError)
48
+ @loaded_value.path = @field_resolve_step.path
49
+ @field_resolve_step.arguments = @loaded_value
50
+ else
51
+ query = @field_resolve_step.selections_step.query
52
+ query.current_trace.object_loaded(@argument_definition, @loaded_value, query.context)
53
+ @arguments[@argument_key] = @loaded_value
54
+ end
55
+
56
+ field_pending_steps = @field_resolve_step.pending_steps
57
+ field_pending_steps.delete(self)
58
+ if @field_resolve_step.arguments && field_pending_steps.size == 0 # rubocop:disable Development/ContextIsPassedCop
59
+ @field_resolve_step.runner.add_step(@field_resolve_step)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,11 +1,29 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/execution/next/prepare_object_step"
3
- require "graphql/execution/next/field_resolve_step"
4
- require "graphql/execution/next/load_argument_step"
5
- require "graphql/execution/next/runner"
6
- require "graphql/execution/next/selections_step"
2
+ require "graphql/execution/prepare_object_step"
3
+ require "graphql/execution/input_values"
4
+ require "graphql/execution/field_resolve_step"
5
+ require "graphql/execution/finalize"
6
+ require "graphql/execution/load_argument_step"
7
+ require "graphql/execution/runner"
8
+ require "graphql/execution/selections_step"
7
9
  module GraphQL
8
10
  module Execution
11
+ module Finalizer
12
+ attr_accessor :path
13
+ def finalize_graphql_result(query, result_data, result_key)
14
+ raise RequiredImplementationMissingError
15
+ end
16
+ end
17
+
18
+ module HaltExecution
19
+ end
20
+
21
+ module PostProcessor
22
+ def after_resolve(field_results)
23
+ raise RequiredImplementationMissingError, "#{self.class}#after_resolve should handle `field_results` and return a new value to use"
24
+ end
25
+ end
26
+
9
27
  module Next
10
28
  module SchemaExtension
11
29
  def execute_next(query_str = nil, context: nil, document: nil, operation_name: nil, variables: nil, root_value: nil, validate: true, visibility_profile: nil)