graphql 2.1.12 → 2.2.0

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.

@@ -337,14 +337,16 @@ module GraphQL
337
337
  print_string("union ")
338
338
  print_string(union_type.name)
339
339
  print_directives(union_type.directives)
340
- print_string(" = ")
341
- i = 0
342
- union_type.types.each do |t|
343
- if i > 0
344
- print_string(" | ")
340
+ if union_type.types.any?
341
+ print_string(" = ")
342
+ i = 0
343
+ union_type.types.each do |t|
344
+ if i > 0
345
+ print_string(" | ")
346
+ end
347
+ print_string(t.name)
348
+ i += 1
345
349
  end
346
- print_string(t.name)
347
- i += 1
348
350
  end
349
351
  end
350
352
 
@@ -353,12 +355,14 @@ module GraphQL
353
355
  print_string("enum ")
354
356
  print_string(enum_type.name)
355
357
  print_directives(enum_type.directives)
356
- print_string(" {\n")
357
- enum_type.values.each.with_index do |value, i|
358
- print_description(value, indent: " ", first_in_block: i == 0)
359
- print_enum_value_definition(value)
358
+ if enum_type.values.any?
359
+ print_string(" {\n")
360
+ enum_type.values.each.with_index do |value, i|
361
+ print_description(value, indent: " ", first_in_block: i == 0)
362
+ print_enum_value_definition(value)
363
+ end
364
+ print_string("}")
360
365
  end
361
- print_string("}")
362
366
  end
363
367
 
364
368
  def print_enum_value_definition(enum_value)
@@ -69,11 +69,7 @@ module GraphQL
69
69
  end
70
70
  elsif child_class < GraphQL::Schema::Object
71
71
  # This is being included into an object type, make sure it's using `implements(...)`
72
- backtrace_line = caller_locations(0, 10).find do |location|
73
- location.base_label == "implements" &&
74
- location.path.end_with?("schema/member/has_interfaces.rb")
75
- end
76
-
72
+ backtrace_line = caller(0, 10).find { |line| line.include?("schema/member/has_interfaces.rb") && line.include?("in `implements'")}
77
73
  if !backtrace_line
78
74
  raise "Attach interfaces using `implements(#{self})`, not `include(#{self})`"
79
75
  end
@@ -384,6 +384,11 @@ module GraphQL
384
384
  (superclass.respond_to?(:get_type) ? superclass.get_type(type_name, context) : nil)
385
385
  end
386
386
 
387
+ # @return [Boolean] Does this schema have _any_ definition for a type named `type_name`, regardless of visibility?
388
+ def has_defined_type?(type_name)
389
+ own_types.key?(type_name) || introspection_system.types.key?(type_name) || (superclass.respond_to?(:has_defined_type?) ? superclass.has_defined_type?(type_name) : false)
390
+ end
391
+
387
392
  # @api private
388
393
  attr_writer :connections
389
394
 
@@ -939,11 +944,7 @@ module GraphQL
939
944
  end
940
945
 
941
946
  def resolve_type(type, obj, ctx)
942
- if type.kind.object?
943
- type
944
- else
945
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})"
946
- end
947
+ 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})"
947
948
  end
948
949
  # rubocop:enable Lint/DuplicateMethods
