graphql 2.5.23 → 2.5.24

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
@@ -32,6 +32,7 @@ module GraphQL
32
32
  @multiplex = nil
33
33
  @result_values = nil
34
34
  @result = nil
35
+ @finalizers = @top_level_finalizers = nil
35
36
 
36
37
  if fragment_node
37
38
  @ast_nodes = [fragment_node]
@@ -51,6 +52,10 @@ module GraphQL
51
52
  @leaf
52
53
  end
53
54
 
55
+ def root_value
56
+ object
57
+ end
58
+
54
59
  attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
55
60
 
56
61
  attr_accessor :multiplex, :result_values
@@ -90,10 +95,22 @@ module GraphQL
90
95
  @query.fragments
91
96
  end
92
97
 
98
+ def validate
99
+ @query.validate
100
+ end
101
+
93
102
  def valid?
94
103
  @query.valid?
95
104
  end
96
105
 
106
+ def query?
107
+ true
108
+ end
109
+
110
+ def run_partials(...)
111
+ @query.run_partials(...)
112
+ end
113
+
97
114
  def analyzers
98
115
  EmptyObjects::EMPTY_ARRAY
99
116
  end
@@ -107,7 +124,7 @@ module GraphQL
107
124
  end
108
125
 
109
126
  def selected_operation
110
- ast_nodes.first
127
+ Language::Nodes::OperationDefinition.new(selections: ast_nodes.flat_map(&:selections))
111
128
  end
112
129
 
113
130
  def static_errors
@@ -123,7 +140,6 @@ module GraphQL
123
140
  def set_type_info_from_path
124
141
  selections = [@query.selected_operation]
125
142
  type = @query.root_type
126
- parent_type = nil
127
143
  field_defn = nil
128
144
 
129
145
  @path.each do |name_in_doc|
@@ -162,7 +178,6 @@ module GraphQL
162
178
  end
163
179
  field_name = next_selections.first.name
164
180
  field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
165
- parent_type = type
166
181
  type = field_defn.type
167
182
  if type.non_null?
168
183
  type = type.of_type
data/lib/graphql/query.rb CHANGED
@@ -159,6 +159,7 @@ module GraphQL
159
159
  @root_value = root_value
160
160
  @fragments = nil
161
161
  @operations = nil
162
+ @finalizers = @top_level_finalizers = nil
162
163
  @validate = validate
163
164
  self.static_validator = static_validator if static_validator
164
165
  context_tracers = (context ? context.fetch(:tracers, []) : [])
@@ -262,6 +263,10 @@ module GraphQL
262
263
  with_prepared_ast { @operations }
263
264
  end
264
265
 
266
+ def path
267
+ EmptyObjects::EMPTY_ARRAY
268
+ end
269
+
265
270
  # Run subtree partials of this query and return their results.
266
271
  # Each partial is identified with a `path:` and `object:`
267
272
  # where the path references a field in the AST and the object will be treated
@@ -271,7 +276,11 @@ module GraphQL
271
276
  # @return [Array<GraphQL::Query::Result>]
272
277
  def run_partials(partials_hashes)
273
278
  partials = partials_hashes.map { |partial_options| Partial.new(query: self, **partial_options) }
274
- Execution::Interpreter.run_all(@schema, partials, context: @context)
279
+ if context[:__graphql_execute_next]
280
+ Execution::Next.run_all(@schema, partials, context: @context)
281
+ else
282
+ Execution::Interpreter.run_all(@schema, partials, context: @context)
283
+ end
275
284
  end
276
285
 
277
286
  # Get the result for this query, executing it once
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class RuntimeError < Error
4
+ include GraphQL::Execution::Finalizer
5
+ end
6
+ end
@@ -31,17 +31,25 @@ module GraphQL
31
31
 
32
32
  def locations(*new_locations)
33
33
  if !new_locations.empty?
34
+ is_runtime = false
34
35
  new_locations.each do |new_loc|
35
- if !LOCATIONS.include?(new_loc.to_sym)
36
+ loc_sym = new_loc.to_sym
37
+ if !LOCATIONS.include?(loc_sym)
36
38
  raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
37
39
  end
40
+ is_runtime ||= RUNTIME_LOCATIONS.include?(loc_sym)
38
41
  end
39
42
  @locations = new_locations
