graphql 2.3.4 → 2.3.6

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/graphql/analysis/analyzer.rb +89 -0
  4. data/lib/graphql/analysis/field_usage.rb +82 -0
  5. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  6. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  7. data/lib/graphql/analysis/query_complexity.rb +183 -0
  8. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  9. data/lib/graphql/analysis/visitor.rb +282 -0
  10. data/lib/graphql/analysis.rb +92 -1
  11. data/lib/graphql/dataloader/async_dataloader.rb +2 -0
  12. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  13. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +7 -4
  14. data/lib/graphql/execution/interpreter/runtime.rb +40 -59
  15. data/lib/graphql/execution/interpreter.rb +2 -2
  16. data/lib/graphql/language/nodes.rb +17 -22
  17. data/lib/graphql/language/parser.rb +54 -13
  18. data/lib/graphql/query/validation_pipeline.rb +2 -2
  19. data/lib/graphql/query.rb +1 -1
  20. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  21. data/lib/graphql/schema/addition.rb +21 -11
  22. data/lib/graphql/schema/argument.rb +19 -5
  23. data/lib/graphql/schema/directive.rb +2 -0
  24. data/lib/graphql/schema/field.rb +8 -0
  25. data/lib/graphql/schema/has_single_input_argument.rb +1 -0
  26. data/lib/graphql/schema/input_object.rb +1 -0
  27. data/lib/graphql/schema/introspection_system.rb +2 -2
  28. data/lib/graphql/schema/late_bound_type.rb +4 -0
  29. data/lib/graphql/schema/list.rb +2 -2
  30. data/lib/graphql/schema/member/has_arguments.rb +2 -35
  31. data/lib/graphql/schema/member/has_directives.rb +1 -1
  32. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  33. data/lib/graphql/schema/member/type_system_helpers.rb +1 -2
  34. data/lib/graphql/schema/resolver.rb +1 -0
  35. data/lib/graphql/schema/warden.rb +2 -3
  36. data/lib/graphql/schema.rb +20 -20
  37. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  38. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  39. data/lib/graphql/subscriptions/broadcast_analyzer.rb +1 -1
  40. data/lib/graphql/subscriptions.rb +1 -1
  41. data/lib/graphql/type_kinds.rb +1 -1
  42. data/lib/graphql/version.rb +1 -1
  43. data/lib/graphql.rb +0 -8
  44. metadata +10 -11
  45. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  46. data/lib/graphql/analysis/ast/field_usage.rb +0 -84
  47. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  48. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  49. data/lib/graphql/analysis/ast/query_complexity.rb +0 -185
  50. data/lib/graphql/analysis/ast/visitor.rb +0 -284
  51. data/lib/graphql/analysis/ast.rb +0 -94
@@ -41,6 +41,14 @@ module GraphQL
41
41
  end
42
42
  end
43
43
 
44
+ def directives
45
+ if @resolver_class
46
+ @resolver_class.directives
47
+ else
48
+ super
49
+ end
50
+ end
51
+
44
52
  # @return [Class] The thing this field was defined on (type, mutation, resolver)
45
53
  attr_accessor :owner
46
54
 
@@ -47,6 +47,7 @@ module GraphQL
47
47
  def dummy
48
48
  @dummy ||= begin
49
49
  d = Class.new(GraphQL::Schema::Resolver)
50
+ d.graphql_name "#{self.graphql_name}DummyResolver"
50
51
  d.argument_class(self.argument_class)
51
52
  # TODO make this lazier?
52
53
  d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
@@ -136,6 +136,7 @@ module GraphQL
136
136
  def #{method_name}
137
137
  self[#{method_name.inspect}]
138
138
  end
139
+ alias_method :#{method_name}, :#{method_name}
139
140
  RUBY
140
141
  argument_defn
141
142
  end
@@ -25,10 +25,10 @@ module GraphQL
25
25
  load_constant(:DirectiveLocationEnum)
26
26
  ]
27
27
  @types = {}
28
- @possible_types = {}
28
+ @possible_types = {}.tap(&:compare_by_identity)
29
29
  type_defns.each do |t|
30
30
  @types[t.graphql_name] = t
31
- @possible_types[t.graphql_name] = [t]
31
+ @possible_types[t] = [t]
32
32
  end
33
33
  @entry_point_fields =
34
34
  if schema.disable_introspection_entry_points?
@@ -25,6 +25,10 @@ module GraphQL
25
25
  @to_list_type ||= GraphQL::Schema::List.new(self)
