graphql 2.0.8 → 2.0.9

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: a10c35ffd2541c0b387e2e7d127eea0d1e2b4559fbd637288296369c0be09d0d
4
- data.tar.gz: 34bf4d3cc5ef08bfbc065f9cdff4690dfa4b3351d46e014422304b897b531189
3
+ metadata.gz: 39d95cd85a336ff82b22df87f496df97db11ecae05dbf80d090d5bb51445a499
4
+ data.tar.gz: b50ecc9d63922cbe1e7cbbd7d9a049528625584fb0bd6991918e867f8d6e2e45
5
5
  SHA512:
6
- metadata.gz: afed371861c1dcca740f07940d7f8239e800723623d6a9eb664592b169568ab1d92e3c2ea1286ba40625e00be0b27584f94e2493479cfd119251831d90c3f0a0
7
- data.tar.gz: 43e8362810fb7a48fcdec9f997a2b33c599e08c1276da79480e75c6fad456328775e71dc1317e98923a88b5e3169a5f9f3b491d09b943c49805d536071e0047f
6
+ metadata.gz: b404ea0ca0c0a1b4206330514da8d38c5e5f31abd4c93ebc696c91c2177f25e7f40703016742aeb6f8857f1bd208b9012778a21643a7ae08709bd08c994b31eb
7
+ data.tar.gz: 5d41fa5df69f4722bf0bffaca89675b77ff7cb4b1af863550bb5908e03135f82214f516c092b83273c3ff367d20c845a000db9d5bbf5f8e43a3db0a0640a0095
@@ -39,9 +39,11 @@ module GraphQL
39
39
  @used_deprecated_arguments << argument.definition.path
40
40
  end
41
41
 
42
+ next if argument.value.nil?
43
+
42
44
  if argument.definition.type.kind.input_object?
43
45
  extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
44
- elsif argument.definition.type.list? && !argument.value.nil?
46
+ elsif argument.definition.type.list?
45
47
  argument
46
48
  .value
47
49
  .select { |value| value.respond_to?(:arguments) }
@@ -56,8 +56,9 @@ module GraphQL
56
56
  # @param last [Integer, nil] Limit parameter from the client, if provided
57
57
  # @param before [String, nil] A cursor for pagination, if the client provided one.
58
58
  # @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection
59
- # @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
60
- def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil)
59
+ # @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set.
60
+ # @param default_page_size [Integer, nil] A configured value to determine the result size when neither first or last are given.
61
+ def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, default_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil)
61
62
  @items = items
62
63
  @parent = parent
63
64
  @context = context
@@ -76,6 +77,12 @@ module GraphQL
76
77
  else
77
78
  max_page_size
78
79
  end
80
+ @has_default_page_size_override = default_page_size != :not_given
81
+ @default_page_size = if default_page_size == :not_given
82
+ nil
83
+ else
84
+ default_page_size
85
+ end
79
86
  end
80
87
 
81
88
  def max_page_size=(new_value)
@@ -95,16 +102,36 @@ module GraphQL
95
102
  @has_max_page_size_override
96
103
  end
97
104
 
105
+ def default_page_size=(new_value)
106
+ @has_default_page_size_override = true
107
+ @default_page_size = new_value
108
+ end
109
+
110
+ def default_page_size
111
+ if @has_default_page_size_override
112
+ @default_page_size
113
+ else
114
+ context.schema.default_page_size
115
+ end
116
+ end
117
+
118
+ def has_default_page_size_override?
119
+ @has_default_page_size_override
120
+ end
121
+
98
122
  attr_writer :first
99
123
  # @return [Integer, nil]
100
124
  # A clamped `first` value.
101
125
  # (The underlying instance variable doesn't have limits on it.)
102
- # If neither `first` nor `last` is given, but `max_page_size` is present, max_page_size is used for first.
126
+ # If neither `first` nor `last` is given, but `default_page_size` is
127
+ # present, default_page_size is used for first. If `default_page_size`
128
+ # is greater than `max_page_size``, it'll be clamped down to
129
+ # `max_page_size`. If `default_page_size` is nil, use `max_page_size`.
103
130
  def first
104
131
  @first ||= begin
105
132
  capped = limit_pagination_argument(@first_value, max_page_size)
106
133
  if capped.nil? && last.nil?
107
- capped = max_page_size
134
+ capped = limit_pagination_argument(default_page_size, max_page_size) || max_page_size
108
135
  end
109
136
  capped
110
137
  end
@@ -70,6 +70,7 @@ module GraphQL
70
70
  parent: parent,