43
+ @is_runtime = is_runtime
40
44
  else
41
45
  @locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
42
46
  end
43
47
  end
44
48
 
49
+ def runtime?
50
+ @is_runtime
51
+ end
52
+
45
53
  def default_directive(new_default_directive = nil)
46
54
  if new_default_directive != nil
47
55
  @default_directive = new_default_directive
@@ -104,8 +112,12 @@ module GraphQL
104
112
 
105
113
  def inherited(subclass)
106
114
  super
115
+ parent_class = self
107
116
  subclass.class_exec do
108
117
  @default_graphql_name ||= nil
118
+ @locations = parent_class.locations
119
+ @is_runtime = parent_class.runtime?
120
+ @repeatable = false
109
121
  end
110
122
  end
111
123
  end
@@ -177,13 +189,16 @@ module GraphQL
177
189
  end
178
190
 
179
191
  LOCATIONS = [
180
- QUERY = :QUERY,
181
- MUTATION = :MUTATION,
182
- SUBSCRIPTION = :SUBSCRIPTION,
183
- FIELD = :FIELD,
184
- FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION,
185
- FRAGMENT_SPREAD = :FRAGMENT_SPREAD,
186
- INLINE_FRAGMENT = :INLINE_FRAGMENT,
192
+ *(RUNTIME_LOCATIONS = [
193
+ QUERY = :QUERY,
194
+ MUTATION = :MUTATION,
195
+ SUBSCRIPTION = :SUBSCRIPTION,
196
+ FIELD = :FIELD,
197
+ FRAGMENT_DEFINITION = :FRAGMENT_DEFINITION,
198
+ FRAGMENT_SPREAD = :FRAGMENT_SPREAD,
199
+ INLINE_FRAGMENT = :INLINE_FRAGMENT,
200
+ VARIABLE_DEFINITION = :VARIABLE_DEFINITION,
201
+ ]),
187
202
  SCHEMA = :SCHEMA,
188
203
  SCALAR = :SCALAR,
189
204
  OBJECT = :OBJECT,
@@ -195,7 +210,6 @@ module GraphQL
195
210
  ENUM_VALUE = :ENUM_VALUE,
196
211
  INPUT_OBJECT = :INPUT_OBJECT,
197
212
  INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
198
- VARIABLE_DEFINITION = :VARIABLE_DEFINITION,
199
213
  ]
200
214
 
201
215
  DEFAULT_DEPRECATION_REASON = 'No longer supported'
@@ -12,22 +12,13 @@ module GraphQL
12
12
  end
13
13
 
14
14
  # Remove pagination args before passing it to a user method
15
- def resolve(object:, arguments:, context:)
15
+ def resolve(object: nil, objects: nil, arguments:, context:)
16
16
  next_args = arguments.dup
17
17
  next_args.delete(:first)
18
18
  next_args.delete(:last)
19
19
  next_args.delete(:before)
20
20
  next_args.delete(:after)
21
- yield(object, next_args, arguments)
22
- end
23
-
24
- def resolve_next(objects:, arguments:, context:)
25
- next_args = arguments.dup
26
- next_args.delete(:first)
27
- next_args.delete(:last)
28
- next_args.delete(:before)
29
- next_args.delete(:after)
30
- yield(objects, next_args, arguments)
21
+ yield(object || objects, next_args, arguments)
31
22
  end
32
23
 
33
24
  def after_resolve(value:, object:, arguments:, context:, memo:)
@@ -36,10 +27,6 @@ module GraphQL
36
27
  context.schema.connections.populate_connection(field, object.object, resolved_value, original_arguments, context)
37
28
  end
38
29
  end
39
-
40
- def after_resolve_next(**kwargs)
41
- raise "This should never be called -- it's hardcoded in execution instead."
42
- end
43
30
  end
44
31
  end
45
32
  end
@@ -28,10 +28,6 @@ module GraphQL
28
28
  value
29
29
  end
30
30
  end
31
-
32
- def after_resolve_next(**kwargs)
33
- raise "This should never be called -- it's hardcoded in execution instead."
34
- end
35
31
  end
36
32
  end
37
33
  end
@@ -270,32 +270,32 @@ module GraphQL
270
270
  @resolver_method = (resolver_method || name_s).to_sym
271
271
 
272
272
  if resolve_static
