graphql 2.3.19 → 2.3.21

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +2 -1
  3. data/lib/graphql/analysis/visitor.rb +2 -0
  4. data/lib/graphql/language/nodes.rb +3 -0
  5. data/lib/graphql/language/static_visitor.rb +37 -33
  6. data/lib/graphql/language/visitor.rb +59 -55
  7. data/lib/graphql/schema/argument.rb +3 -5
  8. data/lib/graphql/schema/build_from_definition.rb +8 -7
  9. data/lib/graphql/schema/directive.rb +1 -1
  10. data/lib/graphql/schema/enum.rb +2 -0
  11. data/lib/graphql/schema/enum_value.rb +1 -1
  12. data/lib/graphql/schema/field.rb +2 -2
  13. data/lib/graphql/schema/input_object.rb +20 -8
  14. data/lib/graphql/schema/interface.rb +1 -1
  15. data/lib/graphql/schema/member/has_directives.rb +1 -1
  16. data/lib/graphql/schema/member/has_fields.rb +1 -1
  17. data/lib/graphql/schema/member/has_interfaces.rb +1 -1
  18. data/lib/graphql/schema/member/scoped.rb +1 -1
  19. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  20. data/lib/graphql/schema.rb +115 -10
  21. data/lib/graphql/tracing/appoptics_trace.rb +4 -0
  22. data/lib/graphql/tracing/appsignal_trace.rb +4 -0
  23. data/lib/graphql/tracing/data_dog_trace.rb +4 -0
  24. data/lib/graphql/tracing/notifications_trace.rb +4 -0
  25. data/lib/graphql/tracing/platform_trace.rb +5 -0
  26. data/lib/graphql/tracing/prometheus_trace.rb +4 -0
  27. data/lib/graphql/tracing/scout_trace.rb +3 -0
  28. data/lib/graphql/tracing/sentry_trace.rb +4 -0
  29. data/lib/graphql/tracing/statsd_trace.rb +4 -0
  30. data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
  31. data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
  32. data/lib/graphql/version.rb +1 -1
  33. metadata +3 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10c07ea3257376b80dc347e8735c085cb1708ab2e10bef481030a9cafb395617
4
- data.tar.gz: fa2c5a429ec7f5fcef99dad3784b118b4c59144d851fa8158a5c25fc52846404
3
+ metadata.gz: adab188bde82d618e8c5f71b5318f32787926b4c9df8c68f20a0f747c0c5d870
4
+ data.tar.gz: a03d9f8784d47b3374d5651b8ae127019009ae98ee1abb248138532e7db9d1ed
5
5
  SHA512:
6
- metadata.gz: 9fe9de7dafd4e61471821f13dd39300d70e69d8e64a264bb22e39482ea9d2eedea81470ee9bcb8d59cf2ba840ac8173547b9ce1bf01c45cc57446f92921c22de
7
- data.tar.gz: 5a4343fb066b3b56129c18f9da25575db4d8eb58b569185a218bcfb069b20ecd51711988823fb25210b5239d0cb1dc03e0dc7c507ae90d6bd00301679d873f17
6
+ metadata.gz: 8ab82a64152e6abb6950591ec691be8212af5ecb2f9abf9672152f5c0d49591301774f83362a1b1646268eb821e86a0cd65bf6fb8c3203ada84d190173b31a11
7
+ data.tar.gz: 6985b7afa97388783788c3396f3a02c23f7d46e0c7f4a1c045c6c446161b7e2091238813181c22cfeaa33abe971b5f8f830c34607217f13f4c90e996f21725d8
@@ -42,6 +42,7 @@ module GraphQL
42
42
  raise GraphQL::RequiredImplementationMissingError
43
43
  end
44
44
 
45
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
45
46
  class << self
46
47
  private
47
48
 
@@ -72,7 +73,7 @@ module GraphQL
72
73
  build_visitor_hooks :variable_definition
73
74
  build_visitor_hooks :variable_identifier
74
75
  build_visitor_hooks :abstract_node
75
-
76
+ # rubocop:enable Development/NoEvalCop
76
77
  protected
77
78
 
78
79
  # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
@@ -64,6 +64,7 @@ module GraphQL
64
64
  @response_path.dup
65
65
  end
66
66
 
67
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
67
68
  # Visitor Hooks