26
26
  end
27
27
 
28
+ def to_type_signature
29
+ name
30
+ end
31
+
28
32
  def inspect
29
33
  "#<LateBoundType @name=#{name}>"
30
34
  end
@@ -52,7 +52,7 @@ module GraphQL
52
52
  unless item_result.valid?
53
53
  if max_errors
54
54
  if max_errors == 0
55
- add_max_errros_reached_message(result)
55
+ add_max_errors_reached_message(result)
56
56
  break
57
57
  end
58
58
 
@@ -76,7 +76,7 @@ module GraphQL
76
76
  end
77
77
  end
78
78
 
79
- def add_max_errros_reached_message(result)
79
+ def add_max_errors_reached_message(result)
80
80
  message = "Too many errors processing list variable, max validation error limit reached. Execution aborted"
81
81
  item_result = GraphQL::Query::InputValidationResult.from_problem(message)
82
82
  result.merge_result!(nil, item_result)
@@ -38,39 +38,6 @@ module GraphQL
38
38
  end
39
39
  arg_defn = self.argument_class.new(*args, **kwargs, &block)
40
40
  add_argument(arg_defn)
41
-
42
- if self.is_a?(Class) && !method_defined?(:"load_#{arg_defn.keyword}")
43
- method_owner = if self < GraphQL::Schema::InputObject || self < GraphQL::Schema::Directive
44
- "self."
45
- elsif self < GraphQL::Schema::Resolver
46
- ""
47
- else
48
- raise "Unexpected argument owner: #{self}"
49
- end
50
- if loads && arg_defn.type.list?
51
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
52
- def #{method_owner}load_#{arg_defn.keyword}(values, context = nil)
53
- argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
54
- (context || self.context).query.after_lazy(values) do |values2|
55
- GraphQL::Execution::Lazy.all(values2.map { |value| load_application_object(argument, value, context || self.context) })
56
- end
57
- end
58
- RUBY
59
- elsif loads
60
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
- def #{method_owner}load_#{arg_defn.keyword}(value, context = nil)
62
- argument = get_argument("#{arg_defn.graphql_name}", context || self.context)
63
- load_application_object(argument, value, context || self.context)
64
- end
65
- RUBY
66
- else
67
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
68
- def #{method_owner}load_#{arg_defn.keyword}(value, _context = nil)
69
- value
70
- end
71
- RUBY
72
- end
73
- end
74
41
  arg_defn
75
42
  end
76
43
 
@@ -259,8 +226,8 @@ module GraphQL
259
226
  #
260
227
  # @param values [Hash<String, Object>]
261
228
  # @param context [GraphQL::Query::Context]
262
- # @yield [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
263
- # @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
229
+ # @yield [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
230
+ # @return [Interpreter::Arguments, Execution::Lazy<Interpreter::Arguments>]
264
231
  def coerce_arguments(parent_object, values, context, &block)
265
232
  # Cache this hash to avoid re-merging it
266
233
  arg_defns = context.warden.arguments(self)
@@ -91,7 +91,7 @@ module GraphQL
91
91
  private
92
92
 
93
93
  # Modify `target` by adding items from `dirs` such that:
94
- # - Any name conflict is overriden by the incoming member of `dirs`
94
+ # - Any name conflict is overridden by the incoming member of `dirs`
95
95
  # - Any other member of `dirs` is appended
96
96
  # @param target [Array<GraphQL::Schema::Directive>]
97
97
  # @param dirs [Array<GraphQL::Schema::Directive>]
@@ -76,7 +76,7 @@ module GraphQL
76
76
 
77
77
  private
78
78
 
79
- # If one of thse values is accessed, initialize all the instance variables to retain
79
+ # If one of these values is accessed, initialize all the instance variables to retain
80
80
  # a consistent object shape.
81
81
  def initialize_relay_metadata
82
82
  if !defined?(@connection_type)
@@ -4,12 +4,11 @@ module GraphQL
4
4
  class Schema
5
5
  class Member
6
6
  module TypeSystemHelpers
7
- def initialize(*args, &block)
7
+ def initialize(...)
8
8
  super
9
9
  @to_non_null_type ||= nil
10
10
  @to_list_type ||= nil
11
11
  end
12
- ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
13
12
 
14
13
  # @return [Schema::NonNull] Make a non-null-type representation of this type
15
14
  def to_non_null_type
@@ -25,6 +25,7 @@ module GraphQL
25
25
  extend GraphQL::Schema::Member::HasValidators