949
950
 
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Testing
4
+ module Helpers
5
+ # @param schema_class [Class<GraphQL::Schema>]
6
+ # @return [Module] A helpers module which always uses the given schema
7
+ def self.for(schema_class)
8
+ Module.new do
9
+ include SchemaHelpers
10
+ @@schema_class_for_helpers = schema_class
11
+ end
12
+ end
13
+
14
+ class Error < GraphQL::Error
15
+ end
16
+
17
+ class TypeNotVisibleError < Error
18
+ def initialize(type_name:)
19
+ message = "`#{type_name}` should be `visible?` this field resolution and `context`, but it was not"
20
+ super(message)
21
+ end
22
+ end
23
+
24
+ class FieldNotVisibleError < Error
25
+ def initialize(type_name:, field_name:)
26
+ message = "`#{type_name}.#{field_name}` should be `visible?` for this resolution, but it was not"
27
+ super(message)
28
+ end
29
+ end
30
+
31
+ class TypeNotDefinedError < Error
32
+ def initialize(type_name:)
33
+ message = "No type named `#{type_name}` is defined; choose another type name or define this type."
34
+ super(message)
35
+ end
36
+ end
37
+
38
+ class FieldNotDefinedError < Error
39
+ def initialize(type_name:, field_name:)
40
+ message = "`#{type_name}` has no field named `#{field_name}`; pick another name or define this field."
41
+ super(message)
42
+ end
43
+ end
44
+
45
+ def run_graphql_field(schema, field_path, object, arguments: {}, context: {})
46
+ type_name, *field_names = field_path.split(".")
47
+ dummy_query = GraphQL::Query.new(schema, context: context)
48
+ query_context = dummy_query.context
49
+ object_type = dummy_query.get_type(type_name) # rubocop:disable Development/ContextIsPassedCop
50
+ if object_type
51
+ graphql_result = object
52
+ field_names.each do |field_name|
53
+ inner_object = graphql_result
54
+ graphql_result = object_type.wrap(inner_object, query_context)
55
+ if graphql_result.nil?
56
+ return nil
57
+ end
58
+ visible_field = dummy_query.get_field(object_type, field_name)
59
+ if visible_field
60
+ dummy_query.context.dataloader.run_isolated {
61
+ field_args = visible_field.coerce_arguments(graphql_result, arguments, query_context)
62
+ field_args = schema.sync_lazy(field_args)
63
+ graphql_result = visible_field.resolve(graphql_result, field_args.keyword_arguments, query_context)
64
+ graphql_result = schema.sync_lazy(graphql_result)
65
+ }
66
+ object_type = visible_field.type.unwrap
67
+ elsif object_type.all_field_definitions.any? { |f| f.graphql_name == field_name }
68
+ raise FieldNotVisibleError.new(field_name: field_name, type_name: type_name)
69
+ else
70
+ raise FieldNotDefinedError.new(type_name: type_name, field_name: field_name)
71
+ end
72
+ end
73
+ graphql_result
74
+ elsif schema.has_defined_type?(type_name)
75
+ raise TypeNotVisibleError.new(type_name: type_name)
76
+ else
77
+ raise TypeNotDefinedError.new(type_name: type_name)
78
+ end
79
+ end
80
+
81
+ def with_resolution_context(schema, type:, object:, context:{})
82
+ resolution_context = ResolutionAssertionContext.new(
83
+ self,
84
+ schema: schema,
85
+ type_name: type,
86
+ object: object,
87
+ context: context
88
+ )
89
+ yield(resolution_context)
90
+ end
91
+
92
+ class ResolutionAssertionContext
93
+ def initialize(test, type_name:, object:, schema:, context:)
94
+ @test = test
95
+ @type_name = type_name
96
+ @object = object
97
+ @schema = schema
98
+ @context = context
99
+ end
100
+
101
+
102
+ def run_graphql_field(field_name, arguments: {})
103
+ if @schema
104
+ @test.run_graphql_field(@schema, "#{@type_name}.#{field_name}", @object, arguments: arguments, context: @context)
105
+ else
106
+ @test.run_graphql_field("#{@type_name}.#{field_name}", @object, arguments: arguments, context: @context)
107
+ end
108
+ end
109
+ end
110
+
111
+ module SchemaHelpers
112
+ include Helpers
113
+
114
+ def run_graphql_field(field_path, object, arguments: {}, context: {})
115
+ super(@@schema_class_for_helpers, field_path, object, arguments: arguments, context: context)
116
+ end
117
+
118
+ def with_resolution_context(*args, **kwargs, &block)
119
+ # schema will be added later
120
+ super(nil, *args, **kwargs, &block)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require "graphql/testing/helpers"
@@ -3,18 +3,20 @@
3
3
  module GraphQL
4
4
  module Tracing
5
5
  module DataDogTrace
6
- # @param tracer [#trace] Deprecated
7
6
  # @param analytics_enabled [Boolean] Deprecated
8
7
  # @param analytics_sample_rate [Float] Deprecated
9
- def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: nil, **rest)
8
+ def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0, service: "ruby-graphql", **rest)
10
9
  if tracer.nil?
11
10
  tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
12
11
  end
13
12
  @tracer = tracer
14
13
 
15
- @analytics_enabled = analytics_enabled
16
- @analytics_sample_rate = analytics_sample_rate
14
+ analytics_available = defined?(Datadog::Contrib::Analytics) \
15
+ && Datadog::Contrib::Analytics.respond_to?(:enabled?) \
16
+ && Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
17
17
 
18
+ @analytics_enabled = analytics_available && Datadog::Contrib::Analytics.enabled?(analytics_enabled)
19
+ @analytics_sample_rate = analytics_sample_rate
18
20
  @service_name = service
19
21
  @has_prepare_span = respond_to?(:prepare_span)
20
22
  super
