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 +4 -4
- data/lib/graphql/analysis/ast/field_usage.rb +3 -1
- data/lib/graphql/pagination/connection.rb +31 -4
- data/lib/graphql/pagination/connections.rb +1 -0
- data/lib/graphql/schema/field/connection_extension.rb +4 -0
- data/lib/graphql/schema/field.rb +23 -4
- data/lib/graphql/schema/resolver.rb +21 -0
- data/lib/graphql/schema.rb +8 -0
- data/lib/graphql/tracing/opentelemetry_tracing.rb +101 -0
- data/lib/graphql/tracing/platform_tracing.rb +4 -4
- data/lib/graphql/tracing.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39d95cd85a336ff82b22df87f496df97db11ecae05dbf80d090d5bb51445a499
|
4
|
+
data.tar.gz: b50ecc9d63922cbe1e7cbbd7d9a049528625584fb0bd6991918e867f8d6e2e45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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?
|
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
|
-
|
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 `
|
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
|
)
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -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
|
-
|
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)
|
data/lib/graphql/schema.rb
CHANGED
@@ -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
|
data/lib/graphql/tracing.rb
CHANGED
@@ -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"
|
data/lib/graphql/version.rb
CHANGED
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.
|
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-
|
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
|