graphql 2.5.23 → 2.6.3

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/query_complexity.rb +29 -13
  3. data/lib/graphql/analysis.rb +20 -13
  4. data/lib/graphql/backtrace/table.rb +10 -1
  5. data/lib/graphql/current.rb +7 -1
  6. data/lib/graphql/dataloader.rb +1 -1
  7. data/lib/graphql/execution/directive_checks.rb +2 -0
  8. data/lib/graphql/execution/field_resolve_step.rb +744 -0
  9. data/lib/graphql/execution/finalize.rb +230 -0
  10. data/lib/graphql/execution/input_values.rb +333 -0
  11. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -0
  12. data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
  13. data/lib/graphql/execution/interpreter/runtime.rb +36 -15
  14. data/lib/graphql/execution/load_argument_step.rb +102 -0
  15. data/lib/graphql/execution/next.rb +42 -16
  16. data/lib/graphql/execution/prepare_object_step.rb +147 -0
  17. data/lib/graphql/execution/resolve_type_step.rb +27 -0
  18. data/lib/graphql/execution/runner.rb +445 -0
  19. data/lib/graphql/execution/selections_step.rb +91 -0
  20. data/lib/graphql/execution.rb +10 -3
  21. data/lib/graphql/execution_error.rb +7 -13
  22. data/lib/graphql/introspection/entry_points.rb +2 -2
  23. data/lib/graphql/introspection/schema_type.rb +6 -2
  24. data/lib/graphql/language/lexer.rb +12 -8
  25. data/lib/graphql/language/parser.rb +1 -1
  26. data/lib/graphql/language.rb +8 -2
  27. data/lib/graphql/pagination/connections.rb +1 -3
  28. data/lib/graphql/query/context.rb +6 -0
  29. data/lib/graphql/query/partial.rb +18 -3
  30. data/lib/graphql/query.rb +12 -3
  31. data/lib/graphql/runtime_error.rb +6 -0
  32. data/lib/graphql/schema/argument.rb +3 -3
  33. data/lib/graphql/schema/build_from_definition.rb +10 -0
  34. data/lib/graphql/schema/directive/feature.rb +4 -0
  35. data/lib/graphql/schema/directive/transform.rb +20 -0
  36. data/lib/graphql/schema/directive.rb +23 -9
  37. data/lib/graphql/schema/field/connection_extension.rb +2 -15
  38. data/lib/graphql/schema/field/scope_extension.rb +0 -4
  39. data/lib/graphql/schema/field.rb +20 -20
  40. data/lib/graphql/schema/field_extension.rb +11 -41
  41. data/lib/graphql/schema/has_single_input_argument.rb +24 -13
  42. data/lib/graphql/schema/input_object.rb +4 -0
  43. data/lib/graphql/schema/interface.rb +26 -0
  44. data/lib/graphql/schema/introspection_system.rb +6 -21
  45. data/lib/graphql/schema/list.rb +4 -0
  46. data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
  47. data/lib/graphql/schema/printer.rb +1 -1
  48. data/lib/graphql/schema/ractor_shareable.rb +1 -0
  49. data/lib/graphql/schema/relay_classic_mutation.rb +16 -2
  50. data/lib/graphql/schema/resolver.rb +30 -14
  51. data/lib/graphql/schema/subscription.rb +53 -8
  52. data/lib/graphql/schema/timeout.rb +2 -2
  53. data/lib/graphql/schema/validator/allow_blank_validator.rb +3 -3
  54. data/lib/graphql/schema/validator/allow_null_validator.rb +3 -3
  55. data/lib/graphql/schema/validator/exclusion_validator.rb +2 -2
  56. data/lib/graphql/schema/validator/format_validator.rb +3 -3
  57. data/lib/graphql/schema/validator/inclusion_validator.rb +2 -2
  58. data/lib/graphql/schema/validator/length_validator.rb +6 -6
  59. data/lib/graphql/schema/validator/numericality_validator.rb +19 -19
  60. data/lib/graphql/schema/validator/required_validator.rb +6 -4
  61. data/lib/graphql/schema/validator.rb +9 -0
  62. data/lib/graphql/schema/visibility/profile.rb +6 -4
  63. data/lib/graphql/schema/visibility/visit.rb +1 -1
  64. data/lib/graphql/schema/visibility.rb +30 -22
  65. data/lib/graphql/schema.rb +43 -20
  66. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +31 -25
  67. data/lib/graphql/subscriptions/event.rb +0 -1
  68. data/lib/graphql/subscriptions.rb +15 -0
  69. data/lib/graphql/tracing/perfetto_trace.rb +5 -3
  70. data/lib/graphql/tracing/trace.rb +6 -0
  71. data/lib/graphql/unauthorized_error.rb +1 -1
  72. data/lib/graphql/version.rb +1 -1
  73. data/lib/graphql.rb +1 -3
  74. metadata +11 -7
  75. data/lib/graphql/execution/next/field_resolve_step.rb +0 -743
  76. data/lib/graphql/execution/next/load_argument_step.rb +0 -64
  77. data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
  78. data/lib/graphql/execution/next/runner.rb +0 -411
  79. data/lib/graphql/execution/next/selections_step.rb +0 -37