273
- @execution_next_mode = :resolve_static
274
- @execution_next_mode_key = resolve_static == true ? @method_sym : resolve_static
273
+ @execution_mode = :resolve_static
274
+ @execution_mode_key = resolve_static == true ? @method_sym : resolve_static
275
275
  elsif resolve_batch
276
- @execution_next_mode = :resolve_batch
277
- @execution_next_mode_key = resolve_batch == true ? @method_sym : resolve_batch
276
+ @execution_mode = :resolve_batch
277
+ @execution_mode_key = resolve_batch == true ? @method_sym : resolve_batch
278
278
  elsif resolve_each
279
- @execution_next_mode = :resolve_each
280
- @execution_next_mode_key = resolve_each == true ? @method_sym : resolve_each
279
+ @execution_mode = :resolve_each
280
+ @execution_mode_key = resolve_each == true ? @method_sym : resolve_each
281
281
  elsif hash_key
282
- @execution_next_mode = :hash_key
283
- @execution_next_mode_key = hash_key
282
+ @execution_mode = :hash_key
283
+ @execution_mode_key = hash_key
284
284
  elsif dig
285
- @execution_next_mode = :dig
286
- @execution_next_mode_key = dig
285
+ @execution_mode = :dig
286
+ @execution_mode_key = dig
287
287
  elsif resolver_class
288
- @execution_next_mode = :resolver_class
289
- @execution_next_mode_key = resolver_class
288
+ @execution_mode = :resolver_class
289
+ @execution_mode_key = resolver_class
290
290
  elsif resolve_legacy_instance_method
291
- @execution_next_mode = :resolve_legacy_instance_method
292
- @execution_next_mode_key = resolve_legacy_instance_method == true ? @method_sym : resolve_legacy_instance_method
291
+ @execution_mode = :resolve_legacy_instance_method
292
+ @execution_mode_key = resolve_legacy_instance_method == true ? @method_sym : resolve_legacy_instance_method
293
293
  elsif dataload
294
- @execution_next_mode = :dataload
295
- @execution_next_mode_key = dataload
294
+ @execution_mode = :dataload
295
+ @execution_mode_key = dataload
296
296
  else
297
- @execution_next_mode = :direct_send
298
- @execution_next_mode_key = @method_sym
297
+ @execution_mode = :direct_send
298
+ @execution_mode_key = @method_sym
299
299
  end
300
300
 
301
301
  @complexity = complexity
@@ -369,7 +369,7 @@ module GraphQL
369
369
  end
370
370
 
371
371
  # @api private
372
- attr_reader :execution_next_mode_key, :execution_next_mode
372
+ attr_reader :execution_mode_key, :execution_mode
373
373
 
374
374
  # Calls the definition block, if one was given.
375
375
  # This is deferred so that references to the return type
@@ -929,7 +929,7 @@ ERR
929
929
  def run_next_extensions_before_resolve(objs, args, ctx, extended, idx: 0, &block)
930
930
  extension = @extensions[idx]
931
931
  if extension
932
- extension.resolve_next(objects: objs, arguments: args, context: ctx) do |extended_objs, extended_args, memo|
932
+ extension.resolve(objects: objs, arguments: args, context: ctx) do |extended_objs, extended_args, memo|
933
933
  if memo
934
934
  memos = extended.memos ||= {}
935
935
  memos[idx] = memo
@@ -123,33 +123,16 @@ module GraphQL
123
123
  #
124
124
  # Whatever this method returns will be used for execution.
125
125
  #
126
- # @param object [Object] The object the field is being resolved on
126
+ # @param object [Object] The object the field is being resolved on (not passed by new execution)
127
+ # @param objects [Array<Object>] The objects the field is being resolved on (passed by new execution)
127
128
  # @param arguments [Hash] Ruby keyword arguments for resolving this field
128
129
  # @param context [Query::Context] the context for this query
129
- # @yieldparam object [Object] The object to continue resolving the field on
130
+ # @yieldparam object_or_objects [Object, Array<Object>] The object or objects (new execution) to continue resolving the field on
130
131
  # @yieldparam arguments [Hash] The keyword arguments to continue resolving with
131
132
  # @yieldparam memo [Object] Any extension-specific value which will be passed to {#after_resolve} later
132
133
  # @return [Object] The return value for this field.
