graphql 2.0.6 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c31ecaae04f8ea6bca65c031a2a41d124d8a1e1dade016decfb047cae3f900ae
4
- data.tar.gz: af77a6ac50b38ca0d23a08da8f63fea1ca8f14ef11ccda56de55e678518380c1
3
+ metadata.gz: 8b34cec1ffb7358b467f2fb7c00134db084793d9eb1ebe22f38f351435607c9b
4
+ data.tar.gz: d15754c440968f51715c0a71f3c23ef1c5fd075793c0de11aae6477976b5aa14
5
5
  SHA512:
6
- metadata.gz: a6038fd4fe140b2196011e14cc61ba8b0ad72008b3cbe9d317bc87996fe6b42f7f289e188cd0d8c22a9d5f08c558d9774fa3533690355a16258b8276ad885e53
7
- data.tar.gz: ff7c5db4532240f9c11d7f3008441f27c5b3a6948cfe942eaf337711436fe9c678de913a849a2e627689a15a08bb2f90f9a345185945308669447ec31dd61027
6
+ metadata.gz: f2ef024af0f5e1e261fe7b998e27d664df5f92127ffb2874135a6d7b1662763a4e2661634dd46cc67dd624b9fc8291ce1bd3488a460566bc346f9cd6edc86b43
7
+ data.tar.gz: 635165d9129c2c49510fd481a2161cf425f91ff016bcdb28b8955d1c818d66885a6f7d90c5210e4433ada541d6e116b3137cb12dbdcc44c32229ac564d266b64
@@ -59,6 +59,13 @@ module GraphQL
59
59
  end
60
60
 
61
61
  if next_results.any?
62
+ # Any pending data loader jobs may populate the
63
+ # resutl arrays or result hashes accumulated in
64
+ # `next_results``. Run those **to completion**
65
+ # before continuing to resolve `next_results`.
66
+ # (Just `.append_job` doesn't work if any pending
67
+ # jobs require multiple passes.)
68
+ dataloader.run
62
69
  dataloader.append_job { resolve(next_results, dataloader) }
63
70
  end
64
71
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/execution/lazy/lazy_method_map"
3
- require "graphql/execution/lazy/resolve"
4
3
 
5
4
  module GraphQL
6
5
  module Execution
@@ -267,12 +267,16 @@ module GraphQL
267
267
  end
268
268
 
269
269
  def print_field_definitions(fields)
270
- out = " {\n".dup
271
- fields.each.with_index do |field, i|
272
- out << print_description(field, indent: ' ', first_in_block: i == 0)
273
- out << " #{print_field_definition(field)}\n"
270
+ if fields.empty?
271
+ ""
272
+ else
273
+ out = " {\n".dup
274
+ fields.each.with_index do |field, i|
275
+ out << print_description(field, indent: ' ', first_in_block: i == 0)
276
+ out << " #{print_field_definition(field)}\n"
277
+ end
278
+ out << "}"
274
279
  end
275
- out << "}"
276
280
  end
277
281
 
278
282
  def print_directives(directives)
@@ -248,7 +248,10 @@ module GraphQL
248
248
 
249
249
  method_name = method || name_s
250
250
  @dig_keys = dig
251
- @hash_key = hash_key
251
+ if hash_key
252
+ @hash_key = hash_key
253
+ @hash_key_str = hash_key.to_s
254
+ end
252
255
 
253
256
  @method_str = -method_name.to_s
254
257
  @method_sym = method_name.to_sym
@@ -639,8 +642,10 @@ module GraphQL
639
642
 
640
643
  inner_object = obj.object
641
644
 
642
- if @hash_key
643
- inner_object[@hash_key]
645
+ if defined?(@hash_key)
646
+ inner_object.fetch(@hash_key) {
647
+ inner_object[@hash_key_str]
648
+ }
644
649
  elsif @dig_keys
645
650
  inner_object.dig(*@dig_keys)
646
651
  elsif obj.respond_to?(resolver_method)
@@ -55,7 +55,9 @@ module GraphQL
55
55
  if visible_item.nil?
56
56
  visible_item = item
57
57
  else
58
- raise Schema::DuplicateNamesError, "Found two visible definitions for `#{item.path}`: #{visible_item.inspect}, #{item.inspect}"
58
+ raise DuplicateNamesError.new(
59
+ duplicated_name: item.path, duplicated_definition_1: visible_item.inspect, duplicated_definition_2: item.inspect
60
+ )
59
61
  end
60
62
  end
61
63
  end
@@ -362,7 +364,9 @@ module GraphQL
362
364
  if @reachable_type_set.add?(type)
363
365
  type_by_name = rt_hash[type.graphql_name] ||= type
364
366
  if type_by_name != type
365
- raise DuplicateNamesError, "Found two visible type definitions for `#{type.graphql_name}`: #{type.inspect}, #{type_by_name.inspect}"
367
+ raise DuplicateNamesError.new(
368
+ duplicated_name: type.graphql_name, duplicated_definition_1: type.inspect, duplicated_definition_2: type_by_name.inspect
369
+ )
366
370
  end
367
371
  if type.kind.input_object?
368
372
  # recurse into visible arguments