@@ -757,6 +757,7 @@ module GraphQL
757
757
  # reset this cached value:
758
758
  @introspection_system = nil
759
759
  introspection_system
760
+ self.visibility&.introspection_system_configured(introspection_system)
760
761
  @introspection
761
762
  else
762
763
  @introspection || find_inherited_value(:introspection)
@@ -768,7 +769,6 @@ module GraphQL
768
769
  if !@introspection_system
769
770
  @introspection_system = Schema::IntrospectionSystem.new(self)
770
771
  @introspection_system.resolve_late_bindings
771
- self.visibility&.introspection_system_configured(@introspection_system)
772
772
  end
773
773
  @introspection_system
774
774
  end
@@ -1150,17 +1150,14 @@ module GraphQL
1150
1150
  attr_accessor :using_backtrace
1151
1151
 
1152
1152
  # @api private
1153
- def handle_or_reraise(context, err)
1153
+ def handle_or_reraise(context, err, object: context[:current_object], arguments: context[:current_arguments], field: context[:current_field])
1154
1154
  handler = Execution::Errors.find_handler_for(self, err.class)
1155
1155
  if handler
1156
- obj = context[:current_object]
1157
- args = context[:current_arguments]
1158
- args = args && args.respond_to?(:keyword_arguments) ? args.keyword_arguments : nil
1159
- field = context[:current_field]
1160
- if obj.is_a?(GraphQL::Schema::Object)
1161
- obj = obj.object
1156
+ arguments = arguments.respond_to?(:keyword_arguments) ? arguments.keyword_arguments : arguments
1157
+ if object.is_a?(GraphQL::Schema::Object)
1158
+ object = object.object
1162
1159
  end
1163
- handler[:handler].call(err, obj, args, context, field)
1160
+ handler[:handler].call(err, object, arguments, context, field)
1164
1161
  else
1165
1162
  if (context[:backtrace] || using_backtrace) && !err.is_a?(GraphQL::ExecutionError)
1166
1163
  err = GraphQL::Backtrace::TracedError.new(err, context)
@@ -1362,14 +1359,6 @@ module GraphQL
1362
1359
  lazy_methods.set(lazy_class, value_method)
1363
1360
  end
1364
1361
 
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
1362
  def resolves_lazies?
1374
1363
  lazy_method_count = 0
1375
1364
  lazy_methods.each do |k, v|
@@ -1450,7 +1439,16 @@ module GraphQL
1450
1439
  end
1451
1440
 
1452
1441
  def tracers
