graphql 2.0.16 → 2.0.18

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/ast/visitor.rb +42 -35
  3. data/lib/graphql/analysis/ast.rb +2 -2
  4. data/lib/graphql/backtrace/tracer.rb +1 -1
  5. data/lib/graphql/execution/interpreter/resolve.rb +19 -0
  6. data/lib/graphql/execution/interpreter/runtime.rb +106 -88
  7. data/lib/graphql/execution/interpreter.rb +14 -9
  8. data/lib/graphql/execution/lazy.rb +6 -12
  9. data/lib/graphql/execution/multiplex.rb +2 -1
  10. data/lib/graphql/graphql_ext.bundle +0 -0
  11. data/lib/graphql/introspection/directive_type.rb +2 -2
  12. data/lib/graphql/introspection/field_type.rb +1 -1
  13. data/lib/graphql/introspection/schema_type.rb +2 -2
  14. data/lib/graphql/introspection/type_type.rb +5 -5
  15. data/lib/graphql/language/lexer.rb +216 -1505
  16. data/lib/graphql/language/lexer.ri +744 -0
  17. data/lib/graphql/language/nodes.rb +39 -31
  18. data/lib/graphql/language/parser.rb +9 -9
  19. data/lib/graphql/language/parser.y +9 -9
  20. data/lib/graphql/language/visitor.rb +191 -83
  21. data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
  22. data/lib/graphql/query/context.rb +45 -11
  23. data/lib/graphql/query.rb +15 -2
  24. data/lib/graphql/schema/argument.rb +0 -4
  25. data/lib/graphql/schema/directive.rb +12 -2
  26. data/lib/graphql/schema/enum.rb +24 -17
  27. data/lib/graphql/schema/enum_value.rb +5 -3
  28. data/lib/graphql/schema/field.rb +53 -45
  29. data/lib/graphql/schema/interface.rb +0 -10
  30. data/lib/graphql/schema/late_bound_type.rb +2 -0
  31. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -14
  32. data/lib/graphql/schema/member/has_arguments.rb +104 -57
  33. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  34. data/lib/graphql/schema/member/has_fields.rb +14 -2
  35. data/lib/graphql/schema/member/has_interfaces.rb +49 -8
  36. data/lib/graphql/schema/member/has_validators.rb +31 -5
  37. data/lib/graphql/schema/member/type_system_helpers.rb +17 -0
  38. data/lib/graphql/schema/object.rb +2 -4
  39. data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
  40. data/lib/graphql/schema/timeout.rb +23 -27
  41. data/lib/graphql/schema/warden.rb +26 -4
  42. data/lib/graphql/schema.rb +37 -19
  43. data/lib/graphql/static_validation/literal_validator.rb +15 -1
  44. data/lib/graphql/static_validation/validator.rb +1 -1
  45. data/lib/graphql/subscriptions/event.rb +2 -7
  46. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  47. data/lib/graphql/tracing/appoptics_trace.rb +231 -0
  48. data/lib/graphql/tracing/appsignal_trace.rb +66 -0
  49. data/lib/graphql/tracing/data_dog_trace.rb +148 -0
  50. data/lib/graphql/tracing/new_relic_trace.rb +75 -0
  51. data/lib/graphql/tracing/notifications_trace.rb +41 -0
  52. data/lib/graphql/tracing/platform_trace.rb +107 -0
  53. data/lib/graphql/tracing/platform_tracing.rb +15 -3
  54. data/lib/graphql/tracing/prometheus_trace.rb +89 -0
  55. data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
  56. data/lib/graphql/tracing/scout_trace.rb +72 -0
  57. data/lib/graphql/tracing/statsd_trace.rb +56 -0
  58. data/lib/graphql/tracing.rb +136 -39
  59. data/lib/graphql/type_kinds.rb +6 -3
  60. data/lib/graphql/types/relay/connection_behaviors.rb +0 -4
  61. data/lib/graphql/types/relay/edge_behaviors.rb +0 -4
  62. data/lib/graphql/types/string.rb +1 -1
  63. data/lib/graphql/version.rb +1 -1
  64. data/lib/graphql.rb +7 -8
  65. metadata +15 -4
  66. data/lib/graphql/language/lexer.rl +0 -280
data/lib/graphql/query.rb CHANGED
@@ -95,12 +95,20 @@ module GraphQL
95
95
  @fragments = nil