@@ -73,14 +73,16 @@ module GraphQL
73
73
  extend GraphQL::Schema::Member::HasAstNode
74
74
  extend GraphQL::Schema::FindInheritedValue
75
75
 
76
- class DuplicateTypeNamesError < GraphQL::Error
77
- def initialize(type_name:, first_definition:, second_definition:, path:)
78
- super("Multiple definitions for `#{type_name}`. Previously found #{first_definition.inspect} (#{first_definition.class}), then found #{second_definition.inspect} (#{second_definition.class}) at #{path.join(".")}")
76
+ class DuplicateNamesError < GraphQL::Error
77
+ attr_reader :duplicated_name
78
+ def initialize(duplicated_name:, duplicated_definition_1:, duplicated_definition_2:)
79
+ @duplicated_name = duplicated_name
80
+ super(
81
+ "Found two visible definitions for `#{duplicated_name}`: #{duplicated_definition_1}, #{duplicated_definition_2}"
82
+ )
79
83
  end
80
84
  end
81
85
 
82
- class DuplicateNamesError < GraphQL::Error; end
83
-
84
86
  class UnresolvedLateBoundTypeError < GraphQL::Error
85
87
  attr_reader :type
86
88
  def initialize(type:)
@@ -225,7 +227,9 @@ module GraphQL
225
227
  if visible_t.nil?
226
228
  visible_t = t
227
229
  else
228
- raise DuplicateNamesError, "Found two visible type definitions for `#{k}`: #{visible_t.inspect}, #{t.inspect}"
230
+ raise DuplicateNamesError.new(
231
+ duplicated_name: k, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
232
+ )
229
233
  end
230
234
  end
231
235
  end
@@ -252,7 +256,9 @@ module GraphQL
252
256
  if visible_t.nil?
253
257
  visible_t = t
254
258
  else
255
- raise DuplicateNamesError, "Found two visible type definitions for `#{type_name}`: #{visible_t.inspect}, #{t.inspect}"
259
+ raise DuplicateNamesError.new(
260
+ duplicated_name: type_name, duplicated_definition_1: visible_t.inspect, duplicated_definition_2: t.inspect
261
+ )
256
262
  end
257
263
  end
258
264
  end
@@ -977,7 +983,9 @@ module GraphQL
977
983
  if !defined?(@subscription_extension_added) && subscription && self.subscriptions
978
984
  @subscription_extension_added = true
979
985
  subscription.all_field_definitions.each do |field|
980
- field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
986
+ if !field.extensions.any? { |ext| ext.is_a?(Subscriptions::DefaultSubscriptionResolveExtension) }
987
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
988
+ end
981
989
  end
982
990
  end
983
991
  end
@@ -39,12 +39,14 @@ module GraphQL
39
39
  end
40
40
 
41
41
  # @param schema [Class] the GraphQL schema this manager belongs to
42
- def initialize(schema:, broadcast: false, default_broadcastable: false, **rest)
42
+ # @param validate_update [Boolean] If false, then validation is skipped when executing updates
43
+ def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest)
43
44
  if broadcast
44
45
  schema.query_analyzer(Subscriptions::BroadcastAnalyzer)
45
46
  end
46
47
  @default_broadcastable = default_broadcastable
47
48
  @schema = schema
49
+ @validate_update = validate_update
48
50
  end
49
51
 
50
52
  # @return [Boolean] Used when fields don't have `broadcastable:` explicitly set
@@ -117,14 +119,16 @@ module GraphQL
117
119
  variables = query_data.fetch(:variables)
118
120
  context = query_data.fetch(:context)
119
121
  operation_name = query_data.fetch(:operation_name)
120
- result = @schema.execute(
122
+ execute_options = {
121
123
  query: query_string,
122
124
  context: context,
123
125
  subscription_topic: event.topic,
124
126
  operation_name: operation_name,
125
127
  variables: variables,
126
128
  root_value: object,
127
- )
129
+ }
130
+ execute_options[:validate] = validate_update?(**execute_options)
131
+ result = @schema.execute(**execute_options)
128
132
  subscriptions_context = result.context.namespace(:subscriptions)
129
133
  if subscriptions_context[:no_update]
130
134
  result = nil
@@ -142,6 +146,14 @@ module GraphQL
142
146
  result
143
147
  end
144
148
 
149
+ # Define this method to customize whether to validate
150
+ # this subscription when executing an update.
151
+ #
152
+ # @return [Boolean] defaults to `true`, or false if `validate: false` is provided.
153
+ def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:)
154
+ @validate_update
155
+ end
156
+
145
157
  # Run the update query for this subscription and deliver it
146
158
  # @see {#execute_update}
147
159
  # @see {#deliver}
@@ -17,15 +17,21 @@ module GraphQL
17
17
  def platform_trace(platform_key, key, data)
18
18
  tracer.trace(platform_key, service: service_name) do |span|
19
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
20
24
 
21
25
  if key == 'execute_multiplex'
22
26
  operations = data[:multiplex].queries.map(&:selected_operation_name).join(', ')
23
- span.resource = if operations.empty?
27
+
28
+ resource = if operations.empty?
24
29
  first_query = data[:multiplex].queries.first