1453
- find_inherited_value(:tracers, EMPTY_ARRAY) + own_tracers
1442
+ inherited = find_inherited_value(:tracers, EMPTY_ARRAY)
1443
+ if inherited.length > 0
1444
+ if own_tracers.length > 0
1445
+ inherited + own_tracers
1446
+ else
1447
+ inherited
1448
+ end
1449
+ else
1450
+ own_tracers
1451
+ end
1454
1452
  end
1455
1453
 
1456
1454
  # Mix `trace_mod` into this schema's `Trace` class so that its methods will be called at runtime.
@@ -1560,7 +1558,8 @@ module GraphQL
1560
1558
  end
1561
1559
 
1562
1560
  def query_analyzers
1563
- find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1561
+ inherited_qa = find_inherited_value(:query_analyzers, EMPTY_ARRAY)
1562
+ inherited_qa.empty? ? own_query_analyzers : (inherited_qa + own_query_analyzers)
1564
1563
  end
1565
1564
 
1566
1565
  # @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on multiplexes to this schema
@@ -1585,6 +1584,14 @@ module GraphQL
1585
1584
  # @see {Query#initialize} for arguments.
1586
1585
  # @return [GraphQL::Query::Result] query result, ready to be serialized as JSON
1587
1586
  def execute(query_str = nil, **kwargs)
1587
+ if default_execution_next
1588
+ execute_next(query_str, **kwargs)
1589
+ else
1590
+ execute_legacy(query_str, **kwargs)
1591
+ end
1592
+ end
1593
+
1594
+ def execute_legacy(query_str = nil, **kwargs)
1588
1595
  if query_str
1589
1596
  kwargs[:query] = query_str
1590
1597
  end
@@ -1626,7 +1633,23 @@ module GraphQL
1626
1633
  # @option kwargs [nil, Integer] :max_complexity (nil)
1627
1634
  # @return [Array<GraphQL::Query::Result>] One result for each query in the input
1628
1635
  def multiplex(queries, **kwargs)
1629
- GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1636
+ if @default_execution_next
1637
+ multiplex_next(queries, **kwargs)
1638
+ else
1639
+ GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1640
+ end
1641
+ end
1642
+
1643
+ def default_execution_next(new_value = NOT_CONFIGURED)
1644
+ if !NOT_CONFIGURED.equal?(new_value)
1645
+ @default_execution_next = new_value
1646
+ elsif instance_variable_defined?(:@default_execution_next)
1647
+ @default_execution_next
1648
+ elsif superclass.respond_to?(:default_execution_next)
1649
+ superclass.default_execution_next
1650
+ else
1651
+ false
1652
+ end
1630
1653
  end
1631
1654
 
1632
1655
  def instrumenters
@@ -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
@@ -54,6 +54,12 @@ module GraphQL
54
54
  events << subscription_instance.event
55
55
  end
56
56
  value
57
+ elsif (exec_next_update_event = context.namespace(:subscriptions)[:update_event])
58
+ if context.query.subscription_topic == exec_next_update_event.topic
59
+ value
60
+ else
61
+ context.skip
62
+ end
57
63
  elsif (events = context.namespace(:subscriptions)[:events])
58
64
  # This is the first execution, so gather an Event
59
65
  # for the backend to register:
@@ -104,7 +104,6 @@ module GraphQL
104
104
 
105
105
  def stringify_args(arg_owner, args, context)
106
106
  arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers
107
-
108
107
  case args
109
108
  when Hash
110
109
  next_args = {}