96
96
  @operations = nil
97
97
  @validate = validate
98
- @tracers = schema.tracers + (context ? context.fetch(:tracers, []) : [])
98
+ context_tracers = (context ? context.fetch(:tracers, []) : [])
99
+ @tracers = schema.tracers + context_tracers
100
+
99
101
  # Support `ctx[:backtrace] = true` for wrapping backtraces
100
102
  if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
103
+ context_tracers += [GraphQL::Backtrace::Tracer]
101
104
  @tracers << GraphQL::Backtrace::Tracer
102
105
  end
103
106
 
107
+ if context_tracers.any? && !(schema.trace_class <= GraphQL::Tracing::LegacyTrace)
108
+ raise ArgumentError, "context[:tracers] and context[:backtrace] are not supported without `tracer_class(GraphQL::Tracing::LegacyTrace)` in the schema configuration, please add it."
109
+ end
110
+
111
+
104
112
  @analysis_errors = []
105
113
  if variables.is_a?(String)
106
114
  raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
@@ -157,6 +165,11 @@ module GraphQL
157
165
 
158
166
  attr_accessor :multiplex
159
167
 
168
+ # @return [GraphQL::Tracing::Trace]
169
+ def current_trace
170
+ @current_trace ||= multiplex ? multiplex.current_trace : schema.new_trace(multiplex: multiplex, query: self)
171
+ end
172
+
160
173
  def subscription_update?
161
174
  @subscription_topic && subscription?
162
175
  end
@@ -362,7 +375,7 @@ module GraphQL
362
375
  parse_error = nil
363
376
  @document ||= begin
364
377
  if query_string
365
- GraphQL.parse(query_string, tracer: self)
378
+ GraphQL.parse(query_string, trace: self.current_trace)
366
379
  end
367
380
  rescue GraphQL::ParseError => err
368
381
  parse_error = err
@@ -149,10 +149,6 @@ module GraphQL
149
149
  true
150
150
  end
151
151
 
152
- def accessible?(context)
153
- true
154
- end
155
-
156
152
  def authorized?(obj, value, ctx)
157
153
  authorized_as_type?(obj, value, ctx, as_type: type)
158
154
  end
@@ -8,6 +8,7 @@ module GraphQL
8
8
  # - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
+ extend GraphQL::Schema::Member::HasArguments::HasDirectiveArguments
11
12
 
12
13
  class << self
13
14
  # Directives aren't types, they don't have kinds.
@@ -21,9 +22,9 @@ module GraphQL
21
22
  # but downcase the first letter.
22
23
  def default_graphql_name
23
24
  @default_graphql_name ||= begin
24
- camelized_name = super
25
+ camelized_name = super.dup
25
26
  camelized_name[0] = camelized_name[0].downcase
26
- camelized_name
27
+ -camelized_name
27
28
  end
28
29
  end
29
30
 
@@ -93,6 +94,15 @@ module GraphQL
93
94
  def repeatable(new_value)
94
95
  @repeatable = new_value
95
96
  end
97
+
98
+ private
99
+
100
+ def inherited(subclass)
101
+ super
102
+ subclass.class_eval do
103
+ @default_graphql_name ||= nil
104
+ end
105
+ end
96
106
  end
97
107
 
98
108
  # @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
@@ -1,24 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphQL
4
- # Extend this class to define GraphQL enums in your schema.
5
- #
6
- # By default, GraphQL enum values are translated into Ruby strings.
7
- # You can provide a custom value with the `value:` keyword.
8
- #
9
- # @example
10
- # # equivalent to
11
- # # enum PizzaTopping {
12
- # # MUSHROOMS
13
- # # ONIONS
14
- # # PEPPERS
15
- # # }
16
- # class PizzaTopping < GraphQL::Enum
17
- # value :MUSHROOMS
18
- # value :ONIONS
19
- # value :PEPPERS
20
- # end
21
4
  class Schema
5
+ # Extend this class to define GraphQL enums in your schema.
6
+ #
7
+ # By default, GraphQL enum values are translated into Ruby strings.
8
+ # You can provide a custom value with the `value:` keyword.
9
+ #
10
+ # @example
11
+ # # equivalent to
12
+ # # enum PizzaTopping {
13
+ # # MUSHROOMS
14
+ # # ONIONS
15
+ # # PEPPERS
16
+ # # }
17
+ # class PizzaTopping < GraphQL::Enum
18
+ # value :MUSHROOMS
19
+ # value :ONIONS
20
+ # value :PEPPERS
21
+ # end
22
22
  class Enum < GraphQL::Schema::Member
