graphql 2.5.22 → 2.5.24
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/analysis.rb +20 -13
- data/lib/graphql/execution/field_resolve_step.rb +631 -0
- data/lib/graphql/execution/finalize.rb +217 -0
- data/lib/graphql/execution/input_values.rb +261 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +6 -0
- 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/load_argument_step.rb +64 -0
- data/lib/graphql/execution/next.rb +26 -6
- data/lib/graphql/execution/prepare_object_step.rb +128 -0
- data/lib/graphql/execution/runner.rb +410 -0
- data/lib/graphql/execution/selections_step.rb +91 -0
- data/lib/graphql/execution.rb +8 -5
- data/lib/graphql/execution_error.rb +5 -1
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/partial.rb +18 -3
- data/lib/graphql/query.rb +10 -1
- data/lib/graphql/runtime_error.rb +6 -0
- data/lib/graphql/schema/directive.rb +23 -9
- data/lib/graphql/schema/field/connection_extension.rb +2 -15
- data/lib/graphql/schema/field/scope_extension.rb +0 -4
- data/lib/graphql/schema/field.rb +23 -24
- data/lib/graphql/schema/field_extension.rb +11 -41
- data/lib/graphql/schema/interface.rb +26 -0
- data/lib/graphql/schema/list.rb +5 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +0 -10
- 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/schema.rb +12 -10
- 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 +34 -10
- data/lib/graphql/subscriptions/event.rb +1 -0
- data/lib/graphql/subscriptions.rb +35 -0
- data/lib/graphql/tracing/perfetto_trace.rb +2 -2
- data/lib/graphql/tracing/trace.rb +6 -0
- data/lib/graphql/unauthorized_error.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -3
- metadata +11 -8
- data/lib/graphql/execution/next/field_resolve_step.rb +0 -711
- data/lib/graphql/execution/next/load_argument_step.rb +0 -60
- data/lib/graphql/execution/next/prepare_object_step.rb +0 -129
- data/lib/graphql/execution/next/runner.rb +0 -389
- data/lib/graphql/execution/next/selections_step.rb +0 -37
|
@@ -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
|
|
@@ -2,25 +2,49 @@
|
|
|
2
2
|
module GraphQL
|
|
3
3
|
class Subscriptions
|
|
4
4
|
class DefaultSubscriptionResolveExtension < GraphQL::Schema::FieldExtension
|
|
5
|
-
def resolve(context:, object
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
def resolve(context:, object: nil, objects: nil, arguments:)
|
|
6
|
+
if objects
|
|
7
|
+
has_override_implementation = @field.execution_mode != :direct_send
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
if !has_override_implementation
|
|
10
|
+
if context.query.subscription_update?
|
|
11
|
+
objects
|
|
12
|
+
else
|
|
13
|
+
objects.map { |o| context.skip }
|
|
14
|
+
end
|
|
12
15
|
else
|
|
13
|
-
|
|
16
|
+
yield(objects, arguments)
|
|
14
17
|
end
|
|
15
18
|
else
|
|
16
|
-
|
|
19
|
+
has_override_implementation = @field.resolver ||
|
|
20
|
+
object.respond_to?(@field.resolver_method)
|
|
21
|
+
|
|
22
|
+
if !has_override_implementation
|
|
23
|
+
if context.query.subscription_update?
|
|
24
|
+
object.object
|
|
25
|
+
else
|
|
26
|
+
context.skip
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
yield(object, arguments)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def after_resolve(values: nil, value: nil, context:, objects: nil, object: nil, arguments:, **rest)
|
|
35
|
+
if values
|
|
36
|
+
values.map do |value|
|
|
37
|
+
self.class.write_subscription(@field, value, arguments, context)
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
self.class.write_subscription(@field, value, arguments, context)
|
|
17
41
|
end
|
|
18
42
|
end
|
|
19
43
|
|
|
20
|
-
def
|
|
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,41 @@ 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
|
+
|
|
262
|
+
def finalizer
|
|
263
|
+
Finalizer.new(self)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
class Finalizer
|
|
267
|
+
include Execution::Finalizer
|
|
268
|
+
def initialize(subscriptions)
|
|
269
|
+
@subscriptions = subscriptions
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def finalize_graphql_result(query, result_data, result_key)
|
|
273
|
+
@subscriptions.finish_subscriptions(query)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
242
277
|
private
|
|
243
278
|
|
|
244
279
|
# 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
|
]
|
|
@@ -98,6 +98,12 @@ module GraphQL
|
|
|
98
98
|
yield
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
def objects(type, object, context)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def object_loaded(argument_definition, object, context)
|
|
105
|
+
end
|
|
106
|
+
|
|
101
107
|
# A call to `.authorized?` is starting
|
|
102
108
|
# @param type [Class<GraphQL::Schema::Object>]
|
|
103
109
|
# @param object [Object]
|
data/lib/graphql/version.rb
CHANGED
data/lib/graphql.rb
CHANGED
|
@@ -21,9 +21,6 @@ module GraphQL
|
|
|
21
21
|
class Error < StandardError
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
class RuntimeError < Error
|
|
25
|
-
end
|
|
26
|
-
|
|
27
24
|
# This error is raised when GraphQL-Ruby encounters a situation
|
|
28
25
|
# that it *thought* would never happen. Please report this bug!
|
|
29
26
|
class InvariantError < Error
|
|
@@ -122,6 +119,7 @@ This is probably a bug in GraphQL-Ruby, please report this error on GitHub: http
|
|
|
122
119
|
autoload :ParseError, "graphql/parse_error"
|
|
123
120
|
autoload :Backtrace, "graphql/backtrace"
|
|
124
121
|
|
|
122
|
+
autoload :RuntimeError, "graphql/runtime_error"
|
|
125
123
|
autoload :UnauthorizedError, "graphql/unauthorized_error"
|
|
126
124
|
autoload :UnauthorizedEnumValueError, "graphql/unauthorized_enum_value_error"
|
|
127
125
|
autoload :UnauthorizedFieldError, "graphql/unauthorized_field_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.5.
|
|
4
|
+
version: 2.5.24
|
|
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-04-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: base64
|
|
@@ -493,6 +493,9 @@ files:
|
|
|
493
493
|
- lib/graphql/execution.rb
|
|
494
494
|
- lib/graphql/execution/directive_checks.rb
|
|
495
495
|
- lib/graphql/execution/errors.rb
|
|
496
|
+
- lib/graphql/execution/field_resolve_step.rb
|
|
497
|
+
- lib/graphql/execution/finalize.rb
|
|
498
|
+
- lib/graphql/execution/input_values.rb
|
|
496
499
|
- lib/graphql/execution/interpreter.rb
|
|
497
500
|
- lib/graphql/execution/interpreter/argument_value.rb
|
|
498
501
|
- lib/graphql/execution/interpreter/arguments.rb
|
|
@@ -504,14 +507,13 @@ files:
|
|
|
504
507
|
- lib/graphql/execution/interpreter/runtime/graphql_result.rb
|
|
505
508
|
- lib/graphql/execution/lazy.rb
|
|
506
509
|
- lib/graphql/execution/lazy/lazy_method_map.rb
|
|
510
|
+
- lib/graphql/execution/load_argument_step.rb
|
|
507
511
|
- lib/graphql/execution/lookahead.rb
|
|
508
512
|
- lib/graphql/execution/multiplex.rb
|
|
509
513
|
- lib/graphql/execution/next.rb
|
|
510
|
-
- lib/graphql/execution/
|
|
511
|
-
- lib/graphql/execution/
|
|
512
|
-
- lib/graphql/execution/
|
|
513
|
-
- lib/graphql/execution/next/runner.rb
|
|
514
|
-
- lib/graphql/execution/next/selections_step.rb
|
|
514
|
+
- lib/graphql/execution/prepare_object_step.rb
|
|
515
|
+
- lib/graphql/execution/runner.rb
|
|
516
|
+
- lib/graphql/execution/selections_step.rb
|
|
515
517
|
- lib/graphql/execution_error.rb
|
|
516
518
|
- lib/graphql/integer_decoding_error.rb
|
|
517
519
|
- lib/graphql/integer_encoding_error.rb
|
|
@@ -577,6 +579,7 @@ files:
|
|
|
577
579
|
- lib/graphql/rubocop/graphql/default_required_true.rb
|
|
578
580
|
- lib/graphql/rubocop/graphql/field_type_in_block.rb
|
|
579
581
|
- lib/graphql/rubocop/graphql/root_types_in_block.rb
|
|
582
|
+
- lib/graphql/runtime_error.rb
|
|
580
583
|
- lib/graphql/runtime_type_error.rb
|
|
581
584
|
- lib/graphql/schema.rb
|
|
582
585
|
- lib/graphql/schema/addition.rb
|
|
@@ -831,7 +834,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
831
834
|
- !ruby/object:Gem::Version
|
|
832
835
|
version: '0'
|
|
833
836
|
requirements: []
|
|
834
|
-
rubygems_version: 4.0.
|
|
837
|
+
rubygems_version: 4.0.6
|
|
835
838
|
specification_version: 4
|
|
836
839
|
summary: A GraphQL language and runtime for Ruby
|
|
837
840
|
test_files: []
|