133
- def resolve(object:, arguments:, context:)
134
- yield(object, arguments, nil)
135
- end
136
-
137
- # Called before batch-resolving {#field}. It should either:
138
- #
139
- # - `yield` values to continue execution; OR
140
- # - return something else to shortcut field execution.
141
- #
142
- # Whatever this method returns will be used for execution.
143
- #
144
- # @param objects [Array<Object>] The objects the field is being resolved on
145
- # @param arguments [Hash] Ruby keyword arguments for resolving this field
146
- # @param context [Query::Context] the context for this query
147
- # @yieldparam objects [Array<Object>] The objects to continue resolving the field on. Length must be the same as passed-in `objects:`
148
- # @yieldparam arguments [Hash] The keyword arguments to continue resolving with
149
- # @yieldparam memo [Object] Any extension-specific value which will be passed to {#after_resolve} later
150
- # @return [Array<Object>] The return value for this field, length matching passed-in `objects:`.
151
- def resolve_next(objects:, arguments:, context:)
152
- yield(objects, arguments, nil)
134
+ def resolve(object: nil, objects: nil, arguments:, context:)
135
+ yield(object || objects, arguments, nil)
153
136
  end
154
137
 
155
138
  # Called after {#field} was resolved, and after any lazy values (like `Promise`s) were synced,
@@ -157,29 +140,16 @@ module GraphQL
157
140
  #
158
141
  # Whatever this hook returns will be used as the return value.
159
142
  #
160
- # @param object [Object] The object the field is being resolved on
143
+ # @param object [Object] The object the field is being resolved on (not passed by new execution)
144
+ # @param objects [Array<Object>] The object the field is being resolved on (passed by new execution)
161
145
  # @param arguments [Hash] Ruby keyword arguments for resolving this field
162
146
  # @param context [Query::Context] the context for this query
163
- # @param value [Object] Whatever the field previously returned
147
+ # @param value [Object] Whatever the field previously returned (not passed by new execution)
148
+ # @param values [Array<Object>] Whatever the field previously returned (passed by new execution)
164
149
  # @param memo [Object] The third value yielded by {#resolve}, or `nil` if there wasn't one
165
150
  # @return [Object] The return value for this field.
166
- def after_resolve(object:, arguments:, context:, value:, memo:)
167
- value
168
- end
169
-
170
- # Called after {#field} was batch-resolved, and after any lazy values (like `Promise`s) were synced,
171
- # but before the value was added to the GraphQL response.
172
- #
173
- # Whatever this hook returns will be used as the return value.
174
- #
175
- # @param objects [Array<Object>] The objects the field is being resolved on
176
- # @param arguments [Hash] Ruby keyword arguments for resolving this field
177
- # @param context [Query::Context] the context for this query
178
- # @param values [Array<Object>] Whatever the field returned, one for each of `objects`
179
- # @param memo [Object] The third value yielded by {#resolve}, or `nil` if there wasn't one
180
- # @return [Array<Object>] The return values for this field, length matching `objects:`.
181
- def after_resolve_next(objects:, arguments:, context:, values:, memo:)
182
- values
151
+ def after_resolve(object: nil, objects: nil, arguments:, context:, values: nil, value: nil, memo:)
152
+ value || values
183
153
  end
184
154
  end
185
155
  end
@@ -33,6 +33,26 @@ module GraphQL
33
33
  self::DefinitionMethods.module_exec(&block)
34
34
  end
35
35
 
36
+ # Instance methods defined in this block will become class methods on objects that implement this interface.
37
+ # Use it to implement `resolve_each:`, `resolve_batch:`, and `resolve_static:` fields.
38
+ # @example
39
+ # field :thing, String, resolve_static: true
40
+ #
41
+ # resolver_methods do
42
+ # def thing
43
+ # Somehow.get.thing
44
+ # end
45
+ # end
46
+ def resolver_methods(&block)
47
+ if !defined?(@_resolver_methods)
48
+ resolver_methods_module = Module.new
49
+ @_resolver_methods = resolver_methods_module
50
+ const_set(:ResolverMethods, resolver_methods_module)
51
+ extend(self::ResolverMethods)
52
+ end
53
+ self::ResolverMethods.module_exec(&block)
54
+ end
55
+
36
56
  # @see {Schema::Warden} hides interfaces without visible implementations