71
71
  field: field,
72
72
  max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
73
+ default_page_size: field.has_default_page_size? ? field.default_page_size : context.schema.default_page_size,
73
74
  first: arguments[:first],
74
75
  after: arguments[:after],
75
76
  last: arguments[:last],
@@ -47,6 +47,9 @@ module GraphQL
47
47
  if field.has_max_page_size? && !value.has_max_page_size_override?
48
48
  value.max_page_size = field.max_page_size
49
49
  end
50
+ if field.has_default_page_size? && !value.has_default_page_size_override?
51
+ value.default_page_size = field.default_page_size
52
+ end
50
53
  if context.schema.new_connections? && (custom_t = context.schema.connections.edge_class_for_field(@field))
51
54
  value.edge_class = custom_t
52
55
  end
@@ -64,6 +67,7 @@ module GraphQL
64
67
  original_arguments,
65
68
  field: field,
66
69
  max_page_size: field.max_page_size,
70
+ default_page_size: field.default_page_size,
67
71
  parent: object,
68
72
  context: context,
69
73
  )
@@ -200,6 +200,7 @@ module GraphQL
200
200
  # @param connection [Boolean] `true` if this field should get automagic connection behavior; default is to infer by `*Connection` in the return type name
201
201
  # @param connection_extension [Class] The extension to add, to implement connections. If `nil`, no extension is added.
202
202
  # @param max_page_size [Integer, nil] For connections, the maximum number of items to return from this field, or `nil` to allow unlimited results.
203
+ # @param default_page_size [Integer, nil] For connections, the default number of items to return from this field, or `nil` to return unlimited results.
203
204
  # @param introspection [Boolean] If true, this field will be marked as `#introspection?` and the name may begin with `__`
204
205
  # @param resolver_class [Class] (Private) A {Schema::Resolver} which this field was derived from. Use `resolver:` to create a field with a resolver.
205
206
  # @param arguments [{String=>GraphQL::Schema::Argument, Hash}] Arguments for this field (may be added in the block, also)
@@ -215,7 +216,7 @@ module GraphQL
215
216
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
216
217
  # @param validates [Array<Hash>] Configurations for validating this field
217
218
  # @fallback_value [Object] A fallback value if the method is not defined
218
- 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, 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)
219
+ 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)
219
220
  if name.nil?
220
221
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
221
222
  end
@@ -269,6 +270,8 @@ module GraphQL
269
270
  @connection = connection
270
271
  @has_max_page_size = max_page_size != :not_given
271
272
  @max_page_size = max_page_size == :not_given ? nil : max_page_size
273
+ @has_default_page_size = default_page_size != :not_given
274
+ @default_page_size = default_page_size == :not_given ? nil : default_page_size
272
275
  @introspection = introspection
273
276
  @extras = extras
274
277
  if !broadcastable.nil?
@@ -464,11 +467,11 @@ module GraphQL
464
467
  end
465
468
 
466
469
  if max_possible_page_size.nil?
467
- max_possible_page_size = max_page_size || query.schema.default_max_page_size
470
+ max_possible_page_size = default_page_size || query.schema.default_page_size || max_page_size || query.schema.default_max_page_size
468
471
  end
469
472
 
470
473
  if max_possible_page_size.nil?
471
- raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `max_page_size` or `default_max_page_size`"
474
+ raise GraphQL::Error, "Can't calculate complexity for #{path}, no `first:`, `last:`, `default_page_size`, `max_page_size` or `default_max_page_size`"
472
475
  else
473
476
  metadata_complexity = 0
474
477
  lookahead = GraphQL::Execution::Lookahead.new(query: query, field: self, ast_nodes: nodes, owner_type: owner)
@@ -496,7 +499,13 @@ module GraphQL
496
499
  case defined_complexity
497
500
  when Proc
498
501
  arguments = query.arguments_for(nodes.first, self)
499
- defined_complexity.call(query.context, arguments.keyword_arguments, child_complexity)
502
+ if arguments.is_a?(GraphQL::ExecutionError)
503
+ return child_complexity
504
+ elsif arguments.respond_to?(:keyword_arguments)
505
+ arguments = arguments.keyword_arguments
506
+ end
507
+
508
+ defined_complexity.call(query.context, arguments, child_complexity)
500
509
  when Numeric
501
510
  defined_complexity + child_complexity
502
511
  else
@@ -539,6 +548,16 @@ module GraphQL
539
548
  @max_page_size || (@resolver_class && @resolver_class.max_page_size)