23
23
  extend GraphQL::Schema::Member::ValidatesInput
24
24
 
@@ -34,6 +34,13 @@ module GraphQL
34
34
  end
35
35
  end
36
36
 
37
+ class MissingValuesError < GraphQL::Error
38
+ def initialize(enum_type)
39
+ @enum_type = enum_type
40
+ super("Enum types require at least one value, but #{enum_type.graphql_name} didn't provide any for this query. Make sure at least one value is defined and visible for this query.")
41
+ end
42
+ end
43
+
37
44
  class << self
38
45
  # Define a value for this enum
39
46
  # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
@@ -25,16 +25,19 @@ module GraphQL
25
25
  include GraphQL::Schema::Member::HasDirectives
26
26
  include GraphQL::Schema::Member::HasDeprecationReason
27
27
 
28
+ UNDEFINED_VALUE = Object.new.freeze
29
+ private_constant :UNDEFINED_VALUE
30
+
28
31
  attr_reader :graphql_name
29
32
 
30
33
  # @return [Class] The enum type that owns this value
31
34
  attr_reader :owner
32
35
 
33
- def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: nil, deprecation_reason: nil, &block)
36
+ def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: UNDEFINED_VALUE, deprecation_reason: nil, &block)
34
37
  @graphql_name = graphql_name.to_s
35
38
  GraphQL::NameValidator.validate!(@graphql_name)
36
39
  @description = desc || description
37
- @value = value.nil? ? @graphql_name : value
40
+ @value = value === UNDEFINED_VALUE ? @graphql_name : value
38
41
  if deprecation_reason
39
42
  self.deprecation_reason = deprecation_reason
40
43
  end
@@ -70,7 +73,6 @@ module GraphQL
70
73
  end
71
74
 
72
75
  def visible?(_ctx); true; end
73
- def accessible?(_ctx); true; end
74
76
  def authorized?(_ctx); true; end
75
77
  end
76
78
  end
@@ -6,6 +6,7 @@ module GraphQL
6
6
  class Schema
7
7
  class Field
8
8
  include GraphQL::Schema::Member::HasArguments
9
+ include GraphQL::Schema::Member::HasArguments::FieldConfigured
9
10
  include GraphQL::Schema::Member::HasAstNode
10
11
  include GraphQL::Schema::Member::HasPath
11
12
  include GraphQL::Schema::Member::HasValidators
@@ -218,7 +219,7 @@ module GraphQL
218
219
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
219
220
  # @param validates [Array<Hash>] Configurations for validating this field
220
221
  # @fallback_value [Object] A fallback value if the method is not defined
221
- def initialize(type: nil, name: nil, owner: nil, null: nil, description: :not_given, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: :not_given, default_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
222
+ def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: :not_given, &definition_block)
222
223
  if name.nil?
223
224
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
224
225
  end
@@ -229,11 +230,13 @@ module GraphQL
229
230
  end
230
231
  @original_name = name
231
232
  name_s = -name.to_s
233
+
232
234
  @underscored_name = -Member::BuildType.underscore(name_s)
233
235
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
234
- if description != :not_given
235
- @description = description
236
- end
236
+
237
+ @description = description
238
+ @type = @owner_type = @own_validators = @own_directives = @own_arguments = nil # these will be prepared later if necessary
239
+
237
240
  self.deprecation_reason = deprecation_reason
238
241
 
239
242
  if method && hash_key && dig
@@ -255,6 +258,9 @@ module GraphQL
255
258
  if hash_key
256
259
  @hash_key = hash_key
257
260
  @hash_key_str = hash_key.to_s
261
+ else
262
+ @hash_key = NOT_CONFIGURED
263
+ @hash_key_str = NOT_CONFIGURED
258
264
  end
259
265
 
260
266
  @method_str = -method_name.to_s
@@ -270,15 +276,11 @@ module GraphQL
270
276
  true
271
277
  end
272
278
  @connection = connection
273
- @has_max_page_size = max_page_size != :not_given
274
- @max_page_size = max_page_size == :not_given ? nil : max_page_size
275
- @has_default_page_size = default_page_size != :not_given
276
- @default_page_size = default_page_size == :not_given ? nil : default_page_size
279
+ @max_page_size = max_page_size
280
+ @default_page_size = default_page_size
277
281
  @introspection = introspection
