graphql 2.5.22 → 2.5.23
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/execution/interpreter/runtime.rb +3 -2
- data/lib/graphql/execution/interpreter.rb +6 -9
- data/lib/graphql/execution/lazy.rb +1 -1
- data/lib/graphql/execution/next/field_resolve_step.rb +93 -61
- data/lib/graphql/execution/next/load_argument_step.rb +5 -1
- data/lib/graphql/execution/next/prepare_object_step.rb +2 -2
- data/lib/graphql/execution/next/runner.rb +48 -26
- data/lib/graphql/execution/next.rb +3 -1
- data/lib/graphql/execution.rb +7 -4
- data/lib/graphql/execution_error.rb +5 -1
- data/lib/graphql/query/context.rb +1 -1
- data/lib/graphql/schema/field.rb +3 -4
- data/lib/graphql/schema/list.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +5 -1
- data/lib/graphql/schema/non_null.rb +1 -1
- data/lib/graphql/schema/resolver.rb +18 -3
- data/lib/graphql/schema/subscription.rb +0 -2
- data/lib/graphql/schema/visibility/profile.rb +68 -49
- data/lib/graphql/schema/wrapper.rb +7 -1
- data/lib/graphql/static_validation/base_visitor.rb +90 -66
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +18 -6
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +5 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +5 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -3
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +322 -256
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +4 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +10 -7
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +27 -7
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +12 -9
- data/lib/graphql/static_validation/validation_context.rb +1 -1
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +25 -1
- data/lib/graphql/subscriptions/event.rb +1 -0
- data/lib/graphql/subscriptions.rb +20 -0
- data/lib/graphql/tracing/perfetto_trace.rb +2 -2
- data/lib/graphql/unauthorized_error.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
|
@@ -28,10 +28,10 @@ module GraphQL
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def add_conflict(node, conflict_str)
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
if nodes.any? { |n| n
|
|
31
|
+
# Check if we already have an error for this exact node.
|
|
32
|
+
# Use object identity first (fast path), then fall back to
|
|
33
|
+
# value + location comparison for duplicate AST nodes.
|
|
34
|
+
if nodes.any? { |n| n.equal?(node) || (n.line == node.line && n.col == node.col && n == node) }
|
|
35
35
|
# already have an error for this node
|
|
36
36
|
return
|
|
37
37
|
end
|
|
@@ -8,8 +8,8 @@ module GraphQL
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def on_inline_fragment(node, parent)
|
|
11
|
-
fragment_parent =
|
|
12
|
-
fragment_child =
|
|
11
|
+
fragment_parent = @parent_object_type
|
|
12
|
+
fragment_child = @current_object_type
|
|
13
13
|
if fragment_child
|
|
14
14
|
validate_fragment_in_scope(fragment_parent, fragment_child, node, context, context.path)
|
|
15
15
|
end
|
|
@@ -17,7 +17,7 @@ module GraphQL
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def on_fragment_spread(node, parent)
|
|
20
|
-
fragment_parent =
|
|
20
|
+
fragment_parent = @current_object_type
|
|
21
21
|
@spreads_to_validate << FragmentSpread.new(node: node, parent_type: fragment_parent, path: context.path)
|
|
22
22
|
super
|
|
23
23
|
end
|
|
@@ -23,18 +23,21 @@ module GraphQL
|
|
|
23
23
|
type_name = fragment_node.type.name
|
|
24
24
|
type = @types.type(type_name)
|
|
25
25
|
if type.nil?
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
suggestion = if @schema.did_you_mean
|
|
27
|
+
@all_possible_fragment_type_names ||= begin
|
|
28
|
+
names = []
|
|
29
|
+
context.types.all_types.each do |type|
|
|
30
|
+
if type.kind.fields?
|
|
31
|
+
names << type.graphql_name
|
|
32
|
+
end
|
|
31
33
|
end
|
|
34
|
+
names
|
|
32
35
|
end
|
|
33
|
-
|
|
36
|
+
context.did_you_mean_suggestion(type_name, @all_possible_fragment_type_names)
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
add_error(GraphQL::StaticValidation::FragmentTypesExistError.new(
|
|
37
|
-
"No such type #{type_name}, so it can't be a fragment condition#{
|
|
40
|
+
"No such type #{type_name}, so it can't be a fragment condition#{suggestion}",
|
|
38
41
|
nodes: fragment_node,
|
|
39
42
|
type: type_name
|
|
40
43
|
))
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
module StaticValidation
|
|
4
4
|
module RequiredArgumentsArePresent
|
|
5
|
+
def initialize(*)
|
|
6
|
+
super
|
|
7
|
+
@required_args_cache = {}.compare_by_identity
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
def on_field(node, _parent)
|
|
6
|
-
assert_required_args(node,
|
|
11
|
+
assert_required_args(node, @current_field_definition)
|
|
7
12
|
super
|
|
8
13
|
end
|
|
9
14
|
|
|
@@ -16,13 +21,28 @@ module GraphQL
|
|
|
16
21
|
private
|
|
17
22
|
|
|
18
23
|
def assert_required_args(ast_node, defn)
|
|
19
|
-
|
|
20
|
-
return if args.empty?
|
|
21
|
-
present_argument_names = ast_node.arguments.map(&:name)
|
|
22
|
-
required_argument_names = context.query.types.arguments(defn)
|
|
23
|
-
.select { |a| a.type.kind.non_null? && !a.default_value? && context.query.types.argument(defn, a.name) }
|
|
24
|
-
.map!(&:name)
|
|
24
|
+
return unless defn
|
|
25
25
|
|
|
26
|
+
# Cache required argument names per definition to avoid re-iterating
|
|
27
|
+
# arguments for the same definition across field instances
|
|
28
|
+
if @required_args_cache.key?(defn)
|
|
29
|
+
required_argument_names = @required_args_cache[defn]
|
|
30
|
+
else
|
|
31
|
+
args = @types.arguments(defn)
|
|
32
|
+
required_argument_names = nil
|
|
33
|
+
if !args.empty?
|
|
34
|
+
args.each do |a|
|
|
35
|
+
if a.type.kind.non_null? && !a.default_value? && @types.argument(defn, a.name)
|
|
36
|
+
(required_argument_names ||= []) << a.graphql_name
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
@required_args_cache[defn] = required_argument_names
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
return if required_argument_names.nil?
|
|
44
|
+
|
|
45
|
+
present_argument_names = ast_node.arguments.map(&:name)
|
|
26
46
|
missing_names = required_argument_names - present_argument_names
|
|
27
47
|
if !missing_names.empty?
|
|
28
48
|
add_error(GraphQL::StaticValidation::RequiredArgumentsArePresentError.new(
|
|
@@ -7,17 +7,20 @@ module GraphQL
|
|
|
7
7
|
type = context.query.types.type(type_name)
|
|
8
8
|
|
|
9
9
|
if type.nil?
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
suggestion = if @schema.did_you_mean
|
|
11
|
+
@all_possible_input_type_names ||= begin
|
|
12
|
+
names = []
|
|
13
|
+
context.types.all_types.each { |(t)|
|
|
14
|
+
if t.kind.input?
|
|
15
|
+
names << t.graphql_name
|
|
16
|
+
end
|
|
17
|
+
}
|
|
18
|
+
names
|
|
19
|
+
end
|
|
20
|
+
context.did_you_mean_suggestion(type_name, @all_possible_input_type_names)
|
|
18
21
|
end
|
|
19
22
|
add_error(GraphQL::StaticValidation::VariablesAreInputTypesError.new(
|
|
20
|
-
"#{type_name} isn't a defined input type (on $#{node.name})#{
|
|
23
|
+
"#{type_name} isn't a defined input type (on $#{node.name})#{suggestion}",
|
|
21
24
|
nodes: node,
|
|
22
25
|
name: node.name,
|
|
23
26
|
type: type_name
|
|
@@ -32,7 +32,7 @@ module GraphQL
|
|
|
32
32
|
# TODO stop using def_delegators because of Array allocations
|
|
33
33
|
def_delegators :@visitor,
|
|
34
34
|
:path, :type_definition, :field_definition, :argument_definition,
|
|
35
|
-
:parent_type_definition, :directive_definition, :
|
|
35
|
+
:parent_type_definition, :directive_definition, :dependencies
|
|
36
36
|
|
|
37
37
|
def on_dependency_resolve(&handler)
|
|
38
38
|
@on_dependency_resolve_handlers << handler
|
|
@@ -17,10 +17,34 @@ module GraphQL
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def resolve_next(context:, objects:, arguments:)
|
|
21
|
+
has_override_implementation = @field.execution_next_mode != :direct_send
|
|
22
|
+
|
|
23
|
+
if !has_override_implementation
|
|
24
|
+
if context.query.subscription_update?
|
|
25
|
+
objects
|
|
26
|
+
else
|
|
27
|
+
objects.map { |o| context.skip }
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
yield(objects, arguments)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
20
34
|
def after_resolve(value:, context:, object:, arguments:, **rest)
|
|
35
|
+
self.class.write_subscription(@field, value, arguments, context)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def after_resolve_next(values:, context:, objects:, arguments:, **rest)
|
|
39
|
+
values.map do |value|
|
|
40
|
+
self.class.write_subscription(@field, value, arguments, context)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.write_subscription(field, value, arguments, context)
|
|
21
45
|
if value.is_a?(GraphQL::ExecutionError)
|
|
22
46
|
value
|
|
23
|
-
elsif
|
|
47
|
+
elsif field.resolver&.method_defined?(:subscription_written?) &&
|
|
24
48
|
(subscription_namespace = context.namespace(:subscriptions)) &&
|
|
25
49
|
(subscriptions_by_path = subscription_namespace[:subscriptions])
|
|
26
50
|
(subscription_instance = subscriptions_by_path[context.current_path])
|
|
@@ -239,6 +239,26 @@ module GraphQL
|
|
|
239
239
|
query.context.namespace(:subscriptions)[:subscription_broadcastable]
|
|
240
240
|
end
|
|
241
241
|
|
|
242
|
+
# Called during execution when a new `subscription ...` operation is received
|
|
243
|
+
# @param query [GraphQL::Query]
|
|
244
|
+
# @return [void]
|
|
245
|
+
def initialize_subscriptions(query)
|
|
246
|
+
subs_namespace = query.context.namespace(:subscriptions)
|
|
247
|
+
subs_namespace[:events] = []
|
|
248
|
+
subs_namespace[:subscriptions] = {}
|
|
249
|
+
nil
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Called during execution when a subscription operation has finished
|
|
253
|
+
# @param query [GraphQL::Query]
|
|
254
|
+
# @return [void]
|
|
255
|
+
def finish_subscriptions(query)
|
|
256
|
+
if (events = query.context.namespace(:subscriptions)[:events]) && !events.empty?
|
|
257
|
+
write_subscription(query, events)
|
|
258
|
+
end
|
|
259
|
+
nil
|
|
260
|
+
end
|
|
261
|
+
|
|
242
262
|
private
|
|
243
263
|
|
|
244
264
|
# Recursively normalize `args` as belonging to `arg_owner`:
|
|
@@ -253,7 +253,7 @@ module GraphQL
|
|
|
253
253
|
packet = trace_packet(
|
|
254
254
|
type: TrackEvent::Type::TYPE_SLICE_BEGIN,
|
|
255
255
|
track_uuid: fid,
|
|
256
|
-
name: query.context.current_path
|
|
256
|
+
name: query.context.current_path&.join(".") || field.path,
|
|
257
257
|
category_iids: FIELD_EXECUTE_CATEGORY_IIDS,
|
|
258
258
|
extra_counter_track_uuids: @counts_objects,
|
|
259
259
|
extra_counter_values: [count_allocations],
|
|
@@ -269,7 +269,7 @@ module GraphQL
|
|
|
269
269
|
if @create_debug_annotations
|
|
270
270
|
start_field.track_event = dup_with(start_field.track_event,{
|
|
271
271
|
debug_annotations: [
|
|
272
|
-
payload_to_debug(nil, object.object, iid: DA_OBJECT_IID, intern_value: true),
|
|
272
|
+
payload_to_debug(nil, (object.is_a?(GraphQL::Schema::Object) ? object.object : object), iid: DA_OBJECT_IID, intern_value: true),
|
|
273
273
|
payload_to_debug(nil, arguments, iid: DA_ARGUMENTS_IID),
|
|
274
274
|
payload_to_debug(nil, app_result, iid: DA_RESULT_IID, intern_value: true)
|
|
275
275
|
]
|
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.5.
|
|
4
|
+
version: 2.5.23
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Mosolgo
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-03
|
|
10
|
+
date: 2026-04-03 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|
|
@@ -831,7 +831,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
831
831
|
- !ruby/object:Gem::Version
|
|
832
832
|
version: '0'
|
|
833
833
|
requirements: []
|
|
834
|
-
rubygems_version: 4.0.
|
|
834
|
+
rubygems_version: 4.0.6
|
|
835
835
|
specification_version: 4
|
|
836
836
|
summary: A GraphQL language and runtime for Ruby
|
|
837
837
|
test_files: []
|