graphql 2.6.11 → 2.6.12
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 +2 -0
- data/lib/graphql/dataloader.rb +2 -0
- data/lib/graphql/execution/field_resolve_step.rb +18 -7
- data/lib/graphql/execution/interpreter/runtime.rb +6 -2
- data/lib/graphql/language/parser.rb +8 -7
- data/lib/graphql/pagination/relation_connection.rb +6 -2
- data/lib/graphql/query/variables.rb +5 -1
- data/lib/graphql/schema/visibility/profile.rb +45 -3
- data/lib/graphql/static_validation/base_visitor.rb +11 -1
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +40 -5
- 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: 24a0e699fe2f72dd869173b2bc6aa96ec8d40e738a293bc56b9176debca03861
|
|
4
|
+
data.tar.gz: 18b16bf0c467f5f8dc0c00ea2bcf2fbaf53283edc9f09a3789918523090a97ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 74a34839ced3a300d20ca370cb37a7c88c56345ecb056e9b9caa7a424fdb7573c5a014b80a32772cc2a5eb40d83e568c5d0875d93b029b1663dda9547fc06ba1
|
|
7
|
+
data.tar.gz: 65dcfea9802c9fb682e6595ef2d2d224a256c0650ff24fa57774eac420b27e594b3c432a104d76c8e033c659a608940661ea4503e0737f63d7839ff36f5f4405
|
|
@@ -254,6 +254,8 @@ module GraphQL
|
|
|
254
254
|
task = Async::Task.new do |root_task|
|
|
255
255
|
run.root_task = root_task
|
|
256
256
|
root_task.graphql_async_dataloader_run = run
|
|
257
|
+
# Tasks inherit the spawning fiber's storage; give this run its own execution state.
|
|
258
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
257
259
|
set_fiber_variables(fiber_vars)
|
|
258
260
|
|
|
259
261
|
while first_pass || run.running? || !jobs.empty?
|
data/lib/graphql/dataloader.rb
CHANGED
|
@@ -263,6 +263,8 @@ module GraphQL
|
|
|
263
263
|
def spawn_fiber
|
|
264
264
|
fiber_vars = get_fiber_variables
|
|
265
265
|
Fiber.new(blocking: !@nonblocking) do
|
|
266
|
+
# Fibers inherit the spawning fiber's storage; give each one its own execution state.
|
|
267
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
266
268
|
set_fiber_variables(fiber_vars)
|
|
267
269
|
yield
|
|
268
270
|
ensure
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
module Execution
|
|
4
4
|
class FieldResolveStep
|
|
5
|
+
# Only these built-in fields on Relay connection and edge types return already-scoped items.
|
|
6
|
+
# Custom fields on those types must still be authorized normally.
|
|
7
|
+
SCOPED_RELAY_FIELD_NAMES = [:node, :nodes, :edges].freeze
|
|
8
|
+
|
|
5
9
|
def initialize(parent_type:, runner:, key:, selections_step:)
|
|
6
10
|
@selections_step = selections_step
|
|
7
11
|
@key = key
|
|
@@ -283,7 +287,7 @@ module GraphQL
|
|
|
283
287
|
authorized_objects = objects
|
|
284
288
|
end
|
|
285
289
|
|
|
286
|
-
if @parent_type.default_relay? && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
|
|
290
|
+
if @parent_type.default_relay? && SCOPED_RELAY_FIELD_NAMES.include?(@field_definition.original_name) && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
|
|
287
291
|
@was_scoped = true
|
|
288
292
|
end
|
|
289
293
|
|
|
@@ -527,7 +531,7 @@ module GraphQL
|
|
|
527
531
|
end
|
|
528
532
|
|
|
529
533
|
inner_type = return_type.of_type
|
|
530
|
-
result_a = Array.new(field_result.size)
|
|
534
|
+
result_a = field_result.is_a?(Array) ? Array.new(field_result.size) : []
|
|
531
535
|
field_result.each_with_index do |item, idx|
|
|
532
536
|
result_a[idx] = build_leaf_result(result_a, idx, item, inner_type, ctx, true)
|
|
533
537
|
end
|
|
@@ -645,11 +649,18 @@ module GraphQL
|
|
|
645
649
|
list_result = graphql_result[key] = []
|
|
646
650
|
@directive_finalizers&.each { |f| @runner.add_finalizer(@selections_step.query, list_result, nil, f) }
|
|
647
651
|
i = 0
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
652
|
+
if field_result.is_a?(Array)
|
|
653
|
+
s = field_result.size
|
|
654
|
+
while i < s
|
|
655
|
+
inner_f_r = field_result[i]
|
|
656
|
+
build_graphql_result(list_result, i, inner_f_r, inner_type, inner_type_nn, inner_type_l, true)
|
|
657
|
+
i += 1
|
|
658
|
+
end
|
|
659
|
+
else
|
|
660
|
+
field_result.each do |inner_f_r|
|
|
661
|
+
build_graphql_result(list_result, i, inner_f_r, inner_type, inner_type_nn, inner_type_l, true)
|
|
662
|
+
i += 1
|
|
663
|
+
end
|
|
653
664
|
end
|
|
654
665
|
elsif @runner.resolves_lazies || (
|
|
655
666
|
@static_type.kind.object? ?
|
|
@@ -619,7 +619,9 @@ module GraphQL
|
|
|
619
619
|
when Array
|
|
620
620
|
# It's an array full of execution errors; add them all.
|
|
621
621
|
if !value.empty? && value.all?(GraphQL::ExecutionError)
|
|
622
|
-
|
|
622
|
+
list_type = field && field.type
|
|
623
|
+
list_type = list_type.of_type if list_type && list_type.non_null?
|
|
624
|
+
list_type_at_all = list_type && list_type.list?
|
|
623
625
|
if selection_result.nil? || !selection_result.graphql_dead
|
|
624
626
|
value.each_with_index do |error, index|
|
|
625
627
|
error.ast_node ||= ast_node
|
|
@@ -627,7 +629,7 @@ module GraphQL
|
|
|
627
629
|
context.errors << error
|
|
628
630
|
end
|
|
629
631
|
if selection_result
|
|
630
|
-
if list_type_at_all
|
|
632
|
+
if list_type_at_all && !list_type.of_type.non_null?
|
|
631
633
|
result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
|
|
632
634
|
set_result(selection_result, result_name, result_without_errors, false, is_non_null)
|
|
633
635
|
else
|
|
@@ -798,6 +800,8 @@ module GraphQL
|
|
|
798
800
|
|
|
799
801
|
def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
|
|
800
802
|
runtime_state ||= get_current_runtime_state
|
|
803
|
+
runtime_state.current_field = field
|
|
804
|
+
runtime_state.current_arguments = arguments
|
|
801
805
|
runtime_state.current_result_name = this_idx
|
|
802
806
|
runtime_state.current_result = response_list
|
|
803
807
|
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
|
@@ -65,24 +65,25 @@ module GraphQL
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def column_at(pos)
|
|
68
|
-
next_line_idx = lines_at.bsearch_index { |l| l >= pos } ||
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
pos -
|
|
68
|
+
next_line_idx = lines_at.bsearch_index { |l| l >= pos } || @lines_at.size
|
|
69
|
+
line_start = next_line_idx == 0 ? 0 : @lines_at[next_line_idx - 1] + 1
|
|
70
|
+
if @graphql_str.ascii_only?
|
|
71
|
+
pos - line_start + 1
|
|
72
72
|
else
|
|
73
|
-
pos + 1
|
|
73
|
+
@graphql_str.byteslice(line_start, pos - line_start).force_encoding(Encoding::UTF_8).length + 1
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
|
-
# @return [Array<Integer>]
|
|
79
|
+
# @return [Array<Integer>] Byte offsets of each line break in the original string
|
|
80
80
|
def lines_at
|
|
81
81
|
@lines_at ||= begin
|
|
82
|
+
graphql_str = @graphql_str.b
|
|
82
83
|
la = []
|
|
83
84
|
idx = 0
|
|
84
85
|
while idx
|
|
85
|
-
idx =
|
|
86
|
+
idx = graphql_str.index("\n", idx)
|
|
86
87
|
if idx
|
|
87
88
|
la << idx
|
|
88
89
|
idx += 1
|
|
@@ -88,7 +88,11 @@ module GraphQL
|
|
|
88
88
|
|
|
89
89
|
# @return [Integer]
|
|
90
90
|
def offset_from_cursor(cursor)
|
|
91
|
-
decode(cursor)
|
|
91
|
+
offset = Integer(decode(cursor), 10, exception: false)
|
|
92
|
+
if offset.nil? || offset <= 0
|
|
93
|
+
raise GraphQL::ExecutionError, "Invalid cursor: #{cursor.inspect}"
|
|
94
|
+
end
|
|
95
|
+
offset
|
|
92
96
|
end
|
|
93
97
|
|
|
94
98
|
# Abstract this operation so we can always ignore inputs less than zero.
|
|
@@ -230,7 +234,7 @@ module GraphQL
|
|
|
230
234
|
end
|
|
231
235
|
|
|
232
236
|
def async_dataloader?
|
|
233
|
-
@context&.
|
|
237
|
+
@context&.dataloader.is_a?(GraphQL::Dataloader::AsyncDataloader)
|
|
234
238
|
end
|
|
235
239
|
|
|
236
240
|
# Load nodes after applying first/last/before/after,
|
|
@@ -35,7 +35,11 @@ module GraphQL
|
|
|
35
35
|
value_was_provided = @provided_variables.key?(variable_name)
|
|
36
36
|
max_errors = schema.validate_max_errors - @errors.count if schema.validate_max_errors
|
|
37
37
|
begin
|
|
38
|
-
validation_result =
|
|
38
|
+
validation_result = if value_was_provided || default_value.nil?
|
|
39
|
+
variable_type.validate_input(provided_value, ctx, max_errors: max_errors)
|
|
40
|
+
else
|
|
41
|
+
GraphQL::Query::InputValidationResult::VALID
|
|
42
|
+
end
|
|
39
43
|
if validation_result.valid?
|
|
40
44
|
if value_was_provided
|
|
41
45
|
# Add the variable if a value was provided
|
|
@@ -33,30 +33,49 @@ module GraphQL
|
|
|
33
33
|
|
|
34
34
|
def freeze
|
|
35
35
|
@cached_visible.default_proc = nil
|
|
36
|
+
@cached_visible.freeze
|
|
36
37
|
@cached_visible_fields.default_proc = nil
|
|
37
38
|
@cached_visible_fields.each do |type, fields|
|
|
38
39
|
fields.default_proc = nil
|
|
40
|
+
fields.freeze
|
|
39
41
|
end
|
|
42
|
+
@cached_visible_fields.freeze
|
|
40
43
|
@cached_visible_arguments.default_proc = nil
|
|
41
44
|
@cached_visible_arguments.each do |type, fields|
|
|
42
45
|
fields.default_proc = nil
|
|
46
|
+
fields.freeze
|
|
43
47
|
end
|
|
48
|
+
@cached_visible_arguments.freeze
|
|
44
49
|
@cached_parent_fields.default_proc = nil
|
|
45
50
|
@cached_parent_fields.each do |type, fields|
|
|
46
51
|
fields.default_proc = nil
|
|
52
|
+
fields.freeze
|
|
47
53
|
end
|
|
54
|
+
@cached_parent_fields.freeze
|
|
48
55
|
@cached_parent_arguments.default_proc = nil
|
|
49
56
|
@cached_parent_arguments.each do |type, args|
|
|
50
57
|
args.default_proc = nil
|
|
58
|
+
args.freeze
|
|
51
59
|
end
|
|
60
|
+
@cached_parent_arguments.freeze
|
|
52
61
|
@cached_possible_types.default_proc = nil
|
|
62
|
+
@cached_possible_types.freeze
|
|
53
63
|
@cached_enum_values.default_proc = nil
|
|
64
|
+
@cached_enum_values.freeze
|
|
54
65
|
@cached_fields.default_proc = nil
|
|
66
|
+
@cached_fields.freeze
|
|
55
67
|
@cached_arguments.default_proc = nil
|
|
68
|
+
@cached_arguments.freeze
|
|
56
69
|
@loadable_possible_types.default_proc = nil
|
|
70
|
+
@loadable_possible_types.freeze
|
|
57
71
|
@cached_field_result.default_proc = nil
|
|
58
|
-
@cached_field_result.each
|
|
72
|
+
@cached_field_result.each do |_, h|
|
|
73
|
+
h.default_proc = nil
|
|
74
|
+
h.freeze
|
|
75
|
+
end
|
|
76
|
+
@cached_field_result.freeze
|
|
59
77
|
@cached_type_result.default_proc = nil
|
|
78
|
+
@cached_type_result.freeze
|
|
60
79
|
super
|
|
61
80
|
end
|
|
62
81
|
|
|
@@ -277,10 +296,18 @@ module GraphQL
|
|
|
277
296
|
arguments(f).each do |arg|
|
|
278
297
|
argument(f, arg.graphql_name)
|
|
279
298
|
end
|
|
299
|
+
|
|
300
|
+
resolver_class = f.resolver
|
|
301
|
+
if resolver_class
|
|
302
|
+
arguments(resolver_class).each do |arg|
|
|
303
|
+
argument(resolver_class, arg.graphql_name)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
280
306
|
end
|
|
281
307
|
@schema.introspection_system.dynamic_fields.each do |f|
|
|
282
308
|
field(type_defn, f.graphql_name)
|
|
283
309
|
end
|
|
310
|
+
interfaces(type_defn)
|
|
284
311
|
elsif type_defn.kind.input_object?
|
|
285
312
|
arguments(type_defn).each do |arg|
|
|
286
313
|
argument(type_defn, arg.graphql_name)
|
|
@@ -289,8 +316,9 @@ module GraphQL
|
|
|
289
316
|
enum_values(type_defn)
|
|
290
317
|
elsif type_defn.kind.union?
|
|
291
318
|
loadable_possible_types(type_defn, @context)
|
|
292
|
-
|
|
293
|
-
|
|
319
|
+
@schema.introspection_system.dynamic_fields.each do |f|
|
|
320
|
+
field(type_defn, f.graphql_name)
|
|
321
|
+
end
|
|
294
322
|
end
|
|
295
323
|
possible_types(type_defn)
|
|
296
324
|
end
|
|
@@ -313,6 +341,20 @@ module GraphQL
|
|
|
313
341
|
argument(directive, directive_argument.graphql_name)
|
|
314
342
|
end
|
|
315
343
|
end
|
|
344
|
+
|
|
345
|
+
@cached_arguments.each do |owner, args|
|
|
346
|
+
@cached_parent_arguments[owner]
|
|
347
|
+
|
|
348
|
+
args.each do |arg|
|
|
349
|
+
if (loads_type = arg.loads)
|
|
350
|
+
loadable?(loads_type, @context)
|
|
351
|
+
possible_types(loads_type)
|
|
352
|
+
if loads_type.kind.union?
|
|
353
|
+
loadable_possible_types(loads_type, @context)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
316
358
|
end
|
|
317
359
|
|
|
318
360
|
private
|
|
@@ -16,6 +16,7 @@ module GraphQL
|
|
|
16
16
|
@schema = context.schema
|
|
17
17
|
@inline_fragment_paths = {}
|
|
18
18
|
@field_unwrapped_types = {}.compare_by_identity
|
|
19
|
+
@child_positions = {}.compare_by_identity
|
|
19
20
|
super(document)
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -159,6 +160,7 @@ module GraphQL
|
|
|
159
160
|
@current_argument_definition = @parent_argument_definition
|
|
160
161
|
@parent_argument_definition = prev_parent
|
|
161
162
|
@path_depth -= 1
|
|
163
|
+
@child_positions.delete(node)
|
|
162
164
|
end
|
|
163
165
|
|
|
164
166
|
def on_fragment_spread(node, parent)
|
|
@@ -171,7 +173,7 @@ module GraphQL
|
|
|
171
173
|
def on_input_object(node, parent)
|
|
172
174
|
arg_defn = @current_argument_definition
|
|
173
175
|
if arg_defn && arg_defn.type.list?
|
|
174
|
-
@path[@path_depth] = parent
|
|
176
|
+
@path[@path_depth] = child_positions(parent)[node]
|
|
175
177
|
@path_depth += 1
|
|
176
178
|
super
|
|
177
179
|
@path_depth -= 1
|
|
@@ -180,6 +182,14 @@ module GraphQL
|
|
|
180
182
|
end
|
|
181
183
|
end
|
|
182
184
|
|
|
185
|
+
def child_positions(parent)
|
|
186
|
+
@child_positions[parent] ||= begin
|
|
187
|
+
positions = {}.compare_by_identity
|
|
188
|
+
parent.children.each_with_index { |child, index| positions[child] ||= index }
|
|
189
|
+
positions
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
183
193
|
# @return [GraphQL::BaseType] The current object type
|
|
184
194
|
def type_definition
|
|
185
195
|
@current_object_type
|
|
@@ -9,18 +9,53 @@ module GraphQL
|
|
|
9
9
|
'Schema is not configured for subscriptions',
|
|
10
10
|
nodes: node
|
|
11
11
|
))
|
|
12
|
-
elsif node.selections.size != 1
|
|
13
|
-
add_error(GraphQL::StaticValidation::NotSingleSubscriptionError.new(
|
|
14
|
-
'A subscription operation may only have one selection',
|
|
15
|
-
nodes: node,
|
|
16
|
-
))
|
|
17
12
|
else
|
|
13
|
+
root_fields = subscription_root_fields(node)
|
|
14
|
+
if root_fields.map { |field| field.alias || field.name }.uniq.size != 1
|
|
15
|
+
add_error(GraphQL::StaticValidation::NotSingleSubscriptionError.new(
|
|
16
|
+
'A subscription operation may only have one selection',
|
|
17
|
+
nodes: node,
|
|
18
|
+
))
|
|
19
|
+
elsif root_fields.any? { |field| field.name.start_with?("__") }
|
|
20
|
+
add_error(GraphQL::StaticValidation::NotSingleSubscriptionError.new(
|
|
21
|
+
'A subscription operation may not select an introspection field',
|
|
22
|
+
nodes: node,
|
|
23
|
+
))
|
|
24
|
+
end
|
|
18
25
|
super
|
|
19
26
|
end
|
|
20
27
|
else
|
|
21
28
|
super
|
|
22
29
|
end
|
|
23
30
|
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def subscription_root_fields(node)
|
|
35
|
+
root_type = context.types.subscription_root
|
|
36
|
+
fields = []
|
|
37
|
+
selections = node.selections.dup
|
|
38
|
+
visited_fragments = {}
|
|
39
|
+
|
|
40
|
+
while (selection = selections.pop)
|
|
41
|
+
case selection
|
|
42
|
+
when GraphQL::Language::Nodes::Field
|
|
43
|
+
fields << selection
|
|
44
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
|
45
|
+
next if visited_fragments[selection.name]
|
|
46
|
+
visited_fragments[selection.name] = true
|
|
47
|
+
fragment = context.fragments[selection.name]
|
|
48
|
+
selections << fragment if fragment
|
|
49
|
+
when GraphQL::Language::Nodes::InlineFragment, GraphQL::Language::Nodes::FragmentDefinition
|
|
50
|
+
fragment_type = selection.type ? @types.type(selection.type.name) : root_type
|
|
51
|
+
if fragment_type && fragment_type.kind.composite? && @types.possible_types(fragment_type).include?(root_type)
|
|
52
|
+
selections.concat(selection.selections)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
fields
|
|
58
|
+
end
|
|
24
59
|
end
|
|
25
60
|
end
|
|
26
61
|
end
|
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.12
|
|
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-10-14 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|