278
282
  @extras = extras
279
- if !broadcastable.nil?
280
- @broadcastable = broadcastable
281
- end
283
+ @broadcastable = broadcastable
282
284
  @resolver_class = resolver_class
283
285
  @scope = scope
284
286
  @trace = trace
@@ -353,7 +355,7 @@ module GraphQL
353
355
  # @return [Boolean, nil]
354
356
  # @see GraphQL::Subscriptions::BroadcastAnalyzer
355
357
  def broadcastable?
356
- if defined?(@broadcastable)
358
+ if !NOT_CONFIGURED.equal?(@broadcastable)
357
359
  @broadcastable
358
360
  elsif @resolver_class
359
361
  @resolver_class.broadcastable?
@@ -367,10 +369,10 @@ module GraphQL
367
369
  def description(text = nil)
368
370
  if text
369
371
  @description = text
370
- elsif defined?(@description)
372
+ elsif !NOT_CONFIGURED.equal?(@description)
371
373
  @description
372
374
  elsif @resolver_class
373
- @description || @resolver_class.description
375
+ @resolver_class.description
374
376
  else
375
377
  nil
376
378
  end
@@ -542,22 +544,34 @@ module GraphQL
542
544
 
543
545
  # @return [Boolean] True if this field's {#max_page_size} should override the schema default.
544
546
  def has_max_page_size?
545
- @has_max_page_size || (@resolver_class && @resolver_class.has_max_page_size?)
547
+ !NOT_CONFIGURED.equal?(@max_page_size) || (@resolver_class && @resolver_class.has_max_page_size?)
546
548
  end
547
549
 
548
550
  # @return [Integer, nil] Applied to connections if {#has_max_page_size?}
549
551
  def max_page_size
550
- @max_page_size || (@resolver_class && @resolver_class.max_page_size)
552
+ if !NOT_CONFIGURED.equal?(@max_page_size)
553
+ @max_page_size
554
+ elsif @resolver_class && @resolver_class.has_max_page_size?
555
+ @resolver_class.max_page_size
556
+ else
557
+ nil
558
+ end
551
559
  end
552
560
 
553
561
  # @return [Boolean] True if this field's {#default_page_size} should override the schema default.
554
562
  def has_default_page_size?
555
- @has_default_page_size || (@resolver_class && @resolver_class.has_default_page_size?)
563
+ !NOT_CONFIGURED.equal?(@default_page_size) || (@resolver_class && @resolver_class.has_default_page_size?)
556
564
  end
557
565
 
558
566
  # @return [Integer, nil] Applied to connections if {#has_default_page_size?}
559
567
  def default_page_size
560
- @default_page_size || (@resolver_class && @resolver_class.default_page_size)
568
+ if !NOT_CONFIGURED.equal?(@default_page_size)
569
+ @default_page_size
570
+ elsif @resolver_class && @resolver_class.has_default_page_size?
571
+ @resolver_class.default_page_size
572
+ else
573
+ nil
574
+ end
561
575
  end
562
576
 
563
577
  class MissingReturnTypeError < GraphQL::Error; end
@@ -589,14 +603,6 @@ module GraphQL
589
603
  end
590
604
  end
591
605
 
592
- def accessible?(context)
593
- if @resolver_class
594
- @resolver_class.accessible?(context)
595
- else
596
- true
597
- end
598
- end
599
-
600
606
  def authorized?(object, args, context)
601
607
  if @resolver_class
602
608
  # The resolver _instance_ will check itself during `resolve()`
@@ -610,27 +616,29 @@ module GraphQL
610
616
  arg_values = args
611
617
  using_arg_values = false
612
618
  end
613
- # Faster than `.any?`
614
- arguments(context).each_value do |arg|
615
- arg_key = arg.keyword
616
- if arg_values.key?(arg_key)
617
- arg_value = arg_values[arg_key]
618
- if using_arg_values
619
- if arg_value.default_used?
620
- # pass -- no auth required for default used
621
- next
622
- else
623
- application_arg_value = arg_value.value
624
- if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
625
- application_arg_value.keyword_arguments
619
+ if args.size > 0
620
+ args = context.warden.arguments(self)
621
+ args.each do |arg|
622
+ arg_key = arg.keyword
623
+ if arg_values.key?(arg_key)
624
+ arg_value = arg_values[arg_key]
625
+ if using_arg_values
626
+ if arg_value.default_used?
627
+ # pass -- no auth required for default used
628
+ next
629
+ else
630
+ application_arg_value = arg_value.value
631
+ if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
632
+ application_arg_value.keyword_arguments
633
+ end
626
634
  end