@@ -32,9 +34,12 @@ module GraphQL
32
34
  }.each do |trace_method, trace_key|
33
35
  module_eval <<-RUBY, __FILE__, __LINE__
34
36
  def #{trace_method}(**data)
35
- @tracer.trace("#{trace_key}", service: @service_name, type: 'custom') do |span|
36
- span.set_tag('component', 'graphql')
37
- span.set_tag('operation', '#{trace_method}')
37
+ @tracer.trace("#{trace_key}", service: @service_name) do |span|
38
+ span.span_type = 'custom'
39
+ if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
40
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
41
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, '#{trace_method}')
42
+ end
38
43
 
39
44
  #{
40
45
  if trace_method == 'execute_multiplex'
@@ -49,8 +54,10 @@ module GraphQL
49
54
  end
50
55
  span.resource = resource if resource
51
56
 
52
- # [Deprecated] will be removed in the future
53
- span.set_metric('_dd1.sr.eausr', @analytics_sample_rate) if @analytics_enabled
57
+ # For top span of query, set the analytics sample rate tag, if available.
58
+ if @analytics_enabled
59
+ Datadog::Contrib::Analytics.set_sample_rate(span, @analytics_sample_rate)
60
+ end
54
61
  RUBY
55
62
  elsif trace_method == 'execute_query'
56
63
  <<-RUBY
@@ -82,10 +89,12 @@ module GraphQL
82
89
  nil
83
90
  end
84
91
  if platform_key && trace_field
85
- @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
86
- span.set_tag('component', 'graphql')
87
- span.set_tag('operation', span_key)
88
-
92
+ @tracer.trace(platform_key, service: @service_name) do |span|
93
+ span.span_type = 'custom'
94
+ if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
95
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
96
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
97
+ end
89
98
  if @has_prepare_span
90
99
  prepare_span_data = { query: query, field: field, ast_node: ast_node, arguments: arguments, object: object }
91
100
  prepare_span(span_key, prepare_span_data, span)
@@ -116,10 +125,12 @@ module GraphQL
116
125
 
117
126
  def authorized_span(span_key, object, type, query)
118
127
  platform_key = @platform_key_cache[DataDogTrace].platform_authorized_key_cache[type]
119
- @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
120
- span.set_tag('component', 'graphql')
121
- span.set_tag('operation', span_key)
122
-
128
+ @tracer.trace(platform_key, service: @service_name) do |span|
129
+ span.span_type = 'custom'
130
+ if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
131
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
132
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
133
+ end
123
134
  if @has_prepare_span
124
135
  prepare_span(span_key, {object: object, type: type, query: query}, span)
125
136
  end
@@ -147,10 +158,12 @@ module GraphQL
147
158
 
148
159
  def resolve_type_span(span_key, object, type, query)
149
160
  platform_key = @platform_key_cache[DataDogTrace].platform_resolve_type_key_cache[type]
150
- @tracer.trace(platform_key, service: @service_name, type: 'custom') do |span|
151
- span.set_tag('component', 'graphql')
152
- span.set_tag('operation', span_key)
153
-
161
+ @tracer.trace(platform_key, service: @service_name) do |span|
162
+ span.span_type = 'custom'
163
+ if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
164
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
165
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, span_key)
166
+ end
154
167
  if @has_prepare_span
155
168
  prepare_span(span_key, {object: object, type: type, query: query}, span)
156
169
  end
@@ -15,9 +15,12 @@ module GraphQL
15
15
  }
16
16
 
17
17
  def platform_trace(platform_key, key, data)
18
- tracer.trace(platform_key, service: options[:service], type: 'custom') do |span|
19
- span.set_tag('component', 'graphql')
20
- span.set_tag('operation', key)
18
+ tracer.trace(platform_key, service: service_name) do |span|
19
+ span.span_type = 'custom'
20
+ if defined?(Datadog::Tracing::Metadata::Ext) # Introduced in ddtrace 1.0
21
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_COMPONENT, 'graphql')
22
+ span.set_tag(Datadog::Tracing::Metadata::Ext::TAG_OPERATION, key)
23
+ end
21
24
 
22
25
  if key == 'execute_multiplex'
23
26
  operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
@@ -30,8 +33,10 @@ module GraphQL
30
33
  end
31
34
  span.resource = resource if resource
32
35
 
33
- # [Deprecated] will be removed in the future
34
- span.set_metric('_dd1.sr.eausr', analytics_sample_rate) if analytics_enabled?
36
+ # For top span of query, set the analytics sample rate tag, if available.
37
+ if analytics_enabled?
38
+ Datadog::Contrib::Analytics.set_sample_rate(span, analytics_sample_rate)
39
+ end
35
40
  end