26
26
  include Schema::Member::HasPath
27
27
  extend Schema::Member::HasPath
28
+ extend Schema::Member::HasDirectives
28
29
 
29
30
  # @param object [Object] The application object that this field is being resolved on
30
31
  # @param context [GraphQL::Query::Context]
@@ -295,7 +295,7 @@ module GraphQL
295
295
  true
296
296
  else
297
297
  if @context.respond_to?(:logger) && (logger = @context.logger)
298
- logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementors" }
298
+ logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementers" }
299
299
  end
300
300
  false
301
301
  end
@@ -363,8 +363,7 @@ module GraphQL
363
363
  end
364
364
 
365
365
  def referenced?(type_defn)
366
- graphql_name = type_defn.unwrap.graphql_name
367
- members = @schema.references_to(graphql_name)
366
+ members = @schema.references_to(type_defn)
368
367
  members.any? { |m| visible?(m) }
369
368
  end
370
369
 
@@ -187,7 +187,7 @@ module GraphQL
187
187
  # {default_trace_mode} is used when no `trace_mode: ...` is requested.
188
188
  #
189
189
  # When a `trace_class` is added this way, it will _not_ receive other modules added with `trace_with(...)`
190
- # unless `trace_mode` is explicitly given. (This class will not recieve any default trace modules.)
190
+ # unless `trace_mode` is explicitly given. (This class will not receive any default trace modules.)
191
191
  #
192
192
  # Subclasses of the schema will use `trace_class` as a base class for this mode and those
193
193
  # subclass also will _not_ receive default tracing modules.
@@ -506,7 +506,7 @@ module GraphQL
506
506
  if type.kind.union?
507
507
  type.possible_types(context: context)
508
508
  else
509
- stored_possible_types = own_possible_types[type.graphql_name]
509
+ stored_possible_types = own_possible_types[type]
510
510
  visible_possible_types = if stored_possible_types && type.kind.interface?
511
511
  stored_possible_types.select do |possible_type|
512
512
  possible_type.interfaces(context).include?(type)
@@ -515,7 +515,7 @@ module GraphQL
515
515
  stored_possible_types
516
516
  end
517
517
  visible_possible_types ||