37
57
  def visible?(context)
38
58
  true
@@ -79,6 +99,12 @@ module GraphQL
79
99
  if !backtrace_line
80
100
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
81
101
  end
102
+
103
+ child_class.ancestors.reverse_each do |ancestor|
104
+ if ancestor.const_defined?(:ResolverMethods)
105
+ child_class.extend(ancestor::ResolverMethods)
106
+ end
107
+ end
82
108
  end
83
109
 
84
110
  super
@@ -22,6 +22,10 @@ module GraphQL
22
22
  @type_signature ||= -"[#{@of_type.to_type_signature}]"
23
23
  end
24
24
 
25
+ def authorizes?(ctx)
26
+ of_type.authorizes?(ctx)
27
+ end
28
+
25
29
  # This is for introspection, where it's expected the name will be `null`
26
30
  def graphql_name
27
31
  nil
@@ -26,16 +26,6 @@ module GraphQL
26
26
  end
27
27
  end
28
28
 
29
- # Just a convenience method to point out that people should use graphql_name instead
30
- def name(new_name = nil)
31
- return super() if new_name.nil?
32
-
33
- fail(
34
- "The new name override method is `graphql_name`, not `name`. Usage: "\
35
- "graphql_name \"#{new_name}\""
36
- )
37
- end
38
-
39
29
  # Call this method to provide a new description; OR
40
30
  # call it without an argument to get the description
41
31
  # @param new_description [String]
@@ -80,8 +80,8 @@ module GraphQL
80
80
  result = if is_authed
81
81
  Schema::Validator.validate!(self.class.validators, object, context, @prepared_arguments, as: @field)
82
82
  if q.subscription? && @field.owner == context.schema.subscription
83
- # This needs to use arguments without `loads:`
84
- @original_arguments = @field_resolve_step.coerce_arguments(@field, @field_resolve_step.ast_node.arguments, false)
83
+ # This needs to use arguments without `loads:`. TODO extract this into subscription-related code somehow?
84
+ @original_arguments = @field_resolve_step.runner.input_values[q].argument_values(@field, @field_resolve_step.ast_node.arguments, nil)
85
85
  end
86
86
  call_resolve(@prepared_arguments)
87
87
  elsif new_return_value.nil?
@@ -1362,14 +1362,6 @@ module GraphQL
1362
1362
  lazy_methods.set(lazy_class, value_method)
1363
1363
  end
1364
1364
 
1365
- def uses_raw_value?
1366
- !!@uses_raw_value
1367
- end
1368
-
1369
- def uses_raw_value(new_val)
1370
- @uses_raw_value = new_val
1371
- end
1372
-
1373
1365
  def resolves_lazies?
1374
1366
  lazy_method_count = 0
1375
1367
  lazy_methods.each do |k, v|
@@ -1450,7 +1442,16 @@ module GraphQL
1450
1442
  end
1451
1443
 
1452
1444
  def tracers
1453
- find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1445
+ inherited = find_inherited_value(:tracers, EMPTY_ARRAY)
1446
+ if inherited.length > 0
1447
+ if own_tracers.length > 0
1448
+ inherited + own_tracers
1449
+ else
1450
+ inherited
1451
+ end
1452
+ else
1453
+ own_tracers
1454
+ end
1454
1455
  end
1455
1456
 
1456
1457
  # Mix `trace_mod` into this schema's `Trace` class so that its methods will be called at runtime.
@@ -1560,7 +1561,8 @@ module GraphQL
1560
1561
  end
1561
1562
 
1562
1563
  def query_analyzers
1563
- find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1564
+ inherited_qa = find_inherited_value(:query_analyzers, EMPTY_ARRAY)
1565
+ inherited_qa.empty? ? own_query_analyzers : (inherited_qa + own_query_analyzers)
1564
1566
  end
1565
1567
 
1566
1568
  # @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on multiplexes to this schema
@@ -2,41 +2,41 @@
2
2
  module GraphQL
3
3
  class Subscriptions
4
4
  class DefaultSubscriptionResolveExtension < GraphQL::Schema::FieldExtension
5
- def resolve(context:, object:, arguments:)
6
- has_override_implementation = @field.resolver ||
7
- object.respond_to?(@field.resolver_method)
5
+ def resolve(context:, object: nil, objects: nil, arguments:)
6
+ if objects
7
+ has_override_implementation = @field.execution_mode != :direct_send
8
8
 