@@ -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`:
@@ -67,6 +67,8 @@ module GraphQL
67
67
  DA_FETCH_KEYS_IID => "fetch keys",
68
68
  }
69
69
 
70
+ ANON_CLASS_NAME = "(anonymous)"
71
+
70
72
  DEBUG_INSPECT_CATEGORY_IIDS = [15]
71
73
  DA_DEBUG_INSPECT_CLASS_IID = 16
72
74
  DEBUG_INSPECT_EVENT_NAME_IID = 17
@@ -118,7 +120,7 @@ module GraphQL
118
120
  }
119
121
 
120
122
  @source_name_iids = Hash.new do |h, source_class|
121
- h[source_class] = @interned_event_name_iids[source_class.name]
123
+ h[source_class] = @interned_event_name_iids[source_class.name || ANON_CLASS_NAME]
122
124
  end.compare_by_identity
123
125
 
124
126
  @auth_name_iids = Hash.new do |h, graphql_type|
@@ -144,7 +146,7 @@ module GraphQL
144
146
  end
145
147
 
146
148
  @class_name_iids = Hash.new do |h, k|
147
- h[k] = @interned_da_string_values[k.name]
149
+ h[k] = @interned_da_string_values[k.name || ANON_CLASS_NAME]
148
150
  end.compare_by_identity
149
151
 
150
152
  @starting_objects = GC.stat(:total_allocated_objects)
@@ -682,7 +684,7 @@ module GraphQL
682
684
  when GraphQL::Schema::InputObject
683
685
  payload_to_debug(k, v.to_h, iid: iid, intern_value: intern_value)
684
686
  else
685
- class_name_iid = @interned_da_string_values[(v.class.name || "(anonymous)")]
687
+ class_name_iid = @interned_da_string_values[(v.class.name || ANON_CLASS_NAME)]
686
688
  da = [
687
689
  debug_annotation(DA_DEBUG_INSPECT_CLASS_IID, :string_value_iid, class_name_iid),
688
690
  ]
@@ -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.6.3"
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"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.23
4
+ version: 2.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-03 00:00:00.000000000 Z
10
+ date: 2026-05-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64
@@ -493,6 +493,9 @@ files:
493
493
  - lib/graphql/execution.rb
494
494
  - lib/graphql/execution/directive_checks.rb
495
495
  - lib/graphql/execution/errors.rb
496
+ - lib/graphql/execution/field_resolve_step.rb
497
+ - lib/graphql/execution/finalize.rb
498
+ - lib/graphql/execution/input_values.rb
496
499
  - lib/graphql/execution/interpreter.rb
497
500
  - lib/graphql/execution/interpreter/argument_value.rb
498
501
  - lib/graphql/execution/interpreter/arguments.rb
@@ -504,14 +507,14 @@ files:
504
507
  - lib/graphql/execution/interpreter/runtime/graphql_result.rb
505
508
  - lib/graphql/execution/lazy.rb
506
509
  - lib/graphql/execution/lazy/lazy_method_map.rb
510
+ - lib/graphql/execution/load_argument_step.rb
507
511
  - lib/graphql/execution/lookahead.rb
508
512
  - lib/graphql/execution/multiplex.rb
509
513
  - lib/graphql/execution/next.rb
510
- - lib/graphql/execution/next/field_resolve_step.rb
511
- - lib/graphql/execution/next/load_argument_step.rb
512
- - lib/graphql/execution/next/prepare_object_step.rb
513
- - lib/graphql/execution/next/runner.rb
514
- - lib/graphql/execution/next/selections_step.rb
514
+ - lib/graphql/execution/prepare_object_step.rb
515
+ - lib/graphql/execution/resolve_type_step.rb
516
+ - lib/graphql/execution/runner.rb
517
+ - lib/graphql/execution/selections_step.rb
515
518
  - lib/graphql/execution_error.rb
516
519
  - lib/graphql/integer_decoding_error.rb
517
520
  - lib/graphql/integer_encoding_error.rb
@@ -577,6 +580,7 @@ files:
577
580
  - lib/graphql/rubocop/graphql/default_required_true.rb
578
581
  - lib/graphql/rubocop/graphql/field_type_in_block.rb
579
582
  - lib/graphql/rubocop/graphql/root_types_in_block.rb
583
+ - lib/graphql/runtime_error.rb
580
584
  - lib/graphql/runtime_type_error.rb
581
585
  - lib/graphql/schema.rb
582
586
  - lib/graphql/schema/addition.rb