518
- introspection_system.possible_types[type.graphql_name] ||
518
+ introspection_system.possible_types[type] ||
519
519
  (
520
520
  superclass.respond_to?(:possible_types) ?
521
521
  superclass.possible_types(type, context) :
@@ -553,14 +553,9 @@ module GraphQL
553
553
  attr_writer :dataloader_class
554
554
 
555
555
  def references_to(to_type = nil, from: nil)
556
- @own_references_to ||= {}
557
556
  if to_type
558
- if !to_type.is_a?(String)
559
- to_type = to_type.graphql_name
560
- end
561
-
562
557
  if from
563
- refs = @own_references_to[to_type] ||= []
558
+ refs = own_references_to[to_type] ||= []
564
559
  refs << from
565
560
  else
566
561
  get_references_to(to_type) || EMPTY_ARRAY
@@ -571,9 +566,9 @@ module GraphQL
571
566
  # So optimize the most common case -- don't create a duplicate Hash.
572
567
  inherited_value = find_inherited_value(:references_to, EMPTY_HASH)
573
568
  if inherited_value.any?
574
- inherited_value.merge(@own_references_to)
569
+ inherited_value.merge(own_references_to)
575
570
  else
576
- @own_references_to
571
+ own_references_to
577
572
  end
578
573
  end
579
574
  end
@@ -1287,7 +1282,7 @@ module GraphQL
1287
1282
 
1288
1283
  # Execute a query on itself.
1289
1284
  # @see {Query#initialize} for arguments.
1290
- # @return [Hash] query result, ready to be serialized as JSON
1285
+ # @return [GraphQL::Query::Result] query result, ready to be serialized as JSON
1291
1286
  def execute(query_str = nil, **kwargs)
1292
1287
  if query_str
1293
1288
  kwargs[:query] = query_str
@@ -1327,7 +1322,7 @@ module GraphQL
1327
1322
  # @see {Execution::Multiplex#run_all} for multiplex keyword arguments
1328
1323
  # @param queries [Array<Hash>] Keyword arguments for each query
1329
1324
  # @param context [Hash] Multiplex-level context
1330
- # @return [Array<Hash>] One result for each query in the input
1325
+ # @return [Array<GraphQL::Query::Result>] One result for each query in the input
1331
1326
  def multiplex(queries, **kwargs)
1332
1327
  GraphQL::Execution::Interpreter.run_all(self, queries, **kwargs)
1333
1328
  end
@@ -1460,7 +1455,8 @@ module GraphQL
1460
1455
  own_union_memberships.merge!(addition.union_memberships)
1461
1456
 
1462
1457
  addition.references.each { |thing, pointers|
1463
- pointers.each { |pointer| references_to(thing, from: pointer) }
1458
+ prev_refs = own_references_to[thing] || []
1459
+ own_references_to[thing] = prev_refs | pointers.to_a
1464
1460
  }
1465
1461
 
1466
1462
  addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
@@ -1488,6 +1484,10 @@ module GraphQL
1488
1484
  @own_types ||= {}
1489
1485
  end
1490
1486
 
1487
+ def own_references_to
1488
+ @own_references_to ||= {}.tap(&:compare_by_identity)
1489
+ end
1490
+
1491
1491
  def non_introspection_types
1492
1492
  find_inherited_value(:non_introspection_types, EMPTY_HASH).merge(own_types)
1493
1493
  end
@@ -1501,7 +1501,7 @@ module GraphQL
1501
1501
  end
1502
1502
 
1503
1503
  def own_possible_types
1504
- @own_possible_types ||= {}
1504
+ @own_possible_types ||= {}.tap(&:compare_by_identity)
1505
1505
  end
1506
1506
 
1507
1507
  def own_union_memberships
@@ -1529,15 +1529,15 @@ module GraphQL
1529
1529
  end
1530
1530
 
1531
1531
  # This is overridden in subclasses to check the inheritance chain
1532
- def get_references_to(type_name)
1533
- @own_references_to[type_name]
1532
+ def get_references_to(type_defn)
1533
+ own_references_to[type_defn]
1534
1534
  end
1535
1535
  end
1536
1536
 
1537
1537
  module SubclassGetReferencesTo
1538
- def get_references_to(type_name)
1539
- own_refs = @own_references_to[type_name]
1540
- inherited_refs = superclass.references_to(type_name)
1538
+ def get_references_to(type_defn)
1539
+ own_refs = own_references_to[type_defn]
1540
+ inherited_refs = superclass.references_to(type_defn)
1541
1541
  if inherited_refs&.any?
1542
1542
  if own_refs&.any?
1543
1543
  own_refs + inherited_refs
@@ -396,7 +396,7 @@ module GraphQL
396
396
  end
397
397
 
398
398
  # Given two list of parents, find out if they are mutually exclusive
399
- # In this context, `parents` represends the "self scope" of the field,
399
+ # In this context, `parents` represents the "self scope" of the field,
400
400
  # what types may be found at this point in the query.
401
401
  def mutually_exclusive?(parents1, parents2)
402
402
  if parents1.empty? || parents2.empty?
@@ -107,7 +107,7 @@ module GraphQL
107
107
  when 2
108
108
  true
109
109
  else
110
- raise ArgumentError, "#{@serializer} must repond to `.load` accepting one or two arguments"
110
+ raise ArgumentError, "#{@serializer} must respond to `.load` accepting one or two arguments"
111
111
  end
112
112
  @transmit_ns = namespace
113
113
  super
@@ -9,7 +9,7 @@ module GraphQL
9
9
  # Assign the result to `context.namespace(:subscriptions)[:subscription_broadcastable]`
10
10
  # @api private
11
11
  # @see Subscriptions#broadcastable? for a public API
12
- class BroadcastAnalyzer < GraphQL::Analysis::AST::Analyzer
12
+ class BroadcastAnalyzer < GraphQL::Analysis::Analyzer
13
13
  def initialize(subject)
14
14
  super
15
15
  @default_broadcastable = subject.schema.subscriptions.default_broadcastable
@@ -235,7 +235,7 @@ module GraphQL
235
235
  if !query.valid?
236
236
  raise "Invalid query: #{query.validation_errors.map(&:to_h).inspect}"
237
237
  end
238
- GraphQL::Analysis::AST.analyze_query(query, @schema.query_analyzers)
238
+ GraphQL::Analysis.analyze_query(query, @schema.query_analyzers)
239
239
  query.context.namespace(:subscriptions)[:subscription_broadcastable]
240
240
  end
241
241
 
@@ -16,7 +16,7 @@ module GraphQL
16
16
  @description = description
17
17
  end
18
18
 
19
- # Does this TypeKind have multiple possible implementors?
19
+ # Does this TypeKind have multiple possible implementers?
20
20
  # @deprecated Use `abstract?` instead of `resolves?`.
21
21
  def resolves?; @abstract; end
22
22
  # Is this TypeKind abstract?
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.3.4"
3
+ VERSION = "2.3.6"
4
4
  end
data/lib/graphql.rb CHANGED
@@ -6,14 +6,6 @@ require "singleton"
6
6
  require "forwardable"
7
7
 
8
8
  module GraphQL
9
- # forwards-compat for argument handling
10
- module Ruby2Keywords
11
- if RUBY_VERSION < "2.7"
12
- def ruby2_keywords(*)
13
- end
14
- end
15
- end
16
-
17
9
  class Error < StandardError
18
10
  end
19
11
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.4
4
+ version: 2.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-21 00:00:00.000000000 Z
11
+ date: 2024-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -306,14 +306,13 @@ files:
306
306
  - lib/generators/graphql/union_generator.rb
307
307
  - lib/graphql.rb
308
308
  - lib/graphql/analysis.rb
309
- - lib/graphql/analysis/ast.rb
310
- - lib/graphql/analysis/ast/analyzer.rb
311
- - lib/graphql/analysis/ast/field_usage.rb
312
- - lib/graphql/analysis/ast/max_query_complexity.rb
313
- - lib/graphql/analysis/ast/max_query_depth.rb
314
- - lib/graphql/analysis/ast/query_complexity.rb
315
- - lib/graphql/analysis/ast/query_depth.rb
316
- - lib/graphql/analysis/ast/visitor.rb
309
+ - lib/graphql/analysis/analyzer.rb
310
+ - lib/graphql/analysis/field_usage.rb
311
+ - lib/graphql/analysis/max_query_complexity.rb
312
+ - lib/graphql/analysis/max_query_depth.rb
313
+ - lib/graphql/analysis/query_complexity.rb
314
+ - lib/graphql/analysis/query_depth.rb
315
+ - lib/graphql/analysis/visitor.rb
317
316
  - lib/graphql/analysis_error.rb
318
317
  - lib/graphql/backtrace.rb
319
318
  - lib/graphql/backtrace/inspect_result.rb
@@ -645,7 +644,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
645
644
  - !ruby/object:Gem::Version
646
645
  version: '0'
647
646
  requirements: []
648
- rubygems_version: 3.5.3
647
+ rubygems_version: 3.5.12
649
648
  signing_key:
650
649
  specification_version: 4
651
650
  summary: A GraphQL language and runtime for Ruby
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Analysis
4
- module AST
5
- # Query analyzer for query ASTs. Query analyzers respond to visitor style methods
6
- # but are prefixed by `enter` and `leave`.
7
- #
8
- # When an analyzer is initialized with a Multiplex, you can always get the current query from
9
- # `visitor.query` in the visit methods.
10
- #
11
- # @param [GraphQL::Query, GraphQL::Execution::Multiplex] The query or multiplex to analyze
12
- class Analyzer
13
- def initialize(subject)
14
- @subject = subject
15
-
16
- if subject.is_a?(GraphQL::Query)
17
- @query = subject
18
- @multiplex = nil
19
- else
20
- @multiplex = subject
21
- @query = nil
22
- end
23
- end
24
-
25
- # Analyzer hook to decide at analysis time whether a query should
26
- # be analyzed or not.
27
- # @return [Boolean] If the query should be analyzed or not
28
- def analyze?
29
- true
30
- end
31
-
32
- # Analyzer hook to decide at analysis time whether analysis
33
- # requires a visitor pass; can be disabled for precomputed results.
34
- # @return [Boolean] If analysis requires visitation or not
35
- def visit?
36
- true
37
- end
38
-
39
- # The result for this analyzer. Returning {GraphQL::AnalysisError} results
40
- # in a query error.
41
- # @return [Any] The analyzer result
42
- def result
43
- raise GraphQL::RequiredImplementationMissingError
44
- end
45
-
46
- class << self
47
- private
48
-
49
- def build_visitor_hooks(member_name)
50
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
51
- def on_enter_#{member_name}(node, parent, visitor)
52
- end
53
-
54
- def on_leave_#{member_name}(node, parent, visitor)
55
- end
56
- EOS
57
- end
58
- end
59
-
60
- build_visitor_hooks :argument
61
- build_visitor_hooks :directive
62
- build_visitor_hooks :document
63
- build_visitor_hooks :enum
64
- build_visitor_hooks :field
65
- build_visitor_hooks :fragment_spread
66
- build_visitor_hooks :inline_fragment
67
- build_visitor_hooks :input_object
68
- build_visitor_hooks :list_type
69
- build_visitor_hooks :non_null_type
70
- build_visitor_hooks :null_value
71
- build_visitor_hooks :operation_definition
72
- build_visitor_hooks :type_name
73
- build_visitor_hooks :variable_definition
74
- build_visitor_hooks :variable_identifier
75
- build_visitor_hooks :abstract_node
76
-
77
- protected
78
-
79
- # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
80
- attr_reader :subject
81
-
82
- # @return [GraphQL::Query, nil] `nil` if this analyzer is visiting a multiplex
83
- # (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
84
- attr_reader :query
85
-
86
- # @return [GraphQL::Execution::Multiplex, nil] `nil` if this analyzer is visiting a query
87
- attr_reader :multiplex
88
- end
89
- end
90
- end
91
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Analysis
4
- module AST
5
- class FieldUsage < Analyzer
6
- def initialize(query)
7
- super
8
- @used_fields = Set.new
9
- @used_deprecated_fields = Set.new
10
- @used_deprecated_arguments = Set.new
11
- @used_deprecated_enum_values = Set.new
12
- end
13
-
14
- def on_leave_field(node, parent, visitor)
15
- field_defn = visitor.field_definition
16
- field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
17
- @used_fields << field
18
- @used_deprecated_fields << field if field_defn.deprecation_reason
19
- arguments = visitor.query.arguments_for(node, field_defn)
20
- # If there was an error when preparing this argument object,
21
- # then this might be an error or something:
22
- if arguments.respond_to?(:argument_values)
23
- extract_deprecated_arguments(arguments.argument_values)
24
- end
25
- end
26
-
27
- def result
28
- {
29
- used_fields: @used_fields.to_a,
30
- used_deprecated_fields: @used_deprecated_fields.to_a,
31
- used_deprecated_arguments: @used_deprecated_arguments.to_a,
32
- used_deprecated_enum_values: @used_deprecated_enum_values.to_a,
33
- }
34
- end
35
-
36
- private
37
-
38
- def extract_deprecated_arguments(argument_values)
39
- argument_values.each_pair do |_argument_name, argument|
40
- if argument.definition.deprecation_reason
41
- @used_deprecated_arguments << argument.definition.path
42
- end
43
-
44
- arg_val = argument.value
45
-
46
- next if arg_val.nil?
47
-
48
- argument_type = argument.definition.type
49
- if argument_type.non_null?
50
- argument_type = argument_type.of_type
51
- end
52
-
53
- if argument_type.kind.input_object?
54
- extract_deprecated_arguments(argument.original_value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
55
- elsif argument_type.kind.enum?
56
- extract_deprecated_enum_value(argument_type, arg_val)
57
- elsif argument_type.list?
58
- inner_type = argument_type.unwrap
59
- case inner_type.kind
60
- when TypeKinds::INPUT_OBJECT
61
- argument.original_value.each do |value|
62
- extract_deprecated_arguments(value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
63
- end
64
- when TypeKinds::ENUM
65
- arg_val.each do |value|
66
- extract_deprecated_enum_value(inner_type, value)
67
- end
68
- else
69
- # Not a kind of input that we track
70
- end
71
- end
72
- end
73
- end
74
-
75
- def extract_deprecated_enum_value(enum_type, value)
76
- enum_value = @query.warden.enum_values(enum_type).find { |ev| ev.value == value }
77
- if enum_value&.deprecation_reason
78
- @used_deprecated_enum_values << enum_value.path
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Analysis
4
- module AST
5
- # Used under the hood to implement complexity validation,
6
- # see {Schema#max_complexity} and {Query#max_complexity}
7
- class MaxQueryComplexity < QueryComplexity
8
- def result
9
- return if subject.max_complexity.nil?
10
-
11
- total_complexity = max_possible_complexity
12
-
13
- if total_complexity > subject.max_complexity
14
- GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{subject.max_complexity}")
15
- else
16
- nil
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Analysis
4
- module AST
5
- class MaxQueryDepth < QueryDepth
6
- def result
7
- configured_max_depth = if query
8
- query.max_depth
9
- else
10
- multiplex.schema.max_depth
11
- end
12
-
13
- if configured_max_depth && @max_depth > configured_max_depth
14
- GraphQL::AnalysisError.new("Query has depth of #{@max_depth}, which exceeds max depth of #{configured_max_depth}")
15
- else
16
- nil
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end