540
549
  end
541
550
 
551
+ # @return [Boolean] True if this field's {#default_page_size} should override the schema default.
552
+ def has_default_page_size?
553
+ @has_default_page_size || (@resolver_class && @resolver_class.has_default_page_size?)
554
+ end
555
+
556
+ # @return [Integer, nil] Applied to connections if {#has_default_page_size?}
557
+ def default_page_size
558
+ @default_page_size || (@resolver_class && @resolver_class.default_page_size)
559
+ end
560
+
542
561
  class MissingReturnTypeError < GraphQL::Error; end
543
562
  attr_writer :type
544
563
 
@@ -328,6 +328,27 @@ module GraphQL
328
328
  (!!defined?(@max_page_size)) || (superclass.respond_to?(:has_max_page_size?) && superclass.has_max_page_size?)
329
329
  end
330
330
 
331
+ # Get or set the `default_page_size:` which will be configured for fields using this resolver
332
+ # (`nil` means "unlimited default page size".)
333
+ # @param default_page_size [Integer, nil] Set a new value
334
+ # @return [Integer, nil] The `default_page_size` assigned to fields that use this resolver
335
+ def default_page_size(new_default_page_size = :not_given)
336
+ if new_default_page_size != :not_given
337
+ @default_page_size = new_default_page_size
338
+ elsif defined?(@default_page_size)
339
+ @default_page_size
340
+ elsif superclass.respond_to?(:default_page_size)
341
+ superclass.default_page_size
342
+ else
343
+ nil
344
+ end
345
+ end
346
+
347
+ # @return [Boolean] `true` if this resolver or a superclass has an assigned `default_page_size`
348
+ def has_default_page_size?
349
+ (!!defined?(@default_page_size)) || (superclass.respond_to?(:has_default_page_size?) && superclass.has_default_page_size?)
350
+ end
351
+
331
352
  # A non-normalized type configuration, without `null` applied
332
353
  def type_expr
333
354
  @type_expr || (superclass.respond_to?(:type_expr) ? superclass.type_expr : nil)
@@ -506,6 +506,14 @@ module GraphQL
506
506
  end
507
507
  end
508
508
 
509
+ def default_page_size(new_default_page_size = nil)
510
+ if new_default_page_size
511
+ @default_page_size = new_default_page_size
512
+ else
513
+ @default_page_size || find_inherited_value(:default_page_size)
514
+ end
515
+ end
516
+
509
517
  def query_execution_strategy(new_query_execution_strategy = nil)
510
518
  if new_query_execution_strategy