36
41
 
37
42
  if key == 'execute_query'
@@ -46,6 +51,10 @@ module GraphQL
46
51
  end
47
52
  end
48
53
 
54
+ def service_name
55
+ options.fetch(:service, 'ruby-graphql')
56
+ end
57
+
49
58
  # Implement this method in a subclass to apply custom tags to datadog spans
50
59
  # @param key [String] The event being traced
51
60
  # @param data [Hash] The runtime data for this event (@see GraphQL::Tracing for keys for each event)
@@ -56,13 +65,18 @@ module GraphQL
56
65
  def tracer
57
66
  default_tracer = defined?(Datadog::Tracing) ? Datadog::Tracing : Datadog.tracer
58
67
 
59
- # [Deprecated] options[:tracer] will be removed in the future
60
68
  options.fetch(:tracer, default_tracer)
61
69
  end
62
70
 
71
+ def analytics_available?
72
+ defined?(Datadog::Contrib::Analytics) \
73
+ && Datadog::Contrib::Analytics.respond_to?(:enabled?) \
74
+ && Datadog::Contrib::Analytics.respond_to?(:set_sample_rate)
75
+ end
76
+
63
77
  def analytics_enabled?
64
78
  # [Deprecated] options[:analytics_enabled] will be removed in the future
65
- options.fetch(:analytics_enabled, false)
79
+ analytics_available? && Datadog::Contrib::Analytics.enabled?(options.fetch(:analytics_enabled, false))
66
80
  end
67
81
 
68
82
  def analytics_sample_rate
@@ -15,6 +15,7 @@ module GraphQL
15
15
  @query = query
16
16
  end
17
17
 
18
+ # The Ruby parser doesn't call this method (`graphql/c_parser` does.)
18
19
  def lex(query_string:)
19
20
  yield
20
21
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.1.12"
3
+ VERSION = "2.2.0"
4
4
  end
data/lib/graphql.rb CHANGED
@@ -121,3 +121,4 @@ require "graphql/unauthorized_error"
121
121
  require "graphql/unauthorized_field_error"
122
122
  require "graphql/load_application_object_failed_error"
123
123
  require "graphql/deprecation"
124
+ require "graphql/testing"
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.1.12
4
+ version: 2.2.0
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-02-28 00:00:00.000000000 Z
11
+ date: 2023-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: racc
@@ -70,44 +70,44 @@ dependencies:
70
70
  name: minitest
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 5.9.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 5.9.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: minitest-focus
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '1.1'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '1.1'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: minitest-reporters
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '1.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '1.0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rake
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +309,7 @@ files:
309
309
  - lib/graphql/backtrace/tracer.rb
310
310
  - lib/graphql/coercion_error.rb
311
311
  - lib/graphql/dataloader.rb
312
+ - lib/graphql/dataloader/async_dataloader.rb
312
313
  - lib/graphql/dataloader/null_dataloader.rb
313
314
  - lib/graphql/dataloader/request.rb
314
315
  - lib/graphql/dataloader/request_all.rb
@@ -360,7 +361,6 @@ files:
360
361
  - lib/graphql/language/lexer.rb
361
362
  - lib/graphql/language/nodes.rb
362
363
  - lib/graphql/language/parser.rb
363
- - lib/graphql/language/parser.y
364
364
  - lib/graphql/language/printer.rb
365
365
  - lib/graphql/language/sanitized_printer.rb
366
366
  - lib/graphql/language/static_visitor.rb
@@ -553,6 +553,8 @@ files:
553
553
  - lib/graphql/subscriptions/event.rb
554
554
  - lib/graphql/subscriptions/instrumentation.rb
555
555
  - lib/graphql/subscriptions/serialize.rb
556
+ - lib/graphql/testing.rb
557
+ - lib/graphql/testing/helpers.rb
556
558
  - lib/graphql/tracing.rb
557
559
  - lib/graphql/tracing/active_support_notifications_trace.rb
558
560
  - lib/graphql/tracing/active_support_notifications_tracing.rb
@@ -629,7 +631,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
629
631
  - !ruby/object:Gem::Version
630
632
  version: '0'
631
633
  requirements: []
632
- rubygems_version: 3.5.3
634
+ rubygems_version: 3.4.10
633
635
  signing_key:
634
636
  specification_version: 4
635
637
  summary: A GraphQL language and runtime for Ruby