68
69
  [
69
70
  :operation_definition, :fragment_definition,
@@ -92,6 +93,7 @@ module GraphQL
92
93
 
93
94
  RUBY
94
95
  end
96
+ # rubocop:enable Development/NoEvalCop
95
97
 
96
98
  def on_operation_definition(node, parent)
97
99
  object_type = @schema.root_type_for_operation(node.operation_type)
@@ -141,6 +141,8 @@ module GraphQL
141
141
  end
142
142
 
143
143
  class << self
144
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
145
+
144
146
  # Add a default `#visit_method` and `#children_method_name` using the class name
145
147
  def inherited(child_class)
146
148
  super
@@ -343,6 +345,7 @@ module GraphQL
343
345
  RUBY
344
346
  end
345
347
  end
348
+ # rubocop:enable Development/NoEvalCop
346
349
  end
347
350
  end
348
351
 
@@ -22,39 +22,6 @@ module GraphQL
22
22
  end
23
23
  end
24
24
 
25
- # We don't use `alias` here because it breaks `super`
26
- def self.make_visit_methods(ast_node_class)
27
- node_method = ast_node_class.visit_method
28
- children_of_type = ast_node_class.children_of_type
29
- child_visit_method = :"#{node_method}_children"
30
-
31
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
32
- # The default implementation for visiting an AST node.
33
- # It doesn't _do_ anything, but it continues to visiting the node's children.
34
- # To customize this hook, override one of its make_visit_methods (or the base method?)
35
- # in your subclasses.
36
- #
37
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
38
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
39
- # @return [void]
40
- def #{node_method}(node, parent)
41
- #{
42
- if method_defined?(child_visit_method)
43
- "#{child_visit_method}(node)"
44
- elsif children_of_type
45
- children_of_type.map do |child_accessor, child_class|
46
- "node.#{child_accessor}.each do |child_node|
47
- #{child_class.visit_method}(child_node, node)
48
- end"
49
- end.join("\n")
50
- else
51
- ""
52
- end
53
- }
54
- end
55
- RUBY
56
- end
57
-
58
25
  def on_document_children(document_node)
59
26
  document_node.children.each do |child_node|
60
27
  visit_method = child_node.visit_method
@@ -123,6 +90,41 @@ module GraphQL
123
90
  end
124
91
  end
125
92
 
93
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
94
+
95
+ # We don't use `alias` here because it breaks `super`
96
+ def self.make_visit_methods(ast_node_class)
97
+ node_method = ast_node_class.visit_method
98
+ children_of_type = ast_node_class.children_of_type
99
+ child_visit_method = :"#{node_method}_children"
100
+
101
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
102
+ # The default implementation for visiting an AST node.
103
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
104
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
105
+ # in your subclasses.
106
+ #
107
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
108
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
109
+ # @return [void]
110
+ def #{node_method}(node, parent)
111
+ #{
112
+ if method_defined?(child_visit_method)
113
+ "#{child_visit_method}(node)"
114
+ elsif children_of_type
115
+ children_of_type.map do |child_accessor, child_class|
116
+ "node.#{child_accessor}.each do |child_node|
117
+ #{child_class.visit_method}(child_node, node)
118
+ end"
119
+ end.join("\n")
120
+ else
121
+ ""
122
+ end
123
+ }
124
+ end
125
+ RUBY
126
+ end
127
+
126
128
  [
127
129
  Language::Nodes::Argument,
128
130
  Language::Nodes::Directive,
@@ -162,6 +164,8 @@ module GraphQL
162
164
  ].each do |ast_node_class|
163
165
  make_visit_methods(ast_node_class)
164
166
  end
167
+
168
+ # rubocop:disable Development/NoEvalCop
165
169
  end
166
170
  end
167
171
  end
@@ -61,61 +61,6 @@ module GraphQL
61
61
  end
62
62
  end
63
63
 
64
- # We don't use `alias` here because it breaks `super`
65
- def self.make_visit_methods(ast_node_class)
66
- node_method = ast_node_class.visit_method
67
- children_of_type = ast_node_class.children_of_type
68
- child_visit_method = :"#{node_method}_children"
69
-
70
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
71
- # The default implementation for visiting an AST node.
72
- # It doesn't _do_ anything, but it continues to visiting the node's children.
73
- # To customize this hook, override one of its make_visit_methods (or the base method?)
74
- # in your subclasses.
75
- #
76
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
77
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
78
- # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
79
- def #{node_method}(node, parent)
80
- if node.equal?(DELETE_NODE)
81
- # This might be passed to `super(DELETE_NODE, ...)`
82
- # by a user hook, don't want to keep visiting in that case.
83
- [node, parent]
84
- else
85
- new_node = node
86
- #{
87
- if method_defined?(child_visit_method)
88
- "new_node = #{child_visit_method}(new_node)"
89
- elsif children_of_type
90
- children_of_type.map do |child_accessor, child_class|
91
- "node.#{child_accessor}.each do |child_node|
92
- new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
93
- # Reassign `node` in case the child hook makes a modification
94
- if new_child_and_node.is_a?(Array)
95
- new_node = new_child_and_node[1]
96
- end
97
- end"
98
- end.join("\n")
99
- else
100
- ""
101
- end
102
- }
103
-
104
- if new_node.equal?(node)
105
- [node, parent]
106
- else
107
- [new_node, parent]
108
- end
109
- end
110
- end
111
-
112
- def #{node_method}_with_modifications(node, parent)
113
- new_node_and_new_parent = #{node_method}(node, parent)
114
- apply_modifications(node, parent, new_node_and_new_parent)
115
- end
116
- RUBY
117
- end
118
-
119
64
  def on_document_children(document_node)