511
519
  @query_execution_strategy = new_query_execution_strategy
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ class OpenTelemetryTracing < PlatformTracing
6
+ self.platform_keys = {
7
+ 'lex' => 'graphql.lex',
8
+ 'parse' => 'graphql.parse',
9
+ 'validate' => 'graphql.validate',
10
+ 'analyze_query' => 'graphql.analyze_query',
11
+ 'analyze_multiplex' => 'graphql.analyze_multiplex',
12
+ 'execute_query' => 'graphql.execute_query',
13
+ 'execute_query_lazy' => 'graphql.execute_query_lazy',
14
+ 'execute_multiplex' => 'graphql.execute_multiplex'
15
+ }
16
+
17
+ def platform_trace(platform_key, key, data)
18
+ return yield if platform_key.nil?
19
+
20
+ tracer.in_span(platform_key, attributes: attributes_for(key, data)) do |span, _context|
21
+ yield.tap do |response|
22
+ errors = response[:errors]&.compact&.map { |e| e.to_h }&.to_json if key == 'validate'
23
+ unless errors.nil?
24
+ span.add_event(
25
+ 'graphql.validation.error',
26
+ attributes: {
27
+ 'message' => errors
28
+ }
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def platform_field_key(type, field)
36
+ "#{type.graphql_name}.#{field.graphql_name}"
37
+ end
38
+
39
+ def platform_authorized_key(type)
40
+ "#{type.graphql_name}.authorized"
41
+ end
42
+
43
+ def platform_resolve_type_key(type)
44
+ "#{type.graphql_name}.resolve_type"
45
+ end
46
+
47
+ private
48
+
49
+ def tracer
50
+ OpenTelemetry::Instrumentation::GraphQL::Instrumentation.instance.tracer
51
+ end
52
+
53
+ def config
54
+ OpenTelemetry::Instrumentation::GraphQL::Instrumentation.instance.config
55
+ end
56
+
57
+ def platform_key_enabled?(ctx, key)
58
+ return false unless config[key]
59
+
60
+ ns = ctx.namespace(:opentelemetry)
61
+ return true if ns.empty? # restores original behavior so that keys are returned if tracing is not set in context.
62
+ return false unless ns.key?(key) && ns[key]
63
+
64
+ return true
65
+ end
66
+
67
+ def attributes_for(key, data)
68
+ attributes = {}
69
+ case key
70
+ when 'execute_query'
71
+ attributes['selected_operation_name'] = data[:query].selected_operation_name if data[:query].selected_operation_name
72
+ attributes['selected_operation_type'] = data[:query].selected_operation.operation_type
73
+ attributes['query_string'] = data[:query].query_string
74
+ end
75
+ attributes
76
+ end
77
+
78
+ def cached_platform_key(ctx, key, trace_phase)
79
+ cache = ctx.namespace(self.class)[:platform_key_cache] ||= {}
80
+
81
+ cache.fetch(key) do
82
+ cache[key] = if trace_phase == :field
83
+ return unless platform_key_enabled?(ctx, :enable_platform_field)
84
+
85
+ yield
86
+ elsif trace_phase == :authorized
87
+ return unless platform_key_enabled?(ctx, :enable_platform_authorized)
88
+
89
+ yield
90
+ elsif trace_phase == :resolve_type
91
+ return unless platform_key_enabled?(ctx, :enable_platform_resolve_type)
92
+
93
+ yield
94
+ else
95
+ raise "Unknown trace phase"
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -45,7 +45,7 @@ module GraphQL
45
45
 
46
46
  platform_key = if trace_field
47
47
  context = data.fetch(:query).context
48
- cached_platform_key(context, field) { platform_field_key(data[:owner], field) }
48
+ cached_platform_key(context, field, :field) { platform_field_key(data[:owner], field) }
49
49
  else
50
50
  nil
51
51
  end
@@ -61,14 +61,14 @@ module GraphQL
61
61
  when "authorized", "authorized_lazy"
62
62
  type = data.fetch(:type)
63
63
  context = data.fetch(:context)
64
- platform_key = cached_platform_key(context, type) { platform_authorized_key(type) }
64
+ platform_key = cached_platform_key(context, type, :authorized) { platform_authorized_key(type) }
65
65
  platform_trace(platform_key, key, data) do
66
66
  yield
67
67
  end
68
68
  when "resolve_type", "resolve_type_lazy"
69
69
  type = data.fetch(:type)
70
70
  context = data.fetch(:context)
71
- platform_key = cached_platform_key(context, type) { platform_resolve_type_key(type) }
71
+ platform_key = cached_platform_key(context, type, :resolve_type) { platform_resolve_type_key(type) }
72
72
  platform_trace(platform_key, key, data) do
73
73
  yield
74
74
  end
@@ -116,7 +116,7 @@ module GraphQL
116
116
  # If the key isn't present, the given block is called and the result is cached for `key`.
117
117
  #
118
118
  # @return [String]
119
- def cached_platform_key(ctx, key)
119
+ def cached_platform_key(ctx, key, trace_phase)
120
120
  cache = ctx.namespace(self.class)[:platform_key_cache] ||= {}
121
121
  cache.fetch(key) { cache[key] = yield }
122
122
  end
@@ -8,6 +8,7 @@ require "graphql/tracing/new_relic_tracing"
8
8
  require "graphql/tracing/scout_tracing"
9
9
  require "graphql/tracing/statsd_tracing"
10
10
  require "graphql/tracing/prometheus_tracing"
11
+ require "graphql/tracing/opentelemetry_tracing"
11
12
 
12
13
  if defined?(PrometheusExporter::Server)
13
14
  require "graphql/tracing/prometheus_tracing/graphql_collector"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.0.8"
3
+ VERSION = "2.0.9"
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.8
4
+ version: 2.0.9
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-05-24 00:00:00.000000000 Z
11
+ date: 2022-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -538,6 +538,7 @@ files:
538
538
  - lib/graphql/tracing/data_dog_tracing.rb
539
539
  - lib/graphql/tracing/new_relic_tracing.rb
540
540
  - lib/graphql/tracing/notifications_tracing.rb
541
+ - lib/graphql/tracing/opentelemetry_tracing.rb
541
542
  - lib/graphql/tracing/platform_tracing.rb
542
543
  - lib/graphql/tracing/prometheus_tracing.rb
543
544
  - lib/graphql/tracing/prometheus_tracing/graphql_collector.rb