graphql 2.6.10 → 2.6.11
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.
- checksums.yaml +4 -4
- data/lib/graphql/dataloader.rb +5 -2
- data/lib/graphql/execution/runner.rb +21 -17
- data/lib/graphql/pagination/array_connection.rb +5 -1
- data/lib/graphql/pagination/relation_connection.rb +18 -2
- data/lib/graphql/query.rb +2 -1
- data/lib/graphql/schema/directive.rb +5 -0
- data/lib/graphql/schema/member/has_arguments.rb +1 -1
- data/lib/graphql/schema/visibility/profile.rb +10 -1
- data/lib/graphql/subscriptions/serialize.rb +32 -5
- data/lib/graphql/tracing/sentry_trace.rb +13 -1
- data/lib/graphql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f449cab829c8314cf4cd1b51e225e70603f5dc16dfcb221d3204aa39bd9fe2cd
|
|
4
|
+
data.tar.gz: 6fb74ee40392f0663b728c76e72239596fc82271d2222e2d9170d8ad06579f6c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2820887a516c9a015774633ac126924642ceb778b523d0563af9ba766f6a3bfa5fa89ad0420c9ea3ee5208fe8fcdd58101aff1777b44de98c8c12b01fd64be0d
|
|
7
|
+
data.tar.gz: 90856cb6b43ac1be362d3358820857c1c8cc038f19def34a119677a6924c7b1441eca628c9e26a2134ae52aaab7507cea3521e36cad2763614909c10d8a79577
|
data/lib/graphql/dataloader.rb
CHANGED
|
@@ -262,11 +262,12 @@ module GraphQL
|
|
|
262
262
|
|
|
263
263
|
def spawn_fiber
|
|
264
264
|
fiber_vars = get_fiber_variables
|
|
265
|
-
Fiber.new(blocking: !@nonblocking)
|
|
265
|
+
Fiber.new(blocking: !@nonblocking) do
|
|
266
266
|
set_fiber_variables(fiber_vars)
|
|
267
267
|
yield
|
|
268
|
+
ensure
|
|
268
269
|
cleanup_fiber
|
|
269
|
-
|
|
270
|
+
end
|
|
270
271
|
end
|
|
271
272
|
|
|
272
273
|
# Pre-warm the Dataloader cache with ActiveRecord objects which were loaded elsewhere.
|
|
@@ -359,6 +360,7 @@ module GraphQL
|
|
|
359
360
|
while job = @pending_jobs.shift
|
|
360
361
|
job.call
|
|
361
362
|
end
|
|
363
|
+
ensure
|
|
362
364
|
trace&.dataloader_fiber_exit
|
|
363
365
|
end
|
|
364
366
|
end
|
|
@@ -392,6 +394,7 @@ module GraphQL
|
|
|
392
394
|
source.run_pending_keys
|
|
393
395
|
trace&.end_dataloader_source(source)
|
|
394
396
|
end
|
|
397
|
+
ensure
|
|
395
398
|
trace&.dataloader_fiber_exit
|
|
396
399
|
end
|
|
397
400
|
end
|
|
@@ -87,10 +87,10 @@ module GraphQL
|
|
|
87
87
|
@schema.analysis_engine.analyze_multiplex(@multiplex, multiplex_analyzers)
|
|
88
88
|
trace.end_analyze_multiplex(@multiplex, multiplex_analyzers)
|
|
89
89
|
|
|
90
|
-
results =
|
|
90
|
+
results = {}.compare_by_identity
|
|
91
91
|
queries.each do |query|
|
|
92
92
|
if query.validate && !query.valid?
|
|
93
|
-
results
|
|
93
|
+
results[query] = {
|
|
94
94
|
"errors" => query.static_errors.map(&:to_h)
|
|
95
95
|
}
|
|
96
96
|
next
|
|
@@ -125,8 +125,8 @@ module GraphQL
|
|
|
125
125
|
end
|
|
126
126
|
end
|
|
127
127
|
|
|
128
|
-
queries.
|
|
129
|
-
result = results[
|
|
128
|
+
queries.map do |query|
|
|
129
|
+
result = results[query]
|
|
130
130
|
|
|
131
131
|
fin_result = if (!@finalizers&.key?(query) && query.context.errors.empty?) || !query.valid?
|
|
132
132
|
result
|
|
@@ -155,12 +155,16 @@ module GraphQL
|
|
|
155
155
|
end
|
|
156
156
|
query.result
|
|
157
157
|
end
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
rescue SystemStackError => err
|
|
159
|
+
queries.map do |query|
|
|
160
|
+
@schema.query_stack_error(query, err)
|
|
161
|
+
query.result_values ||= { "errors" => query.context.errors.map(&:to_h) }
|
|
162
|
+
query.result
|
|
163
|
+
end
|
|
164
|
+
rescue Exception
|
|
165
|
+
# Assign values here so that the query's `@executed` becomes true
|
|
166
|
+
queries.map { |q| q.result_values ||= {} }
|
|
167
|
+
raise
|
|
164
168
|
end
|
|
165
169
|
ensure
|
|
166
170
|
Fiber[:__graphql_current_multiplex] = previous_multiplex
|
|
@@ -262,12 +266,12 @@ module GraphQL
|
|
|
262
266
|
end
|
|
263
267
|
|
|
264
268
|
if !auth_check
|
|
265
|
-
results
|
|
269
|
+
results[query] = {}
|
|
266
270
|
return
|
|
267
271
|
end
|
|
268
272
|
end
|
|
269
273
|
|
|
270
|
-
results
|
|
274
|
+
results[query] = { "data" => data }
|
|
271
275
|
objects = [root_value]
|
|
272
276
|
query.current_trace.objects(root_type, objects, query.context)
|
|
273
277
|
|
|
@@ -361,7 +365,7 @@ module GraphQL
|
|
|
361
365
|
objects = [root_value]
|
|
362
366
|
query.current_trace.objects(resolved_type, objects, query.context)
|
|
363
367
|
runtime_type_at[data] = resolved_type
|
|
364
|
-
results
|
|
368
|
+
results[query] = { "data" => data }
|
|
365
369
|
isolated_steps[0] << SelectionsStep.new(
|
|
366
370
|
parent_type: resolved_type,
|
|
367
371
|
field_resolve_step: nil,
|
|
@@ -376,10 +380,10 @@ module GraphQL
|
|
|
376
380
|
inner_type = root_type.unwrap
|
|
377
381
|
case inner_type.kind.name
|
|
378
382
|
when "SCALAR", "ENUM"
|
|
379
|
-
results
|
|
383
|
+
results[query] = run_isolated_scalar(root_type, query)
|
|
380
384
|
else
|
|
381
385
|
list_result = Array.new(root_value.size) { Hash.new.compare_by_identity }
|
|
382
|
-
results
|
|
386
|
+
results[query] = { "data" => list_result }
|
|
383
387
|
isolated_steps[0] << SelectionsStep.new(
|
|
384
388
|
parent_type: inner_type,
|
|
385
389
|
field_resolve_step: nil,
|
|
@@ -392,7 +396,7 @@ module GraphQL
|
|
|
392
396
|
)
|
|
393
397
|
end
|
|
394
398
|
when "SCALAR", "ENUM"
|
|
395
|
-
results
|
|
399
|
+
results[query] = run_isolated_scalar(root_type, query)
|
|
396
400
|
else
|
|
397
401
|
raise "Unhandled root type kind: #{root_type.kind.name.inspect}"
|
|
398
402
|
end
|
|
@@ -425,7 +429,7 @@ module GraphQL
|
|
|
425
429
|
key = dummy_path.pop
|
|
426
430
|
is_from_array = key.is_a?(Integer)
|
|
427
431
|
|
|
428
|
-
if lazy?(value)
|
|
432
|
+
if resolves_lazies && lazy?(value)
|
|
429
433
|
value = @schema.sync_lazy(value)
|
|
430
434
|
end
|
|
431
435
|
selections = partial.ast_nodes
|
|
@@ -27,7 +27,11 @@ module GraphQL
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def index_from_cursor(cursor)
|
|
30
|
-
decode(cursor)
|
|
30
|
+
index = Integer(decode(cursor), 10, exception: false)
|
|
31
|
+
if index.nil? || index <= 0
|
|
32
|
+
raise GraphQL::ExecutionError, "Invalid cursor: #{cursor.inspect}"
|
|
33
|
+
end
|
|
34
|
+
[index, items.length + 1].min
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
# Populate all the pagination info _once_,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require "graphql/pagination/connection"
|
|
3
|
+
require "monitor"
|
|
3
4
|
|
|
4
5
|
module GraphQL
|
|
5
6
|
module Pagination
|
|
@@ -178,6 +179,17 @@ module GraphQL
|
|
|
178
179
|
# Apply `first` and `last` to `sliced_nodes`,
|
|
179
180
|
# returning a new relation
|
|
180
181
|
def limited_nodes
|
|
182
|
+
return @limited_nodes if @limited_nodes
|
|
183
|
+
if async_dataloader?
|
|
184
|
+
(@load_monitor ||= Monitor.new).synchronize do
|
|
185
|
+
build_limited_nodes
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
build_limited_nodes
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def build_limited_nodes
|
|
181
193
|
@limited_nodes ||= begin
|
|
182
194
|
calculate_sliced_nodes_parameters
|
|
183
195
|
if @sliced_nodes_null_relation
|
|
@@ -217,15 +229,19 @@ module GraphQL
|
|
|
217
229
|
end
|
|
218
230
|
end
|
|
219
231
|
|
|
232
|
+
def async_dataloader?
|
|
233
|
+
@context&.[](:dataloader).is_a?(GraphQL::Dataloader::AsyncDataloader)
|
|
234
|
+
end
|
|
235
|
+
|
|
220
236
|
# Load nodes after applying first/last/before/after,
|
|
221
237
|
# returns an array of nodes
|
|
222
238
|
def load_nodes
|
|
223
239
|
# Return an array so we can consistently use `.index(node)` on it
|
|
224
240
|
return @nodes if @nodes
|
|
225
|
-
if
|
|
241
|
+
if async_dataloader?
|
|
226
242
|
# `AsyncDataloader` may resolve sibling fields (eg, `edges` and `pageInfo`)
|
|
227
243
|
# in separate Fibers, so several callers can get here before `@nodes` is set.
|
|
228
|
-
(@
|
|
244
|
+
(@load_monitor ||= Monitor.new).synchronize do
|
|
229
245
|
@nodes ||= limited_nodes.to_a
|
|
230
246
|
end
|
|
231
247
|
else
|
data/lib/graphql/query.rb
CHANGED
|
@@ -287,7 +287,8 @@ module GraphQL
|
|
|
287
287
|
# @return [GraphQL::Query::Result] A Hash-like GraphQL response, with `"data"` and/or `"errors"` keys
|
|
288
288
|
def result
|
|
289
289
|
if !@executed
|
|
290
|
-
|
|
290
|
+
execution_engine = @schema.default_execution_next ? Execution::Next : Execution::Interpreter
|
|
291
|
+
execution_engine.run_all(@schema, [self], context: @context)
|
|
291
292
|
end
|
|
292
293
|
@result ||= Query::Result.new(query: self, values: @result_values)
|
|
293
294
|
end
|
|
@@ -84,6 +84,11 @@ module GraphQL
|
|
|
84
84
|
yield
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
def resolve_field(...); end
|
|
88
|
+
def resolve_fragment_spread(...); end
|
|
89
|
+
def resolve_inline_fragment(...); end
|
|
90
|
+
def resolve_operation(...); end
|
|
91
|
+
|
|
87
92
|
def validate!(arguments, context)
|
|
88
93
|
Schema::Validator.validate!(validators, self, context, arguments)
|
|
89
94
|
end
|
|
@@ -397,7 +397,7 @@ module GraphQL
|
|
|
397
397
|
# This union/interface is used in `loads:` but not otherwise visible to this query
|
|
398
398
|
context.types.loadable_possible_types(arg_loads_type, context).include?(application_object_type)
|
|
399
399
|
else
|
|
400
|
-
|
|
400
|
+
arg_loads_type == application_object_type
|
|
401
401
|
end
|
|
402
402
|
else
|
|
403
403
|
context.types.possible_types(arg_loads_type).include?(application_object_type)
|
|
@@ -287,8 +287,12 @@ module GraphQL
|
|
|
287
287
|
end
|
|
288
288
|
elsif type_defn.kind.enum?
|
|
289
289
|
enum_values(type_defn)
|
|
290
|
+
elsif type_defn.kind.union?
|
|
291
|
+
loadable_possible_types(type_defn, @context)
|
|
292
|
+
elsif type_defn.kind.object? || type_defn.kind.interface?
|
|
293
|
+
interfaces(type_defn)
|
|
290
294
|
end
|
|
291
|
-
|
|
295
|
+
possible_types(type_defn)
|
|
292
296
|
end
|
|
293
297
|
if @schema.query
|
|
294
298
|
@schema.introspection_system.entry_points.each do |f|
|
|
@@ -304,6 +308,11 @@ module GraphQL
|
|
|
304
308
|
end
|
|
305
309
|
end
|
|
306
310
|
|
|
311
|
+
directives.each do |directive|
|
|
312
|
+
arguments(directive).each do |directive_argument|
|
|
313
|
+
argument(directive, directive_argument.graphql_name)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
307
316
|
end
|
|
308
317
|
|
|
309
318
|
private
|
|
@@ -13,6 +13,8 @@ module GraphQL
|
|
|
13
13
|
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S.%N%z" # eg '2020-01-01 23:59:59.123456789+05:00'
|
|
14
14
|
TIMESTAMP_CLASS_NAMES = ["Date", "DateTime", "Time"].freeze
|
|
15
15
|
OPEN_STRUCT_KEY = "__ostruct__"
|
|
16
|
+
HASH_KEY = "__graphql_hash__"
|
|
17
|
+
RESERVED_KEYS = [GLOBALID_KEY, SYMBOL_KEY, SYMBOL_KEYS_KEY, TIMESTAMP_KEY, OPEN_STRUCT_KEY, HASH_KEY].freeze
|
|
16
18
|
|
|
17
19
|
module_function
|
|
18
20
|
|
|
@@ -57,7 +59,7 @@ module GraphQL
|
|
|
57
59
|
# @return [Object] An object that load Global::Identification recursive
|
|
58
60
|
def load_value(value)
|
|
59
61
|
if value.is_a?(Array)
|
|
60
|
-
is_gids =
|
|
62
|
+
is_gids = !value.empty? && value.all? { |v| v.is_a?(Hash) && v.size == 1 && v[GLOBALID_KEY] }
|
|
61
63
|
if is_gids
|
|
62
64
|
# Assume it's an array of global IDs
|
|
63
65
|
ids = value.map { |v| v[GLOBALID_KEY] }
|
|
@@ -91,6 +93,10 @@ module GraphQL
|
|
|
91
93
|
when OPEN_STRUCT_KEY
|
|
92
94
|
ostruct_values = load_value(value[OPEN_STRUCT_KEY])
|
|
93
95
|
OpenStruct.new(ostruct_values)
|
|
96
|
+
when HASH_KEY
|
|
97
|
+
value[HASH_KEY].each_with_object({}) do |(k, v), loaded_h|
|
|
98
|
+
loaded_h[load_value(k)] = load_value(v)
|
|
99
|
+
end
|
|
94
100
|
else
|
|
95
101
|
key = value.keys.first
|
|
96
102
|
{ key => load_value(value[key]) }
|
|
@@ -98,15 +104,21 @@ module GraphQL
|
|
|
98
104
|
else
|
|
99
105
|
loaded_h = {}
|
|
100
106
|
sym_keys = value.fetch(SYMBOL_KEYS_KEY, [])
|
|
107
|
+
symbol_key_values = sym_keys.is_a?(Hash) ? sym_keys : nil
|
|
101
108
|
value.each do |k, v|
|
|
102
109
|
if k == SYMBOL_KEYS_KEY
|
|
103
110
|
next
|
|
104
111
|
end
|
|
105
|
-
if sym_keys.include?(k)
|
|
112
|
+
if !symbol_key_values && sym_keys.include?(k)
|
|
106
113
|
k = k.to_sym
|
|
107
114
|
end
|
|
108
115
|
loaded_h[k] = load_value(v)
|
|
109
116
|
end
|
|
117
|
+
if symbol_key_values
|
|
118
|
+
symbol_key_values.each do |k, v|
|
|
119
|
+
loaded_h[k.to_sym] = load_value(v)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
110
122
|
loaded_h
|
|
111
123
|
end
|
|
112
124
|
else
|
|
@@ -120,16 +132,31 @@ module GraphQL
|
|
|
120
132
|
if obj.is_a?(Array)
|
|
121
133
|
obj.map{|item| dump_value(item)}
|
|
122
134
|
elsif obj.is_a?(Hash)
|
|
135
|
+
has_colliding_symbol_key = obj.any? { |k, _v| k.is_a?(Symbol) && obj.key?(k.to_s) }
|
|
136
|
+
if obj.any? { |k, _v| RESERVED_KEYS.include?(k.to_s) }
|
|
137
|
+
return {
|
|
138
|
+
HASH_KEY => obj.map { |k, v| [dump_value(k.is_a?(Symbol) ? k : k.to_s), dump_value(v)] },
|
|
139
|
+
}
|
|
140
|
+
end
|
|
123
141
|
symbol_keys = nil
|
|
142
|
+
symbol_key_values = nil
|
|
124
143
|
dumped_h = {}
|
|
125
144
|
obj.each do |k, v|
|
|
126
|
-
|
|
127
|
-
if k.is_a?(Symbol)
|
|
145
|
+
dumped_v = dump_value(v)
|
|
146
|
+
if has_colliding_symbol_key && k.is_a?(Symbol)
|
|
147
|
+
symbol_key_values ||= {}
|
|
148
|
+
symbol_key_values[k.to_s] = dumped_v
|
|
149
|
+
else
|
|
150
|
+
dumped_h[k.to_s] = dumped_v
|
|
151
|
+
end
|
|
152
|
+
if !has_colliding_symbol_key && k.is_a?(Symbol)
|
|
128
153
|
symbol_keys ||= Set.new
|
|
129
154
|
symbol_keys << k.to_s
|
|
130
155
|
end
|
|
131
156
|
end
|
|
132
|
-
if
|
|
157
|
+
if symbol_key_values
|
|
158
|
+
dumped_h[SYMBOL_KEYS_KEY] = symbol_key_values
|
|
159
|
+
elsif symbol_keys
|
|
133
160
|
dumped_h[SYMBOL_KEYS_KEY] = symbol_keys.to_a
|
|
134
161
|
end
|
|
135
162
|
dumped_h
|
|
@@ -37,13 +37,18 @@ module GraphQL
|
|
|
37
37
|
scope.set_transaction_name(transaction_name(query))
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
|
-
|
|
40
|
+
if graphql_data_collection.nil? || graphql_data_collection.document
|
|
41
|
+
span.set_data('graphql.document', query.query_string)
|
|
42
|
+
end
|
|
41
43
|
if query.selected_operation_name
|
|
42
44
|
span.set_data('graphql.operation.name', query.selected_operation_name)
|
|
43
45
|
end
|
|
44
46
|
if query.selected_operation
|
|
45
47
|
span.set_data('graphql.operation.type', query.selected_operation.operation_type)
|
|
46
48
|
end
|
|
49
|
+
if graphql_data_collection&.variables && !query.provided_variables.empty?
|
|
50
|
+
span.set_data('graphql.variables', query.provided_variables)
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -55,6 +60,13 @@ module GraphQL
|
|
|
55
60
|
|
|
56
61
|
private
|
|
57
62
|
|
|
63
|
+
def graphql_data_collection
|
|
64
|
+
@graphql_data_collection ||= if Sentry.respond_to?(:configuration)
|
|
65
|
+
configuration = Sentry.configuration
|
|
66
|
+
configuration.data_collection.graphql if configuration.respond_to?(:data_collection)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
58
70
|
def operation_name(query)
|
|
59
71
|
selected_op = query.selected_operation
|
|
60
72
|
if selected_op
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: graphql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.6.
|
|
4
|
+
version: 2.6.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Mosolgo
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-09-21 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|