25
30
  fallback_transaction_name(first_query && first_query.context)
26
31
  else
27
32
  operations
28
33
  end
34
+ span.resource = resource if resource
29
35
 
30
36
  # For top span of query, set the analytics sample rate tag, if available.
31
37
  if analytics_enabled?
@@ -10,6 +10,8 @@ module GraphQL
10
10
  # so you can extend your own `BaseObject` instead of `GraphQL::Schema::Object`.
11
11
  #
12
12
  # @example Implementation a connection and edge
13
+ # class BaseObject < GraphQL::Schema::Object; end
14
+ #
13
15
  # # Given some object in your app ...
14
16
  # class Types::Post < BaseObject
15
17
  # end
@@ -20,14 +22,22 @@ module GraphQL
20
22
  #
21
23
  # # Then extend them for the object in your app
22
24
  # class Types::PostEdge < Types::BaseEdge
23
- # node_type(Types::Post)
25
+ # node_type Types::Post
24
26
  # end
27
+ #
25
28
  # class Types::PostConnection < Types::BaseConnection
26
- # edge_type(Types::PostEdge)
27
- # edges_nullable(true)
28
- # edge_nullable(true)
29
- # node_nullable(true)
30
- # has_nodes_field(true)
29
+ # edge_type Types::PostEdge,
30
+ # edges_nullable: true,
31
+ # edge_nullable: true,
32
+ # node_nullable: true,
33
+ # nodes_field: true
34
+ #
35
+ # # Alternatively, you can call the class methods followed by your edge type
36
+ # # edges_nullable true
37
+ # # edge_nullable true
38
+ # # nodes_nullable true
39
+ # # has_nodes_field true
40
+ # # edge_type Types::PostEdge
31
41
  # end
32
42
  #
33
43
  # @see Relay::BaseEdge for edge types
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.0.6"
3
+ VERSION = "2.0.7"
4
4
  end
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.0.6
4
+ version: 2.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-14 00:00:00.000000000 Z
11
+ date: 2022-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -314,7 +314,6 @@ files:
314
314
  - lib/graphql/execution/interpreter/runtime.rb
315
315
  - lib/graphql/execution/lazy.rb
316
316
  - lib/graphql/execution/lazy/lazy_method_map.rb
317
- - lib/graphql/execution/lazy/resolve.rb
318
317
  - lib/graphql/execution/lookahead.rb
319
318
  - lib/graphql/execution/multiplex.rb
320
319
  - lib/graphql/execution_error.rb
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
- module GraphQL
3
- module Execution
4
- class Lazy
5
- # Helpers for dealing with data structures containing {Lazy} instances
6
- # @api private
7
- module Resolve
8
- # Mutate `value`, replacing {Lazy} instances in place with their resolved values
9
- # @return [void]
10
-
11
- # This object can be passed like an array, but it doesn't allocate an
12
- # array until it's used.
13
- #
14
- # There's one crucial difference: you have to _capture_ the result
15
- # of `#<<`. (This _works_ with arrays but isn't required, since it has a side-effect.)
16
- # @api private
17
- module NullAccumulator
18
- def self.<<(item)
19
- [item]
20
- end
21
-
22
- def self.empty?
23
- true
24
- end
25
- end
26
-
27
- def self.resolve(value)
28
- lazies = resolve_in_place(value)
29
- deep_sync(lazies)
30
- end
31
-
32
- def self.resolve_in_place(value)
33
- acc = each_lazy(NullAccumulator, value)
34
-
35
- if acc.empty?
36
- Lazy::NullResult
37
- else
38
- Lazy.new {
39
- acc.each_with_index { |ctx, idx|
40
- acc[idx] = ctx.value.value
41
- }
42
- resolve_in_place(acc)
43
- }
44
- end
45
- end
46
-
47
- # If `value` is a collection,
48
- # add any {Lazy} instances in the collection
49
- # to `acc`
50
- # @return [void]
51
- def self.each_lazy(acc, value)
52
- case value
53
- when Hash
54
- value.each do |key, field_result|
55
- acc = each_lazy(acc, field_result)
56
- end
57
- when Array
58
- value.each do |field_result|
59
- acc = each_lazy(acc, field_result)
60
- end
61
- when Query::Context::SharedMethods
62
- field_value = value.value
63
- case field_value
64
- when Lazy
65
- acc = acc << value
66
- when Enumerable # shortcut for Hash & Array
67
- acc = each_lazy(acc, field_value)
68
- end
69
- end
70
-
71
- acc
72
- end
73
-
74
- # Traverse `val`, triggering resolution for each {Lazy}.
75
- # These {Lazy}s are expected to mutate their owner data structures
76
- # during resolution! (They're created with the `.then` calls in `resolve_in_place`).
77
- # @return [void]
78
- def self.deep_sync(val)
79
- case val
80
- when Lazy
81
- deep_sync(val.value)
82
- when Array
83
- val.each { |v| deep_sync(v.value) }
84
- when Hash
85
- val.each { |k, v| deep_sync(v.value) }
86
- end
87
- end
88
- end
89
- end
90
- end
91
- end