120
65
  new_node = document_node
121
66
  document_node.children.each do |child_node|
@@ -216,6 +161,63 @@ module GraphQL
216
161
  new_node
217
162
  end
218
163
 
164
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
165
+
166
+ # We don't use `alias` here because it breaks `super`
167
+ def self.make_visit_methods(ast_node_class)
168
+ node_method = ast_node_class.visit_method
169
+ children_of_type = ast_node_class.children_of_type
170
+ child_visit_method = :"#{node_method}_children"
171
+
172
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
173
+ # The default implementation for visiting an AST node.
174
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
175
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
176
+ # in your subclasses.
177
+ #
178
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
179
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
180
+ # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
181
+ def #{node_method}(node, parent)
182
+ if node.equal?(DELETE_NODE)
183
+ # This might be passed to `super(DELETE_NODE, ...)`
184
+ # by a user hook, don't want to keep visiting in that case.
185
+ [node, parent]
186
+ else
187
+ new_node = node
188
+ #{
189
+ if method_defined?(child_visit_method)
190
+ "new_node = #{child_visit_method}(new_node)"
191
+ elsif children_of_type
192
+ children_of_type.map do |child_accessor, child_class|
193
+ "node.#{child_accessor}.each do |child_node|
194
+ new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
195
+ # Reassign `node` in case the child hook makes a modification
196
+ if new_child_and_node.is_a?(Array)
197
+ new_node = new_child_and_node[1]
198
+ end
199
+ end"
200
+ end.join("\n")
201
+ else
202
+ ""
203
+ end
204
+ }
205
+
206
+ if new_node.equal?(node)
207
+ [node, parent]
208
+ else
209
+ [new_node, parent]
210
+ end
211
+ end
212
+ end
213
+
214
+ def #{node_method}_with_modifications(node, parent)
215
+ new_node_and_new_parent = #{node_method}(node, parent)
216
+ apply_modifications(node, parent, new_node_and_new_parent)
217
+ end
218
+ RUBY
219
+ end
220
+
219
221
  [
220
222
  Language::Nodes::Argument,
221
223
  Language::Nodes::Directive,
@@ -256,6 +258,8 @@ module GraphQL
256
258
  make_visit_methods(ast_node_class)
257
259
  end
258
260
 
261
+ # rubocop:enable Development/NoEvalCop
262
+
259
263
  private
260
264
 
261
265
  def apply_modifications(node, parent, new_node_and_new_parent)
@@ -53,6 +53,7 @@ module GraphQL
53
53
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, comment: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
54
54
  arg_name ||= name
55
55
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
56
+ NameValidator.validate!(@name)
56
57
  @type_expr = type_expr || type
57
58
  @description = desc || description
58
59
  @comment = comment
@@ -89,11 +90,8 @@ module GraphQL
89
90
  end
90
91
 
91
92
  if definition_block
92
- if definition_block.arity == 1
93
- instance_exec(self, &definition_block)
94
- else
95
- instance_eval(&definition_block)
96
- end
93
+ # `self` will still be self, it will also be the first argument to the block:
94
+ instance_exec(self, &definition_block)
97
95
  end
98
96
  end
99
97
 
@@ -467,17 +467,18 @@ module GraphQL
467
467
 
468
468
  # Don't do this for interfaces
469
469
  if default_resolve
470
- owner.class_eval <<-RUBY, __FILE__, __LINE__
471
- # frozen_string_literal: true
472
- def #{resolve_method_name}(**args)
473
- field_instance = self.class.get_field("#{field_definition.name}")
474
- context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
475
- end
476
- RUBY
470
+ define_field_resolve_method(owner, resolve_method_name, field_definition.name)
477
471
  end
478
472
  end
479
473
  end
480
474
 
475
+ def define_field_resolve_method(owner, method_name, field_name)
476
+ owner.define_method(method_name) { |**args|
477
+ field_instance = self.class.get_field(field_name)
478
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
479
+ }
480
+ end
481
+
481
482
  def build_resolve_type(lookup_hash, directives, missing_type_handler)
482
483
  resolve_type_proc = nil
483
484
  resolve_type_proc = ->(ast_node) {
@@ -99,7 +99,7 @@ module GraphQL
99
99
 
100
100
  def inherited(subclass)
101
101
  super
102
- subclass.class_eval do
102
+ subclass.class_exec do
103
103
  @default_graphql_name ||= nil
104
104
  end
105
105
  end
@@ -153,6 +153,8 @@ module GraphQL
153
153
  else
154
154
  nil
155
155
  end
156
+ # rescue MissingValuesError
157
+ # nil
156
158
  end
157
159
 
158
160
  # Called by the runtime when a field returns a value to give back to the client.
@@ -48,7 +48,7 @@ module GraphQL
48
48
  end
49
49
 
50
50
  if block_given?
51
- instance_eval(&block)
51
+ instance_exec(self, &block)
52
52
  end
53
53
  end
54
54
 
@@ -255,7 +255,7 @@ module GraphQL
255
255
 
256
256
  @underscored_name = -Member::BuildType.underscore(name_s)
257
257
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
258
-
258
+ NameValidator.validate!(@name)
259
259
  @description = description
260
260
  @comment = comment
261
261
  @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
@@ -369,7 +369,7 @@ module GraphQL
369
369
  if @definition_block.arity == 1
370
370
  @definition_block.call(self)
371
371
  else
372
- instance_eval(&@definition_block)
372
+ instance_exec(self, &@definition_block)
373
373
  end
374
374
  self.extensions.each(&:after_define_apply)
375
375
  @call_after_define = true
@@ -132,13 +132,9 @@ module GraphQL
132
132
  end
133
133
  end
134
134
  # Add a method access
135
- method_name = argument_defn.keyword
136
- class_eval <<-RUBY, __FILE__, __LINE__
137
- def #{method_name}
138
- self[#{method_name.inspect}]
139
- end
140
- alias_method :#{method_name}, :#{method_name}
141
- RUBY
135
+ suppress_redefinition_warning do
136
+ define_accessor_method(argument_defn.keyword)
137
+ end
142
138
  argument_defn
143
139
  end
144
140
 
@@ -163,7 +159,7 @@ module GraphQL
163
159
 
164
160
  # Inject missing required arguments
165
161
  missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
166
- if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
162
+ if !input.key?(argument.graphql_name) && argument.type.non_null? && !argument.default_value? && types.argument(self, argument.graphql_name)
167
163
  m[argument.graphql_name] = nil
168
164
  end
169
165
 
@@ -243,6 +239,22 @@ module GraphQL
243
239
 
244
240
  result
245
241
  end
242
+
243
+ private
244
+
245
+ # Suppress redefinition warning for objectId arguments
246
+ def suppress_redefinition_warning
247
+ verbose = $VERBOSE
248
+ $VERBOSE = nil
249
+ yield
250
+ ensure
251
+ $VERBOSE = verbose
252
+ end
253
+
254
+ def define_accessor_method(method_name)
255
+ define_method(method_name) { self[method_name] }
256
+ alias_method(method_name, method_name)
257
+ end
246
258
  end
247
259
 
248
260
  private
@@ -29,7 +29,7 @@ module GraphQL
29
29
  const_set(:DefinitionMethods, defn_methods_module)
30
30
  extend(self::DefinitionMethods)
31
31
  end
32
- self::DefinitionMethods.module_eval(&block)
32
+ self::DefinitionMethods.module_exec(&block)
33
33
  end
34
34
 
35
35
  # @see {Schema::Warden} hides interfaces without visible implementations
@@ -6,7 +6,7 @@ module GraphQL
6
6
  module HasDirectives
7
7
  def self.extended(child_cls)
8
8
  super
9
- child_cls.module_eval { self.own_directives = nil }
9
+ child_cls.module_exec { self.own_directives = nil }
10
10
  end
11
11
 
12
12
  def inherited(child_cls)
@@ -185,7 +185,7 @@ module GraphQL
185
185
 
186
186
  def inherited(subclass)
187
187
  super
188
- subclass.class_eval do
188
+ subclass.class_exec do
189
189
  @own_fields ||= nil
190
190
  @field_class ||= nil
191
191
  end
@@ -133,7 +133,7 @@ module GraphQL
133
133
 
134
134
  def inherited(subclass)
135
135
  super
136
- subclass.class_eval do
136
+ subclass.class_exec do
137
137
  @own_interface_type_memberships ||= nil
138
138
  end
139
139
  end
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  def inherited(subclass)
32
32
  super
33
- subclass.class_eval do
33
+ subclass.class_exec do
34
34
  @reauthorize_scoped_objects = nil
35
35
  end
36
36
  end
@@ -42,7 +42,7 @@ module GraphQL
42
42
  private
43
43
 
44
44
  def inherited(subclass)
45
- subclass.class_eval do
45
+ subclass.class_exec do
46
46
  @to_non_null_type ||= nil
47
47
  @to_list_type ||= nil
48
48
  end
@@ -431,6 +431,14 @@ module GraphQL
431
431
  end
432
432
  end
433
433
 
434
+ # Get or set the root `query { ... }` object for this schema.
435
+ #
436
+ # @example Using `Types::Query` as the entry-point
437
+ # query { Types::Query }
438
+ #
439
+ # @param new_query_object [Class<GraphQL::Schema::Object>] The root type to use for queries
440
+ # @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root query type.
441
+ # @return [Class<GraphQL::Schema::Object>, nil] The configured query root type, if there is one.
434
442
  def query(new_query_object = nil, &lazy_load_block)
435
443
  if new_query_object || block_given?
436
444
  if @query_object
@@ -450,6 +458,14 @@ module GraphQL
450
458
  end
451
459
  end
452
460
 
461
+ # Get or set the root `mutation { ... }` object for this schema.
462
+ #
463
+ # @example Using `Types::Mutation` as the entry-point
464
+ # mutation { Types::Mutation }
465
+ #
466
+ # @param new_mutation_object [Class<GraphQL::Schema::Object>] The root type to use for mutations
467
+ # @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root mutation type.
468
+ # @return [Class<GraphQL::Schema::Object>, nil] The configured mutation root type, if there is one.
453
469
  def mutation(new_mutation_object = nil, &lazy_load_block)
454
470
  if new_mutation_object || block_given?
455
471
  if @mutation_object
@@ -469,6 +485,14 @@ module GraphQL
469
485
  end
470
486
  end
471
487
 
488
+ # Get or set the root `subscription { ... }` object for this schema.
489
+ #
490
+ # @example Using `Types::Subscription` as the entry-point
491
+ # subscription { Types::Subscription }
492
+ #
493
+ # @param new_subscription_object [Class<GraphQL::Schema::Object>] The root type to use for subscriptions
494
+ # @param lazy_load_block If a block is given, then it will be called when GraphQL-Ruby needs the root subscription type.
495
+ # @return [Class<GraphQL::Schema::Object>, nil] The configured subscription root type, if there is one.
472
496
  def subscription(new_subscription_object = nil, &lazy_load_block)
473
497
  if new_subscription_object || block_given?
474
498
  if @subscription_object
@@ -492,8 +516,7 @@ module GraphQL
492
516
  end
493
517
  end
494
518
 
495
- # @see [GraphQL::Schema::Warden] Restricted access to root types
496
- # @return [GraphQL::ObjectType, nil]
519
+ # @api private
497
520
  def root_type_for_operation(operation)
498
521
  case operation
499
522
  when "query"
@@ -507,6 +530,7 @@ module GraphQL
507
530
  end
508
531
  end
509
532
 
533
+ # @return [Array<Class>] The root types (query, mutation, subscription) defined for this schema
510
534
  def root_types
511
535
  if use_visibility_profile?
512
536
  [query, mutation, subscription].compact
@@ -515,6 +539,7 @@ module GraphQL
515
539
  end
516
540
  end
517
541
 
542
+ # @api private
518
543
  def warden_class
519
544
  if defined?(@warden_class)
520
545
  @warden_class
@@ -525,6 +550,7 @@ module GraphQL
525
550
  end
526
551
  end
527
552
 
553
+ # @api private
528
554
  attr_writer :warden_class
529
555
 
530
556
  # @api private
@@ -786,6 +812,7 @@ module GraphQL
786
812
  res[:errors]
787
813
  end
788
814
 
815
+ # @param new_query_class [Class<GraphQL::Query>] A subclass to use when executing queries
789
816
  def query_class(new_query_class = NOT_CONFIGURED)
790
817
  if NOT_CONFIGURED.equal?(new_query_class)
791
818
  @query_class || (superclass.respond_to?(:query_class) ? superclass.query_class : GraphQL::Query)
@@ -971,6 +998,8 @@ module GraphQL
971
998
  end
972
999
  end
973
1000
 
1001
+
1002
+ # @param new_default_logger [#log] Something to use for logging messages
974
1003
  def default_logger(new_default_logger = NOT_CONFIGURED)
975
1004
  if NOT_CONFIGURED.equal?(new_default_logger)
976
1005
  if defined?(@default_logger)
@@ -991,6 +1020,7 @@ module GraphQL
991
1020
  end
992
1021
  end
993
1022
 
1023
+ # @param new_context_class [Class<GraphQL::Query::Context>] A subclass to use when executing queries
994
1024
  def context_class(new_context_class = nil)
995
1025
  if new_context_class
996
1026
  @context_class = new_context_class
@@ -999,6 +1029,20 @@ module GraphQL
999
1029
  end
1000
1030
  end
1001
1031
 
1032
+ # Register a handler for errors raised during execution. The handlers can return a new value or raise a new error.
1033
+ #
1034
+ # @example Handling "not found" with a client-facing error
1035
+ # rescue_from(ActiveRecord::NotFound) { raise GraphQL::ExecutionError, "An object could not be found" }
1036
+ #
1037
+ # @param err_classes [Array<StandardError>] Classes which should be rescued by `handler_block`
1038
+ # @param handler_block The code to run when one of those errors is raised during execution
1039
+ # @yieldparam error [StandardError] An instance of one of the configured `err_classes`
1040
+ # @yieldparam object [Object] The current application object in the query when the error was raised
1041
+ # @yieldparam arguments [GraphQL::Query::Arguments] The current field arguments when the error was raised
1042
+ # @yieldparam context [GraphQL::Query::Context] The context for the currently-running operation
1043
+ # @yieldreturn [Object] Some object to use in the place where this error was raised
1044
+ # @raise [GraphQL::ExecutionError] In the handler, raise to add a client-facing error to the response
1045
+ # @raise [StandardError] In the handler, raise to crash the query with a developer-facing error
1002
1046
  def rescue_from(*err_classes, &handler_block)
1003
1047
  err_classes.each do |err_class|
1004
1048
  Execution::Errors.register_rescue_from(err_class, error_handlers[:subclass_handlers], handler_block)
@@ -1065,8 +1109,24 @@ module GraphQL
1065
1109
  end
1066
1110
  end
1067
1111
 
1068
- def resolve_type(type, obj, ctx)
1069
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{type.name})"
1112
+ # GraphQL-Ruby calls this method during execution when it needs the application to determine the type to use for an object.
1113
+ #
1114
+ # Usually, this object was returned from a field whose return type is an {GraphQL::Schema::Interface} or a {GraphQL::Schema::Union}.
1115
+ # But this method is called in other cases, too -- for example, when {GraphQL::Schema::Argument.loads} cases an object to be directly loaded from the database.
1116
+ #
1117
+ # @example Returning a GraphQL type based on the object's class name
1118
+ # class MySchema < GraphQL::Schema
1119
+ # def resolve_type(_abs_type, object, _context)
1120
+ # graphql_type_name = "Types::#{object.class.name}Type"
1121
+ # graphql_type_name.constantize # If this raises a NameError, then come implement special cases in this method
1122
+ # end
1123
+ # end
1124
+ # @param abstract_type [Class, Module, nil] The Interface or Union type which is being resolved, if there is one
1125
+ # @param application_object [Object] The object returned from a field whose type must be determined
1126
+ # @param context [GraphQL::Query::Context] The query context for the currently-executing query
1127
+ # @return [Class<GraphQL::Schema::Object] The Object type definition to use for `obj`
1128
+ def resolve_type(abstract_type, application_object, context)
1129
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(abstract_type, application_object, context) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{abstract_type.name})"
1070
1130
  end
1071
1131
  # rubocop:enable Lint/DuplicateMethods
1072
1132
 
@@ -1089,12 +1149,37 @@ module GraphQL
1089
1149
  super
1090
1150
  end
1091
1151
 
1092
- def object_from_id(node_id, ctx)
1093
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(node_id, ctx) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1094
- end
1095
-
1096
- def id_from_object(object, type, ctx)
1097
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(object, type, ctx) must be implemented to create global ids (tried to create an id for `#{object.inspect}`)"
1152
+ # Fetch an object based on an incoming ID and the current context. This method should return an object
1153
+ # from your application, or return `nil` if there is no object or the object shouldn't be available to this operation.
1154
+ #
1155
+ # @example Fetching an object with Rails's GlobalID
1156
+ # def self.object_from_id(object_id, _context)
1157
+ # GlobalID.find(global_id)
1158
+ # # TODO: use `context[:current_user]` to determine if this object is authorized.
1159
+ # end
1160
+ # @param object_id [String] The ID to fetch an object for. This may be client-provided (as in `node(id: ...)` or `loads:`) or previously stored by the schema (eg, by the `ObjectCache`)
1161
+ # @param context [GraphQL::Query::Context] The context for the currently-executing operation
1162
+ # @return [Object, nil] The application which `object_id` references, or `nil` if there is no object or the current operation shouldn't have access to the object
1163
+ # @see id_from_object which produces these IDs
1164
+ def object_from_id(object_id, context)
1165
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(object_id, context) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1166
+ end
1167
+
1168
+ # Return a stable ID string for `object` so that it can be refetched later, using {.object_from_id}.
1169
+ #
1170
+ # {GlobalID}(https://github.com/rails/globalid) and {SQIDs}(https://sqids.org/ruby) can both be used to create IDs.
1171
+ #
1172
+ # @example Using Rails's GlobalID to generate IDs
1173
+ # def self.id_from_object(application_object, graphql_type, context)
1174
+ # application_object.to_gid_param
1175
+ # end
1176
+ #
1177
+ # @param application_object [Object] Some object encountered by GraphQL-Ruby while running a query
1178
+ # @param graphql_type [Class, Module] The type that GraphQL-Ruby is using for `application_object` during this query
1179
+ # @param context [GraphQL::Query::Context] The context for the operation that is currently running
1180
+ # @return [String] A stable identifier which can be passed to {.object_from_id} later to re-fetch `application_object`
1181
+ def id_from_object(application_object, graphql_type, context)
1182
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.id_from_object(application_object, graphql_type, context) must be implemented to create global ids (tried to create an id for `#{application_object.inspect}`)"
1098
1183
  end
1099
1184
 
1100
1185
  def visible?(member, ctx)
@@ -1149,6 +1234,16 @@ module GraphQL
1149
1234
  unauthorized_object(unauthorized_error)
1150
1235
  end
1151
1236
 
1237
+ # Called at runtime when GraphQL-Ruby encounters a mismatch between the application behavior
1238
+ # and the GraphQL type system.
1239
+ #
1240
+ # The default implementation of this method is to follow the GraphQL specification,
1241
+ # but you can override this to report errors to your bug tracker or customize error handling.
1242
+ # @param type_error [GraphQL::Error] several specific error classes are passed here, see the default implementation for details
1243
+ # @param context [GraphQL::Query::Context] the context for the currently-running operation
1244
+ # @return [void]
1245
+ # @raise [GraphQL::ExecutionError] to return this error to the client
1246
+ # @raise [GraphQL::Error] to crash the query and raise a developer-facing error
1152
1247
  def type_error(type_error, ctx)
1153
1248
  case type_error
1154
1249
  when GraphQL::InvalidNullError
@@ -1244,6 +1339,7 @@ module GraphQL
1244
1339
  # @param mode [Symbol] Trace module will only be used for this trade mode
1245
1340
  # @param options [Hash] Keywords that will be passed to the tracing class during `#initialize`
1246
1341
  # @return [void]
1342
+ # @see GraphQL::Tracing::Trace for available tracing methods
1247
1343
  def trace_with(trace_mod, mode: :default, **options)
1248
1344
  if mode.is_a?(Array)
1249
1345
  mode.each { |m| trace_with(trace_mod, mode: m, **options) }
@@ -1321,6 +1417,8 @@ module GraphQL
1321
1417
  trace_class_for_mode.new(**trace_options)
1322
1418
  end
1323
1419
 
1420
+ # @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on queries to this schema
1421
+ # @see GraphQL::Analysis the analysis system
1324
1422
  def query_analyzer(new_analyzer)
1325
1423
  own_query_analyzers << new_analyzer
1326
1424
  end
@@ -1329,6 +1427,8 @@ module GraphQL
1329
1427
  find_inherited_value(:query_analyzers, EMPTY_ARRAY) + own_query_analyzers
1330
1428
  end
1331
1429
 
1430
+ # @param new_analyzer [Class<GraphQL::Analysis::Analyzer>] An analyzer to run on multiplexes to this schema
1431
+ # @see GraphQL::Analysis the analysis system
1332
1432
  def multiplex_analyzer(new_analyzer)
1333
1433
  own_multiplex_analyzers << new_analyzer
1334
1434
  end
@@ -1412,6 +1512,11 @@ module GraphQL
1412
1512
  end
1413
1513
  end
1414
1514
 
1515
+ # Called when execution encounters a `SystemStackError`. By default, it adds a client-facing error to the response.
1516
+ # You could modify this method to report this error to your bug tracker.
1517
+ # @param query [GraphQL::Query]
1518
+ # @param err [SystemStackError]
1519
+ # @return [void]
1415
1520
  def query_stack_error(query, err)
1416
1521
  query.context.errors.push(GraphQL::ExecutionError.new("This query is too large to execute."))
1417
1522
  end
@@ -28,6 +28,8 @@ module GraphQL
28
28
  Gem::Version.new('1.0.0')
29
29
  end
30
30
 
31
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
32
+
31
33
  [
32
34
  'lex',
33
35
  'parse',
@@ -55,6 +57,8 @@ module GraphQL
55
57
  RUBY
56
58
  end
57
59
 
60
+ # rubocop:enable Development/NoEvalCop
61
+
58
62
  def execute_field(query:, field:, ast_node:, arguments:, object:)
59
63
  return_type = field.type.unwrap
60
64
  trace_field = if return_type.kind.scalar? || return_type.kind.enum?
@@ -13,6 +13,8 @@ module GraphQL
13
13
  super
14
14
  end
15
15
 
16
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
17
+
16
18
  {
17
19
  "lex" => "lex.graphql",
18
20
  "parse" => "parse.graphql",
@@ -43,6 +45,8 @@ module GraphQL
43
45
  RUBY
44
46
  end
45
47
 
48
+ # rubocop:enable Development/NoEvalCop
49
+
46
50
  def platform_execute_field(platform_key)
47
51
  Appsignal.instrument(platform_key) do
48
52
  yield
@@ -20,6 +20,8 @@ module GraphQL
20
20
  super
21
21
  end
22
22
 
23
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
24
+
23
25
  {
24
26
  'lex' => 'lex.graphql',
25
27
  'parse' => 'parse.graphql',
@@ -69,6 +71,8 @@ module GraphQL
69
71
  RUBY
70
72
  end
71
73
 
74
+ # rubocop:enable Development/NoEvalCop
75
+
72
76
  def execute_field_span(span_key, query, field, ast_node, arguments, object)
73
77
  return_type = field.type.unwrap
74
78
  trace_field = if return_type.kind.scalar? || return_type.kind.enum?
@@ -16,6 +16,8 @@ module GraphQL
16
16
  super
17
17
  end
18
18
 
19
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
20
+
19
21
  {
20
22
  "lex" => "lex.graphql",
21
23
  "parse" => "parse.graphql",
@@ -39,6 +41,8 @@ module GraphQL
39
41
  RUBY
40
42
  end
41
43
 
44
+ # rubocop:enable Development/NoEvalCop
45
+
42
46
  include PlatformTrace
43
47
  end
44
48
  end
@@ -39,6 +39,9 @@ module GraphQL
39
39
  include(BaseKeyCache)
40
40
  }
41
41
  child_class.const_set(:KeyCache, key_methods_class)
42
+
43
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
44
+
42
45
  [:execute_field, :execute_field_lazy].each do |field_trace_method|
43
46
  if !child_class.method_defined?(field_trace_method)
44
47
  child_class.module_eval <<-RUBY, __FILE__, __LINE__
@@ -91,6 +94,8 @@ module GraphQL
91
94
  end
92
95
  RUBY
93
96
  end
97
+
98
+ # rubocop:enable Development/NoEvalCop
94
99
  end
95
100
  end
96
101
 
@@ -13,6 +13,8 @@ module GraphQL
13
13
  super(**rest)
14
14
  end
15
15
 
16
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
17
+
16
18
  {
17
19
  'lex' => "graphql.lex",
18
20
  'parse' => "graphql.parse",
@@ -30,6 +32,8 @@ module GraphQL
30
32
  RUBY
31
33
  end
32
34
 
35
+ # rubocop:enable Development/NoEvalCop
36
+
33
37
  def platform_execute_field(platform_key, &block)
34
38
  instrument_prometheus_execution(platform_key, "execute_field", &block)
35
39
  end
@@ -16,6 +16,8 @@ module GraphQL
16
16
  super
17
17
  end
18
18
 
19
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
20
+
19
21
  {
20
22
  "lex" => "lex.graphql",
21
23
  "parse" => "parse.graphql",
@@ -45,6 +47,7 @@ module GraphQL
45
47
  end
46
48
  RUBY
47
49
  end
50
+ # rubocop:enable Development/NoEvalCop
48
51
 
49
52
  def platform_execute_field(platform_key, &block)
50
53
  self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
@@ -23,6 +23,8 @@ module GraphQL
23
23
  instrument_sentry_execution("graphql.execute", "execute_query", data) { super }
24
24
  end
25
25
 
26
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
27
+
26
28
  {
27
29
  "lex" => "graphql.lex",
28
30
  "parse" => "graphql.parse",
@@ -39,6 +41,8 @@ module GraphQL
39
41
  RUBY
40
42
  end
41
43
 
44
+ # rubocop:enable Development/NoEvalCop
45
+
42
46
  def platform_execute_field(platform_key, &block)
43
47
  instrument_sentry_execution(platform_key, "execute_field", &block)
44
48
  end
@@ -11,6 +11,8 @@ module GraphQL
11
11
  super(**rest)
12
12
  end
13
13
 
14
+ # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
15
+
14
16
  {
15
17
  'lex' => "graphql.lex",
16
18
  'parse' => "graphql.parse",
@@ -30,6 +32,8 @@ module GraphQL
30
32
  RUBY
31
33
  end
32
34
 
35
+ # rubocop:enable Development/NoEvalCop
36
+
33
37
  def platform_execute_field(platform_key, &block)
34
38
  @statsd.time(platform_key, &block)
35
39
  end
@@ -13,7 +13,7 @@ module GraphQL
13
13
  child_class.node_nullable(true)
14
14
  child_class.edges_nullable(true)
15
15
  child_class.edge_nullable(true)
16
- child_class.module_eval {
16
+ child_class.module_exec {
17
17
  self.edge_type = nil
18
18
  self.node_type = nil
19
19
  self.edge_class = nil
@@ -8,7 +8,7 @@ module GraphQL
8
8
  child_class.description("An edge in a connection.")
9
9
  child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
10
10
  child_class.extend(ClassMethods)
11
- child_class.class_eval { self.node_type = nil }
11
+ child_class.class_exec { self.node_type = nil }
12
12
  child_class.node_nullable(true)
13
13
  child_class.default_broadcastable(nil)
14
14
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.3.19"
3
+ VERSION = "2.3.21"
4
4
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.19
4
+ version: 2.3.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-24 00:00:00.000000000 Z
10
+ date: 2025-03-12 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: base64
@@ -650,7 +649,6 @@ metadata:
650
649
  bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
651
650
  mailing_list_uri: https://buttondown.email/graphql-ruby
652
651
  rubygems_mfa_required: 'true'
653
- post_install_message:
654
652
  rdoc_options: []
655
653
  require_paths:
656
654
  - lib
@@ -665,8 +663,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
665
663
  - !ruby/object:Gem::Version
666
664
  version: '0'
667
665
  requirements: []
668
- rubygems_version: 3.5.12
669
- signing_key:
666
+ rubygems_version: 3.6.3
670
667
  specification_version: 4
671
668
  summary: A GraphQL language and runtime for Ruby
672
669
  test_files: []