635
+ else
636
+ application_arg_value = arg_value
627
637
  end
628
- else
629
- application_arg_value = arg_value
630
- end
631
638
 
632
- if !arg.authorized?(object, application_arg_value, context)
633
- return false
639
+ if !arg.authorized?(object, application_arg_value, context)
640
+ return false
641
+ end
634
642
  end
635
643
  end
636
644
  end
@@ -665,7 +673,7 @@ module GraphQL
665
673
 
666
674
  inner_object = obj.object
667
675
 
668
- if defined?(@hash_key)
676
+ if !NOT_CONFIGURED.equal?(@hash_key)
669
677
  hash_value = if inner_object.is_a?(Hash)
670
678
  inner_object.key?(@hash_key) ? inner_object[@hash_key] : inner_object[@hash_key_str]
671
679
  elsif inner_object.respond_to?(:[])
@@ -28,16 +28,6 @@ module GraphQL
28
28
  true
29
29
  end
30
30
 
31
- # The interface is accessible if any of its possible types are accessible
32
- def accessible?(context)
33
- context.schema.possible_types(self, context).each do |type|
34
- if context.schema.accessible?(type, context)
35
- return true
36
- end
37
- end
38
- false
39
- end
40
-
41
31
  def type_membership_class(membership_class = nil)
42
32
  if membership_class
43
33
  @type_membership_class = membership_class
@@ -9,6 +9,8 @@ module GraphQL
9
9
  alias :graphql_name :name
10
10
  def initialize(local_name)
11
11
  @name = local_name
12
+ @to_non_null_type = nil
13
+ @to_list_type = nil
12
14
  end
13
15
 
14
16
  def unwrap
@@ -22,14 +22,10 @@ module GraphQL
22
22
  GraphQL::NameValidator.validate!(new_name)
23
23
  @graphql_name = new_name
24
24
  else
25
- overridden_graphql_name || default_graphql_name
25
+ @graphql_name ||= default_graphql_name
26
26
  end
27
27
  end
28
28
 
29
- def overridden_graphql_name
30
- defined?(@graphql_name) ? @graphql_name : nil
31
- end
32
-
33
29
  # Just a convenience method to point out that people should use graphql_name instead
34
30
  def name(new_name = nil)
35
31
  return super() if new_name.nil?
@@ -60,8 +56,8 @@ module GraphQL
60
56
  def inherited(child_class)
61
57
  child_class.introspection(introspection)
62
58
  child_class.description(description)
63
- if overridden_graphql_name
64
- child_class.graphql_name(overridden_graphql_name)
59
+ if defined?(@graphql_name) && (self.name.nil? || graphql_name != default_graphql_name)
60
+ child_class.graphql_name(graphql_name)
65
61
  end
66
62
  super
67
63
  end
@@ -79,7 +75,7 @@ module GraphQL
79
75
  end
80
76
 
81
77
  def introspection?
82
- introspection
78
+ !!@introspection
83
79
  end
84
80
 
85
81
  # The mutation this type was derived from, if it was derived from a mutation
@@ -102,21 +98,26 @@ module GraphQL
102
98
  def default_graphql_name
103
99
  @default_graphql_name ||= begin
104
100
  raise GraphQL::RequiredImplementationMissingError, 'Anonymous class should declare a `graphql_name`' if name.nil?
105
-
106
- name.split("::").last.sub(/Type\Z/, "")
107
- end
101
+ -name.split("::").last.sub(/Type\Z/, "") end
108
102
  end
109
103
 
110
104
  def visible?(context)
111
105
  true
112
106
  end
113
107
 
114
- def accessible?(context)
108
+ def authorized?(object, context)
115
109
  true
116
110
  end
117
111
 
118
- def authorized?(object, context)
119
- true
112
+ protected
113
+
114
+ attr_writer :default_graphql_name
115
+
116
+ private
117
+
118
+ def inherited(subclass)
119
+ super
120
+ subclass.default_graphql_name = nil
120
121
  end
121
122
  end
122
123
  end