graphql 2.3.4 → 2.3.6

Sign up to get free protection for your applications and to get access to all the features.
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