graphql 2.6.9 → 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/async_dataloader.rb +35 -9
- data/lib/graphql/dataloader.rb +5 -2
- data/lib/graphql/execution/field_resolve_step.rb +8 -1
- data/lib/graphql/execution/interpreter.rb +3 -1
- data/lib/graphql/execution/runner.rb +23 -12
- data/lib/graphql/float_decoding_error.rb +13 -0
- data/lib/graphql/float_encoding_error.rb +28 -0
- data/lib/graphql/language/lexer.rb +10 -7
- data/lib/graphql/language.rb +2 -2
- data/lib/graphql/pagination/array_connection.rb +5 -1
- data/lib/graphql/pagination/relation_connection.rb +26 -1
- data/lib/graphql/query/variable_validation_error.rb +16 -1
- 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/schema.rb +2 -2
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +66 -29
- data/lib/graphql/subscriptions/serialize.rb +32 -5
- data/lib/graphql/tracing/sentry_trace.rb +13 -1
- data/lib/graphql/types/float.rb +18 -4
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +2 -0
- metadata +4 -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
|
|
@@ -36,10 +36,14 @@ module GraphQL
|
|
|
36
36
|
run = task.graphql_async_dataloader_run
|
|
37
37
|
trace = run.trace
|
|
38
38
|
trace&.dataloader_fiber_yield(source)
|
|
39
|
-
run.
|
|
39
|
+
if !run.push_task_message(:paused_task, task)
|
|
40
|
+
task.stop
|
|
41
|
+
end
|
|
40
42
|
condition = task.graphql_async_dataloader_condition
|
|
41
43
|
condition.wait
|
|
42
|
-
run.
|
|
44
|
+
if !run.push_task_message(:resumed_task, task)
|
|
45
|
+
task.stop
|
|
46
|
+
end
|
|
43
47
|
trace&.dataloader_fiber_resume(source)
|
|
44
48
|
nil
|
|
45
49
|
end
|
|
@@ -69,7 +73,7 @@ module GraphQL
|
|
|
69
73
|
|
|
70
74
|
attr_accessor :trace, :root_task
|
|
71
75
|
|
|
72
|
-
attr_reader :jobs, :lazies_at_depth, :jobs_fiber_limit, :snoozed_jobs_condition, :snoozed_sources_condition
|
|
76
|
+
attr_reader :dataloader, :jobs, :lazies_at_depth, :jobs_fiber_limit, :snoozed_jobs_condition, :snoozed_sources_condition
|
|
73
77
|
|
|
74
78
|
def jobs_bandwidth?
|
|
75
79
|
running_count < @jobs_fiber_limit
|
|
@@ -84,6 +88,20 @@ module GraphQL
|
|
|
84
88
|
@tasks_channel_task.cancel
|
|
85
89
|
end
|
|
86
90
|
|
|
91
|
+
# Push to the tasks_channel, tolerating a closed channel: on the error path, `run_queue`
|
|
92
|
+
# closes the channel while sibling tasks can still run one more slice before
|
|
93
|
+
# `root_task.cancel` reaches them. Record `:task_error` payloads so they aren't lost, and
|
|
94
|
+
# return false so the caller can stop the task instead of raising `ClosedError` into user code.
|
|
95
|
+
def push_task_message(msg, data)
|
|
96
|
+
@tasks_channel.push([msg, data])
|
|
97
|
+
true
|
|
98
|
+
rescue Async::Queue::ClosedError
|
|
99
|
+
if msg == :task_error
|
|
100
|
+
@task_error ||= data
|
|
101
|
+
end
|
|
102
|
+
false
|
|
103
|
+
end
|
|
104
|
+
|
|
87
105
|
def wait_for_activity
|
|
88
106
|
@activity.wait
|
|
89
107
|
end
|
|
@@ -175,11 +193,19 @@ module GraphQL
|
|
|
175
193
|
end
|
|
176
194
|
|
|
177
195
|
def active_run
|
|
178
|
-
@pending_run ||
|
|
196
|
+
@pending_run || current_task_run || raise(GraphQL::Error, "No available Run to append to, GraphQL-Ruby bug")
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# The current task's run, but only if it belongs to this dataloader. A different
|
|
200
|
+
# dataloader may be running inside one of our tasks (or vice versa), e.g. a query
|
|
201
|
+
# executed from a resolver or a subscription trigger; its run must not be reused.
|
|
202
|
+
def current_task_run
|
|
203
|
+
run = Async::Task.current?&.graphql_async_dataloader_run
|
|
204
|
+
run if run&.dataloader.equal?(self)
|
|
179
205
|
end
|
|
180
206
|
|
|
181
207
|
def run_isolated
|
|
182
|
-
previous_run =
|
|
208
|
+
previous_run = current_task_run
|
|
183
209
|
prev_pending_keys = {}
|
|
184
210
|
# Clear pending loads but keep already-cached records
|
|
185
211
|
# in case they are useful to the given block.
|
|
@@ -215,7 +241,7 @@ module GraphQL
|
|
|
215
241
|
|
|
216
242
|
def run(trace_query_lazy: nil)
|
|
217
243
|
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
|
218
|
-
run = @pending_run ||
|
|
244
|
+
run = @pending_run || current_task_run || raise(GraphQL::Error, "No available Run, GraphQL-Ruby internal bug")
|
|
219
245
|
@pending_run = nil
|
|
220
246
|
run.trace = trace
|
|
221
247
|
first_pass = true
|
|
@@ -336,14 +362,14 @@ module GraphQL
|
|
|
336
362
|
end
|
|
337
363
|
nil
|
|
338
364
|
rescue StandardError => err
|
|
339
|
-
run.
|
|
365
|
+
run.push_task_message(:task_error, err)
|
|
340
366
|
else
|
|
341
|
-
run.
|
|
367
|
+
run.push_task_message(:finished_task, task)
|
|
342
368
|
ensure
|
|
343
369
|
cleanup_fiber
|
|
344
370
|
trace&.dataloader_fiber_exit
|
|
345
371
|
end
|
|
346
|
-
run.
|
|
372
|
+
run.push_task_message(:started_task, new_task)
|
|
347
373
|
end
|
|
348
374
|
end
|
|
349
375
|
end
|
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
|
|
@@ -744,7 +744,8 @@ module GraphQL
|
|
|
744
744
|
when :dig
|
|
745
745
|
objects.map { |o| o.dig(*@field_definition.execution_mode_key) }
|
|
746
746
|
when :dataload
|
|
747
|
-
|
|
747
|
+
k = @field_definition.execution_mode_key
|
|
748
|
+
results = if k.is_a?(Class)
|
|
748
749
|
context.dataload_all(k, objects)
|
|
749
750
|
elsif (source_class = k[:with])
|
|
750
751
|
if (batch_args = k[:by])
|
|
@@ -764,6 +765,12 @@ module GraphQL
|
|
|
764
765
|
else
|
|
765
766
|
raise ArgumentError, "Unexpected `dataload: ...` configuration: #{k.inspect}"
|
|
766
767
|
end
|
|
768
|
+
method = k.is_a?(Hash) ? k[:method] : nil
|
|
769
|
+
if method
|
|
770
|
+
results.map { |r| r&.public_send(method) }
|
|
771
|
+
else
|
|
772
|
+
results
|
|
773
|
+
end
|
|
767
774
|
when :resolver_class
|
|
768
775
|
results = Array.new(objects.size, nil)
|
|
769
776
|
ps = @pending_steps ||= []
|
|
@@ -22,6 +22,7 @@ module GraphQL
|
|
|
22
22
|
# @param max_complexity [Integer, nil]
|
|
23
23
|
# @return [Array<GraphQL::Query::Result>] One result per query
|
|
24
24
|
def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
|
|
25
|
+
previous_multiplex = Fiber[:__graphql_current_multiplex]
|
|
25
26
|
queries = query_options.map do |opts|
|
|
26
27
|
query = case opts
|
|
27
28
|
when Hash
|
|
@@ -131,7 +132,6 @@ module GraphQL
|
|
|
131
132
|
queries.map { |q| q.result_values ||= {} }
|
|
132
133
|
raise
|
|
133
134
|
ensure
|
|
134
|
-
Fiber[:__graphql_current_multiplex] = nil
|
|
135
135
|
queries.map { |query|
|
|
136
136
|
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
|
137
137
|
if runtime
|
|
@@ -140,6 +140,8 @@ module GraphQL
|
|
|
140
140
|
}
|
|
141
141
|
end
|
|
142
142
|
end
|
|
143
|
+
ensure
|
|
144
|
+
Fiber[:__graphql_current_multiplex] = previous_multiplex
|
|
143
145
|
end
|
|
144
146
|
end
|
|
145
147
|
|
|
@@ -72,6 +72,7 @@ module GraphQL
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def execute
|
|
75
|
+
previous_multiplex = Fiber[:__graphql_current_multiplex]
|
|
75
76
|
Fiber[:__graphql_current_multiplex] = @multiplex
|
|
76
77
|
isolated_steps = [[]]
|
|
77
78
|
trace = @multiplex.current_trace
|
|
@@ -86,10 +87,10 @@ module GraphQL
|
|
|
86
87
|
@schema.analysis_engine.analyze_multiplex(@multiplex, multiplex_analyzers)
|
|
87
88
|
trace.end_analyze_multiplex(@multiplex, multiplex_analyzers)
|
|
88
89
|
|
|
89
|
-
results =
|
|
90
|
+
results = {}.compare_by_identity
|
|
90
91
|
queries.each do |query|
|
|
91
92
|
if query.validate && !query.valid?
|
|
92
|
-
results
|
|
93
|
+
results[query] = {
|
|
93
94
|
"errors" => query.static_errors.map(&:to_h)
|
|
94
95
|
}
|
|
95
96
|
next
|
|
@@ -124,8 +125,8 @@ module GraphQL
|
|
|
124
125
|
end
|
|
125
126
|
end
|
|
126
127
|
|
|
127
|
-
queries.
|
|
128
|
-
result = results[
|
|
128
|
+
queries.map do |query|
|
|
129
|
+
result = results[query]
|
|
129
130
|
|
|
130
131
|
fin_result = if (!@finalizers&.key?(query) && query.context.errors.empty?) || !query.valid?
|
|
131
132
|
result
|
|
@@ -154,9 +155,19 @@ module GraphQL
|
|
|
154
155
|
end
|
|
155
156
|
query.result
|
|
156
157
|
end
|
|
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
|
|
157
168
|
end
|
|
158
169
|
ensure
|
|
159
|
-
Fiber[:__graphql_current_multiplex] =
|
|
170
|
+
Fiber[:__graphql_current_multiplex] = previous_multiplex
|
|
160
171
|
end
|
|
161
172
|
|
|
162
173
|
def gather_selections(type_defn, ast_selections, selections_step, query, all_selections, prototype_result, into:)
|
|
@@ -255,12 +266,12 @@ module GraphQL
|
|
|
255
266
|
end
|
|
256
267
|
|
|
257
268
|
if !auth_check
|
|
258
|
-
results
|
|
269
|
+
results[query] = {}
|
|
259
270
|
return
|
|
260
271
|
end
|
|
261
272
|
end
|
|
262
273
|
|
|
263
|
-
results
|
|
274
|
+
results[query] = { "data" => data }
|
|
264
275
|
objects = [root_value]
|
|
265
276
|
query.current_trace.objects(root_type, objects, query.context)
|
|
266
277
|
|
|
@@ -354,7 +365,7 @@ module GraphQL
|
|
|
354
365
|
objects = [root_value]
|
|
355
366
|
query.current_trace.objects(resolved_type, objects, query.context)
|
|
356
367
|
runtime_type_at[data] = resolved_type
|
|
357
|
-
results
|
|
368
|
+
results[query] = { "data" => data }
|
|
358
369
|
isolated_steps[0] << SelectionsStep.new(
|
|
359
370
|
parent_type: resolved_type,
|
|
360
371
|
field_resolve_step: nil,
|
|
@@ -369,10 +380,10 @@ module GraphQL
|
|
|
369
380
|
inner_type = root_type.unwrap
|
|
370
381
|
case inner_type.kind.name
|
|
371
382
|
when "SCALAR", "ENUM"
|
|
372
|
-
results
|
|
383
|
+
results[query] = run_isolated_scalar(root_type, query)
|
|
373
384
|
else
|
|
374
385
|
list_result = Array.new(root_value.size) { Hash.new.compare_by_identity }
|
|
375
|
-
results
|
|
386
|
+
results[query] = { "data" => list_result }
|
|
376
387
|
isolated_steps[0] << SelectionsStep.new(
|
|
377
388
|
parent_type: inner_type,
|
|
378
389
|
field_resolve_step: nil,
|
|
@@ -385,7 +396,7 @@ module GraphQL
|
|
|
385
396
|
)
|
|
386
397
|
end
|
|
387
398
|
when "SCALAR", "ENUM"
|
|
388
|
-
results
|
|
399
|
+
results[query] = run_isolated_scalar(root_type, query)
|
|
389
400
|
else
|
|
390
401
|
raise "Unhandled root type kind: #{root_type.kind.name.inspect}"
|
|
391
402
|
end
|
|
@@ -418,7 +429,7 @@ module GraphQL
|
|
|
418
429
|
key = dummy_path.pop
|
|
419
430
|
is_from_array = key.is_a?(Integer)
|
|
420
431
|
|
|
421
|
-
if lazy?(value)
|
|
432
|
+
if resolves_lazies && lazy?(value)
|
|
422
433
|
value = @schema.sync_lazy(value)
|
|
423
434
|
end
|
|
424
435
|
selections = partial.ast_nodes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
# This error is raised when `Types::Float` is given a non-finite input value.
|
|
4
|
+
class FloatDecodingError < GraphQL::RuntimeTypeError
|
|
5
|
+
# The value which couldn't be decoded
|
|
6
|
+
attr_reader :float_value
|
|
7
|
+
|
|
8
|
+
def initialize(value)
|
|
9
|
+
@float_value = value
|
|
10
|
+
super("Float is not finite: #{value.inspect}.")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module GraphQL
|
|
3
|
+
# This error is raised when `Types::Float` is asked to return a non-finite value.
|
|
4
|
+
class FloatEncodingError < GraphQL::RuntimeTypeError
|
|
5
|
+
# The value which couldn't be encoded
|
|
6
|
+
attr_reader :float_value
|
|
7
|
+
|
|
8
|
+
# @return [GraphQL::Schema::Field] The field that returned a non-finite float
|
|
9
|
+
attr_reader :field
|
|
10
|
+
|
|
11
|
+
# @return [Array<String, Integer>] Where the field appeared in the GraphQL response
|
|
12
|
+
attr_reader :path
|
|
13
|
+
|
|
14
|
+
def initialize(value, context:)
|
|
15
|
+
@float_value = value
|
|
16
|
+
@field = context[:current_field]
|
|
17
|
+
@path = context[:current_path]
|
|
18
|
+
message = "Float is not finite: #{value.inspect}".dup
|
|
19
|
+
if @path
|
|
20
|
+
message << " @ #{@path.join(".")}"
|
|
21
|
+
end
|
|
22
|
+
if @field
|
|
23
|
+
message << " (#{@field.path})"
|
|
24
|
+
end
|
|
25
|
+
super("#{message}.")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -9,6 +9,9 @@ module GraphQL
|
|
|
9
9
|
end
|
|
10
10
|
@string = graphql_str
|
|
11
11
|
@filename = filename
|
|
12
|
+
if !@string.valid_encoding?
|
|
13
|
+
raise_parse_error("Parse error on bad Unicode escape sequence", nil, nil)
|
|
14
|
+
end
|
|
12
15
|
@scanner = StringScanner.new(graphql_str)
|
|
13
16
|
@pos = nil
|
|
14
17
|
@max_tokens = max_tokens || Float::INFINITY
|
|
@@ -110,10 +113,6 @@ module GraphQL
|
|
|
110
113
|
@scanner.pos += 1
|
|
111
114
|
:UNKNOWN_CHAR
|
|
112
115
|
end
|
|
113
|
-
rescue ArgumentError => err
|
|
114
|
-
if err.message == "invalid byte sequence in UTF-8"
|
|
115
|
-
raise_parse_error("Parse error on bad Unicode escape sequence", nil, nil)
|
|
116
|
-
end
|
|
117
116
|
end
|
|
118
117
|
|
|
119
118
|
def token_value
|
|
@@ -147,7 +146,7 @@ module GraphQL
|
|
|
147
146
|
"\\r" => "\r",
|
|
148
147
|
"\\t" => "\t",
|
|
149
148
|
}
|
|
150
|
-
UTF_8 = /\\u(?:([\
|
|
149
|
+
UTF_8 = /\\u(?:([\da-f]{4})|\{([\da-f]+)\})(?:\\u([\da-f]{4}))?/i
|
|
151
150
|
VALID_STRING = /\A(?:[^\\]|#{ESCAPES}|#{UTF_8})*\z/o
|
|
152
151
|
ESCAPED = /(?:#{ESCAPES}|#{UTF_8})/o
|
|
153
152
|
|
|
@@ -163,7 +162,11 @@ module GraphQL
|
|
|
163
162
|
if !str.valid_encoding? || !str.match?(VALID_STRING)
|
|
164
163
|
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
|
165
164
|
else
|
|
166
|
-
|
|
165
|
+
begin
|
|
166
|
+
Lexer.replace_escaped_characters_in_place(str)
|
|
167
|
+
rescue RangeError
|
|
168
|
+
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
|
169
|
+
end
|
|
167
170
|
|
|
168
171
|
if !str.valid_encoding?
|
|
169
172
|
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
|
@@ -289,7 +292,7 @@ module GraphQL
|
|
|
289
292
|
QUOTE = '"'
|
|
290
293
|
UNICODE_DIGIT = /[0-9A-Za-z]/
|
|
291
294
|
FOUR_DIGIT_UNICODE = /#{UNICODE_DIGIT}{4}/
|
|
292
|
-
N_DIGIT_UNICODE = %r{#{Punctuation::LCURLY}#{UNICODE_DIGIT}{
|
|
295
|
+
N_DIGIT_UNICODE = %r{#{Punctuation::LCURLY}#{UNICODE_DIGIT}+#{Punctuation::RCURLY}}x
|
|
293
296
|
UNICODE_ESCAPE = %r{\\u(?:#{FOUR_DIGIT_UNICODE}|#{N_DIGIT_UNICODE})}
|
|
294
297
|
STRING_ESCAPE = %r{[\\][\\/bfnrt]}
|
|
295
298
|
BLOCK_QUOTE = '"""'
|
data/lib/graphql/language.rb
CHANGED
|
@@ -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,11 +229,24 @@ 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
|
-
@nodes
|
|
240
|
+
return @nodes if @nodes
|
|
241
|
+
if async_dataloader?
|
|
242
|
+
# `AsyncDataloader` may resolve sibling fields (eg, `edges` and `pageInfo`)
|
|
243
|
+
# in separate Fibers, so several callers can get here before `@nodes` is set.
|
|
244
|
+
(@load_monitor ||= Monitor.new).synchronize do
|
|
245
|
+
@nodes ||= limited_nodes.to_a
|
|
246
|
+
end
|
|
247
|
+
else
|
|
248
|
+
@nodes = limited_nodes.to_a
|
|
249
|
+
end
|
|
225
250
|
end
|
|
226
251
|
end
|
|
227
252
|
end
|
|
@@ -22,7 +22,7 @@ module GraphQL
|
|
|
22
22
|
# It is possible there are other extension items in this error, so handle
|
|
23
23
|
# a one level deep merge explicitly. However beyond that only show the
|
|
24
24
|
# latest value and problems.
|
|
25
|
-
super.merge({ "extensions" => { "value" =>
|
|
25
|
+
super.merge({ "extensions" => { "value" => value_for_extensions, "problems" => validation_result.problems }}) do |key, oldValue, newValue|
|
|
26
26
|
if oldValue.respond_to?(:merge)
|
|
27
27
|
oldValue.merge(newValue)
|
|
28
28
|
else
|
|
@@ -33,6 +33,21 @@ module GraphQL
|
|
|
33
33
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
|
+
def value_for_extensions(value = @value)
|
|
37
|
+
case value
|
|
38
|
+
when Array
|
|
39
|
+
value.map { |item| value_for_extensions(item) }
|
|
40
|
+
when Hash
|
|
41
|
+
value.each_with_object({}) do |(key, item), result|
|
|
42
|
+
result[key] = value_for_extensions(item)
|
|
43
|
+
end
|
|
44
|
+
when Float
|
|
45
|
+
value.finite? ? value : value.to_s
|
|
46
|
+
else
|
|
47
|
+
value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
36
51
|
def problem_fields
|
|
37
52
|
@problem_fields ||= @validation_result
|
|
38
53
|
.problems
|
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
|
data/lib/graphql/schema.rb
CHANGED
|
@@ -1338,9 +1338,9 @@ module GraphQL
|
|
|
1338
1338
|
|
|
1339
1339
|
context.errors << execution_error
|
|
1340
1340
|
execution_error
|
|
1341
|
-
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
|
|
1341
|
+
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::FloatEncodingError, GraphQL::IntegerEncodingError
|
|
1342
1342
|
raise type_error
|
|
1343
|
-
when GraphQL::IntegerDecodingError
|
|
1343
|
+
when GraphQL::FloatDecodingError, GraphQL::IntegerDecodingError
|
|
1344
1344
|
nil
|
|
1345
1345
|
end
|
|
1346
1346
|
end
|
|
@@ -15,6 +15,8 @@ module GraphQL
|
|
|
15
15
|
# separately (which leads to exponential recursion through nested fragments),
|
|
16
16
|
# we flatten all fragment spreads into a single field map and compare within it.
|
|
17
17
|
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
|
18
|
+
EXCLUSIVE_COMPARISON = 1
|
|
19
|
+
NONEXCLUSIVE_COMPARISON = 2
|
|
18
20
|
|
|
19
21
|
class Field
|
|
20
22
|
attr_reader :node, :definition, :owner_type, :parents
|
|
@@ -33,6 +35,10 @@ module GraphQL
|
|
|
33
35
|
def unwrapped_return_type
|
|
34
36
|
@unwrapped_return_type ||= return_type&.unwrap
|
|
35
37
|
end
|
|
38
|
+
|
|
39
|
+
def comparison_key
|
|
40
|
+
@comparison_key ||= [@node, @parents]
|
|
41
|
+
end
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
def initialize(*)
|
|
@@ -43,6 +49,9 @@ module GraphQL
|
|
|
43
49
|
# Track which sub-selection node pairs have been compared to prevent
|
|
44
50
|
# infinite recursion with cyclic fragments
|
|
45
51
|
@compared_sub_selections = {}.compare_by_identity
|
|
52
|
+
@compared_field_groups = {}
|
|
53
|
+
@field_group_signatures = {}.compare_by_identity
|
|
54
|
+
@field_selection_signatures = {}.compare_by_identity
|
|
46
55
|
# Cache mutually_exclusive? results for type pairs
|
|
47
56
|
@mutually_exclusive_cache = {}.compare_by_identity
|
|
48
57
|
# Cache collect_fields results for sub-selection comparison
|
|
@@ -215,21 +224,7 @@ module GraphQL
|
|
|
215
224
|
end
|
|
216
225
|
|
|
217
226
|
if all_same
|
|
218
|
-
|
|
219
|
-
# sub-selections. Deduplicate by AST node identity — fields from
|
|
220
|
-
# the same node always have identical sub-selections.
|
|
221
|
-
unique_nodes = fields.uniq { |f| f.node.object_id }
|
|
222
|
-
i = 0
|
|
223
|
-
while i < unique_nodes.size
|
|
224
|
-
j = i + 1
|
|
225
|
-
while j < unique_nodes.size
|
|
226
|
-
if unique_nodes[i].node.selections.size > 0 || unique_nodes[j].node.selections.size > 0
|
|
227
|
-
find_conflict(key, unique_nodes[i], unique_nodes[j])
|
|
228
|
-
end
|
|
229
|
-
j += 1
|
|
230
|
-
end
|
|
231
|
-
i += 1
|
|
232
|
-
end
|
|
227
|
+
find_conflicts_between_selection_groups(key, fields)
|
|
233
228
|
else
|
|
234
229
|
groups = fields.group_by { |f| field_signature(f) }
|
|
235
230
|
unique_groups = groups.values
|
|
@@ -243,22 +238,10 @@ module GraphQL
|
|
|
243
238
|
gj += 1
|
|
244
239
|
end
|
|
245
240
|
|
|
246
|
-
# Within same group,
|
|
247
|
-
# pairs for sub-selection conflicts
|
|
241
|
+
# Within the same group, fields can only conflict on sub-selections.
|
|
248
242
|
group = unique_groups[gi]
|
|
249
243
|
if group.size >= 2
|
|
250
|
-
|
|
251
|
-
ui = 0
|
|
252
|
-
while ui < unique_in_group.size
|
|
253
|
-
uj = ui + 1
|
|
254
|
-
while uj < unique_in_group.size
|
|
255
|
-
if unique_in_group[ui].node.selections.size > 0 || unique_in_group[uj].node.selections.size > 0
|
|
256
|
-
find_conflict(key, unique_in_group[ui], unique_in_group[uj])
|
|
257
|
-
end
|
|
258
|
-
uj += 1
|
|
259
|
-
end
|
|
260
|
-
ui += 1
|
|
261
|
-
end
|
|
244
|
+
find_conflicts_between_selection_groups(key, group)
|
|
262
245
|
end
|
|
263
246
|
|
|
264
247
|
gi += 1
|
|
@@ -279,6 +262,29 @@ module GraphQL
|
|
|
279
262
|
end
|
|
280
263
|
end
|
|
281
264
|
|
|
265
|
+
def find_conflicts_between_selection_groups(response_key, fields)
|
|
266
|
+
fields_by_selection = {}
|
|
267
|
+
fields.each do |field|
|
|
268
|
+
fields_by_selection[field_selection_signature(field)] ||= field
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
representatives = fields_by_selection.values
|
|
272
|
+
i = 0
|
|
273
|
+
while i < representatives.size
|
|
274
|
+
j = i + 1
|
|
275
|
+
while j < representatives.size
|
|
276
|
+
find_conflict(response_key, representatives[i], representatives[j])
|
|
277
|
+
j += 1
|
|
278
|
+
end
|
|
279
|
+
i += 1
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def field_selection_signature(field)
|
|
284
|
+
node = field.node
|
|
285
|
+
@field_selection_signatures[node] ||= node.selections.map(&:to_query_string)
|
|
286
|
+
end
|
|
287
|
+
|
|
282
288
|
def fields_same_signature?(f1, f2)
|
|
283
289
|
n1 = f1.node
|
|
284
290
|
n2 = f2.node
|
|
@@ -458,6 +464,7 @@ module GraphQL
|
|
|
458
464
|
response_keys.each do |key, fields|
|
|
459
465
|
fields2 = response_keys2[key]
|
|
460
466
|
next unless fields2
|
|
467
|
+
next if field_groups_already_compared?(fields, fields2, mutually_exclusive)
|
|
461
468
|
|
|
462
469
|
fields_arr = fields.is_a?(Field) ? [fields] : fields
|
|
463
470
|
fields2_arr = fields2.is_a?(Field) ? [fields2] : fields2
|
|
@@ -475,6 +482,36 @@ module GraphQL
|
|
|
475
482
|
end
|
|
476
483
|
end
|
|
477
484
|
|
|
485
|
+
def field_groups_already_compared?(fields, fields2, mutually_exclusive)
|
|
486
|
+
signature1 = field_group_signature(fields)
|
|
487
|
+
signature2 = field_group_signature(fields2)
|
|
488
|
+
previous_comparisons = @compared_field_groups[signature1]
|
|
489
|
+
comparison_state = previous_comparisons && previous_comparisons[signature2]
|
|
490
|
+
|
|
491
|
+
if mutually_exclusive
|
|
492
|
+
return true if comparison_state
|
|
493
|
+
new_state = EXCLUSIVE_COMPARISON
|
|
494
|
+
else
|
|
495
|
+
return true if comparison_state == NONEXCLUSIVE_COMPARISON
|
|
496
|
+
new_state = NONEXCLUSIVE_COMPARISON
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
previous_comparisons ||= (@compared_field_groups[signature1] = {})
|
|
500
|
+
previous_comparisons[signature2] = new_state
|
|
501
|
+
|
|
502
|
+
reverse_comparisons = @compared_field_groups[signature2] ||= {}
|
|
503
|
+
reverse_comparisons[signature1] = new_state
|
|
504
|
+
false
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
def field_group_signature(fields)
|
|
508
|
+
if fields.is_a?(Field)
|
|
509
|
+
fields.comparison_key
|
|
510
|
+
else
|
|
511
|
+
@field_group_signatures[fields] ||= fields.map(&:comparison_key)
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
478
515
|
def same_arguments?(field1, field2)
|
|
479
516
|
arguments1 = field1.arguments
|
|
480
517
|
arguments2 = field2.arguments
|
|
@@ -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/types/float.rb
CHANGED
|
@@ -5,12 +5,26 @@ module GraphQL
|
|
|
5
5
|
class Float < GraphQL::Schema::Scalar
|
|
6
6
|
description "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)."
|
|
7
7
|
|
|
8
|
-
def self.coerce_input(value,
|
|
9
|
-
value.is_a?(Numeric)
|
|
8
|
+
def self.coerce_input(value, ctx)
|
|
9
|
+
return if !value.is_a?(Numeric)
|
|
10
|
+
|
|
11
|
+
value = value.to_f
|
|
12
|
+
if value.finite?
|
|
13
|
+
value
|
|
14
|
+
else
|
|
15
|
+
err = GraphQL::FloatDecodingError.new(value)
|
|
16
|
+
ctx.schema.type_error(err, ctx)
|
|
17
|
+
end
|
|
10
18
|
end
|
|
11
19
|
|
|
12
|
-
def self.coerce_result(value,
|
|
13
|
-
value.to_f
|
|
20
|
+
def self.coerce_result(value, ctx)
|
|
21
|
+
value = value.to_f
|
|
22
|
+
if value.finite?
|
|
23
|
+
value
|
|
24
|
+
else
|
|
25
|
+
err = GraphQL::FloatEncodingError.new(value, context: ctx)
|
|
26
|
+
ctx.schema.type_error(err, ctx)
|
|
27
|
+
end
|
|
14
28
|
end
|
|
15
29
|
|
|
16
30
|
default_scalar true
|
data/lib/graphql/version.rb
CHANGED
data/lib/graphql.rb
CHANGED
|
@@ -93,6 +93,8 @@ This is probably a bug in GraphQL-Ruby, please report this error on GitHub: http
|
|
|
93
93
|
autoload :AnalysisError, "graphql/analysis_error"
|
|
94
94
|
autoload :CoercionError, "graphql/coercion_error"
|
|
95
95
|
autoload :InvalidNameError, "graphql/invalid_name_error"
|
|
96
|
+
autoload :FloatDecodingError, "graphql/float_decoding_error"
|
|
97
|
+
autoload :FloatEncodingError, "graphql/float_encoding_error"
|
|
96
98
|
autoload :IntegerDecodingError, "graphql/integer_decoding_error"
|
|
97
99
|
autoload :IntegerEncodingError, "graphql/integer_encoding_error"
|
|
98
100
|
autoload :StringEncodingError, "graphql/string_encoding_error"
|
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
|
|
@@ -460,6 +460,8 @@ files:
|
|
|
460
460
|
- lib/graphql/execution/runner.rb
|
|
461
461
|
- lib/graphql/execution/selections_step.rb
|
|
462
462
|
- lib/graphql/execution_error.rb
|
|
463
|
+
- lib/graphql/float_decoding_error.rb
|
|
464
|
+
- lib/graphql/float_encoding_error.rb
|
|
463
465
|
- lib/graphql/integer_decoding_error.rb
|
|
464
466
|
- lib/graphql/integer_encoding_error.rb
|
|
465
467
|
- lib/graphql/introspection.rb
|