graphql 2.0.8 → 2.0.9
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.
- 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
|