9
- if !has_override_implementation
10
- if context.query.subscription_update?
11
- object.object
9
+ if !has_override_implementation
10
+ if context.query.subscription_update?
11
+ objects
12
+ else
13
+ objects.map { |o| context.skip }
14
+ end
12
15
  else
13
- context.skip
16
+ yield(objects, arguments)
14
17
  end
15
18
  else
16
- yield(object, arguments)
17
- end
18
- end
19
+ has_override_implementation = @field.resolver ||
20
+ object.respond_to?(@field.resolver_method)
19
21
 
20
- def resolve_next(context:, objects:, arguments:)
21
- has_override_implementation = @field.execution_next_mode != :direct_send
22
-
23
- if !has_override_implementation
24
- if context.query.subscription_update?
25
- objects
22
+ if !has_override_implementation
23
+ if context.query.subscription_update?
24
+ object.object
25
+ else
26
+ context.skip
27
+ end
26
28
  else
27
- objects.map { |o| context.skip }
29
+ yield(object, arguments)
28
30
  end
29
- else
30
- yield(objects, arguments)
31
31
  end
32
32
  end
33
33
 
34
- def after_resolve(value:, context:, object:, arguments:, **rest)
35
- self.class.write_subscription(@field, value, arguments, context)
36
- end
37
-
38
- def after_resolve_next(values:, context:, objects:, arguments:, **rest)
39
- values.map do |value|
34
+ def after_resolve(values: nil, value: nil, context:, objects: nil, object: nil, arguments:, **rest)
35
+ if values
36
+ values.map do |value|
37
+ self.class.write_subscription(@field, value, arguments, context)
38
+ end
39
+ else
40
40
  self.class.write_subscription(@field, value, arguments, context)
41
41
  end
42
42
  end
@@ -259,6 +259,21 @@ module GraphQL
259
259
  nil
260
260
  end
261
261
 
262
+ def finalizer
263
+ Finalizer.new(self)
264
+ end
265
+
266
+ class Finalizer
267
+ include Execution::Finalizer
268
+ def initialize(subscriptions)
269
+ @subscriptions = subscriptions
270
+ end
271
+
272
+ def finalize_graphql_result(query, result_data, result_key)
273
+ @subscriptions.finish_subscriptions(query)
274
+ end
275
+ end
276
+
262
277
  private
263
278
 
264
279
  # Recursively normalize `args` as belonging to `arg_owner`:
@@ -98,6 +98,12 @@ module GraphQL
98
98
  yield
99
99
  end
100
100
 
101
+ def objects(type, object, context)
102
+ end
103
+
104
+ def object_loaded(argument_definition, object, context)
105
+ end
106
+
101
107
  # A call to `.authorized?` is starting
102
108
  # @param type [Class<GraphQL::Schema::Object>]
103
109
  # @param object [Object]
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  attr_accessor :path, :ast_nodes
32
32
 
33
- def assign_graphql_result(query, result_data, key)
33
+ def finalize_graphql_result(query, result_data, key)
34
34
  result_data[key] = nil
35
35
  end
36
36
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.5.23"
3
+ VERSION = "2.5.24"
4
4
  end
data/lib/graphql.rb CHANGED
@@ -21,9 +21,6 @@ module GraphQL
21
21
  class Error < StandardError
22
22
  end
23
23
 
24
- class RuntimeError < Error
25
- end
26
-
27
24
  # This error is raised when GraphQL-Ruby encounters a situation
28
25
  # that it *thought* would never happen. Please report this bug!
29
26
  class InvariantError < Error
@@ -122,6 +119,7 @@ This is probably a bug in GraphQL-Ruby, please report this error on GitHub: http
122
119
  autoload :ParseError, "graphql/parse_error"
123
120
  autoload :Backtrace, "graphql/backtrace"
124
121
 
122
+ autoload :RuntimeError, "graphql/runtime_error"
125
123
  autoload :UnauthorizedError, "graphql/unauthorized_error"
126
124
  autoload :UnauthorizedEnumValueError, "graphql/unauthorized_enum_value_error"
127
125
  autoload :UnauthorizedFieldError, "graphql/unauthorized_field_error"