graphql 2.5.7 → 2.5.8
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 +12 -5
- data/lib/graphql/query/partial.rb +70 -51
- data/lib/graphql/schema/directive.rb +21 -1
- data/lib/graphql/schema/input_object.rb +4 -0
- data/lib/graphql/schema/scalar.rb +1 -6
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/validator/required_validator.rb +3 -3
- data/lib/graphql/schema/visibility/profile.rb +1 -2
- data/lib/graphql/schema/warden.rb +3 -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: 35ee0d9a05997b264c746c531a4ff8d86ae9c8a4990523319da5ffafc9c89246
|
4
|
+
data.tar.gz: e68bf5323cff52c65403b4ed34a90de85a1f8b660d95cd43c167aeba2bce2d51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7233e64a37086b088d22609117498fcc12992472bde573a0a08b31d579121e9062759deac9ca22394273d28f914c04042dbbe53ba94a90859d0e82d75cc3c25a
|
7
|
+
data.tar.gz: bdeefc1210bcac49daef9670cfb53047c1d048e07ca2c68d6b31936e737f11314ac4cb6dbb6dc3063200f472379980fca42dfa997b44202ee56e5e1a6c525a9e
|
@@ -123,14 +123,14 @@ module GraphQL
|
|
123
123
|
case inner_type.kind.name
|
124
124
|
when "SCALAR", "ENUM"
|
125
125
|
result_name = ast_node.alias || ast_node.name
|
126
|
-
|
126
|
+
field_defn = query.field_definition
|
127
|
+
owner_type = field_defn.owner
|
127
128
|
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
128
129
|
selection_result.base_path = base_path
|
129
130
|
selection_result.ordered_result_keys = [result_name]
|
130
131
|
runtime_state = get_current_runtime_state
|
131
132
|
runtime_state.current_result = selection_result
|
132
133
|
runtime_state.current_result_name = result_name
|
133
|
-
field_defn = query.field_definition
|
134
134
|
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
135
135
|
if HALT != continue_value
|
136
136
|
continue_field(continue_value, owner_type, field_defn, root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
@@ -156,14 +156,14 @@ module GraphQL
|
|
156
156
|
end
|
157
157
|
when "SCALAR", "ENUM"
|
158
158
|
result_name = ast_node.alias || ast_node.name
|
159
|
-
|
160
|
-
|
159
|
+
field_defn = query.field_definition
|
160
|
+
owner_type = field_defn.owner
|
161
|
+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
161
162
|
selection_result.ordered_result_keys = [result_name]
|
162
163
|
selection_result.base_path = base_path
|
163
164
|
runtime_state = get_current_runtime_state
|
164
165
|
runtime_state.current_result = selection_result
|
165
166
|
runtime_state.current_result_name = result_name
|
166
|
-
field_defn = query.field_definition
|
167
167
|
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
168
168
|
if HALT != continue_value
|
169
169
|
continue_field(continue_value, owner_type, field_defn, query.root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
@@ -826,6 +826,13 @@ module GraphQL
|
|
826
826
|
else
|
827
827
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
828
828
|
raw_dir_args = arguments(nil, dir_defn, dir_node)
|
829
|
+
if !raw_dir_args.is_a?(GraphQL::ExecutionError)
|
830
|
+
begin
|
831
|
+
dir_defn.validate!(raw_dir_args, context)
|
832
|
+
rescue GraphQL::ExecutionError => err
|
833
|
+
raw_dir_args = err
|
834
|
+
end
|
835
|
+
end
|
829
836
|
dir_args = continue_value(
|
830
837
|
raw_dir_args, # value
|
831
838
|
nil, # field
|
@@ -18,7 +18,8 @@ module GraphQL
|
|
18
18
|
# @param object [Object] A starting object for execution
|
19
19
|
# @param query [GraphQL::Query] A full query instance that this partial is based on. Caches are shared.
|
20
20
|
# @param context [Hash] Extra context values to merge into `query.context`, if provided
|
21
|
-
|
21
|
+
# @param fragment_node [GraphQL::Language::Nodes::InlineFragment, GraphQL::Language::Nodes::FragmentDefinition]
|
22
|
+
def initialize(path: nil, object:, query:, context: nil, fragment_node: nil, type: nil)
|
22
23
|
@path = path
|
23
24
|
@object = object
|
24
25
|
@query = query
|
@@ -31,57 +32,18 @@ module GraphQL
|
|
31
32
|
@multiplex = nil
|
32
33
|
@result_values = nil
|
33
34
|
@result = nil
|
34
|
-
selections = [@query.selected_operation]
|
35
|
-
type = @query.root_type
|
36
|
-
parent_type = nil
|
37
|
-
field_defn = nil
|
38
|
-
@path.each do |name_in_doc|
|
39
|
-
if name_in_doc.is_a?(Integer)
|
40
|
-
if type.list?
|
41
|
-
type = type.unwrap
|
42
|
-
next
|
43
|
-
else
|
44
|
-
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
next_selections = []
|
49
|
-
selections.each do |selection|
|
50
|
-
selections_to_check = []
|
51
|
-
selections_to_check.concat(selection.selections)
|
52
|
-
while (sel = selections_to_check.shift)
|
53
|
-
case sel
|
54
|
-
when GraphQL::Language::Nodes::InlineFragment
|
55
|
-
selections_to_check.concat(sel.selections)
|
56
|
-
when GraphQL::Language::Nodes::FragmentSpread
|
57
|
-
fragment = @query.fragments[sel.name]
|
58
|
-
selections_to_check.concat(fragment.selections)
|
59
|
-
when GraphQL::Language::Nodes::Field
|
60
|
-
if sel.alias == name_in_doc || sel.name == name_in_doc
|
61
|
-
next_selections << sel
|
62
|
-
end
|
63
|
-
else
|
64
|
-
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
35
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
selections = next_selections
|
36
|
+
if fragment_node
|
37
|
+
@ast_nodes = [fragment_node]
|
38
|
+
@root_type = type || raise(ArgumentError, "Pass `type:` when using `node:`")
|
39
|
+
# This is only used when `@leaf`
|
40
|
+
@field_definition = nil
|
41
|
+
elsif path.nil?
|
42
|
+
raise ArgumentError, "`path:` is required if `node:` is not given; add `path:`"
|
43
|
+
else
|
44
|
+
set_type_info_from_path
|
80
45
|
end
|
81
|
-
|
82
|
-
@ast_nodes = selections
|
83
|
-
@root_type = type
|
84
|
-
@field_definition = field_defn
|
46
|
+
|
85
47
|
@leaf = @root_type.unwrap.kind.leaf?
|
86
48
|
end
|
87
49
|
|
@@ -89,7 +51,7 @@ module GraphQL
|
|
89
51
|
@leaf
|
90
52
|
end
|
91
53
|
|
92
|
-
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :
|
54
|
+
attr_reader :context, :query, :ast_nodes, :root_type, :object, :field_definition, :path, :schema
|
93
55
|
|
94
56
|
attr_accessor :multiplex, :result_values
|
95
57
|
|
@@ -155,6 +117,63 @@ module GraphQL
|
|
155
117
|
def selected_operation_name
|
156
118
|
@query.selected_operation_name
|
157
119
|
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def set_type_info_from_path
|
124
|
+
selections = [@query.selected_operation]
|
125
|
+
type = @query.root_type
|
126
|
+
parent_type = nil
|
127
|
+
field_defn = nil
|
128
|
+
|
129
|
+
@path.each do |name_in_doc|
|
130
|
+
if name_in_doc.is_a?(Integer)
|
131
|
+
if type.list?
|
132
|
+
type = type.unwrap
|
133
|
+
next
|
134
|
+
else
|
135
|
+
raise ArgumentError, "Received path with index `#{name_in_doc}`, but type wasn't a list. Type: #{type.to_type_signature}, path: #{@path}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
next_selections = []
|
140
|
+
selections.each do |selection|
|
141
|
+
selections_to_check = []
|
142
|
+
selections_to_check.concat(selection.selections)
|
143
|
+
while (sel = selections_to_check.shift)
|
144
|
+
case sel
|
145
|
+
when GraphQL::Language::Nodes::InlineFragment
|
146
|
+
selections_to_check.concat(sel.selections)
|
147
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
148
|
+
fragment = @query.fragments[sel.name]
|
149
|
+
selections_to_check.concat(fragment.selections)
|
150
|
+
when GraphQL::Language::Nodes::Field
|
151
|
+
if sel.alias == name_in_doc || sel.name == name_in_doc
|
152
|
+
next_selections << sel
|
153
|
+
end
|
154
|
+
else
|
155
|
+
raise "Unexpected selection in partial path: #{sel.class}, #{sel.inspect}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if next_selections.empty?
|
161
|
+
raise ArgumentError, "Path `#{@path.inspect}` is not present in this query. `#{name_in_doc.inspect}` was not found. Try a different path or rewrite the query to include it."
|
162
|
+
end
|
163
|
+
field_name = next_selections.first.name
|
164
|
+
field_defn = @schema.get_field(type, field_name, @query.context) || raise("Invariant: no field called #{field_name} on #{type.graphql_name}")
|
165
|
+
parent_type = type
|
166
|
+
type = field_defn.type
|
167
|
+
if type.non_null?
|
168
|
+
type = type.of_type
|
169
|
+
end
|
170
|
+
selections = next_selections
|
171
|
+
end
|
172
|
+
|
173
|
+
@ast_nodes = selections
|
174
|
+
@root_type = type
|
175
|
+
@field_definition = field_defn
|
176
|
+
end
|
158
177
|
end
|
159
178
|
end
|
160
179
|
end
|
@@ -9,6 +9,7 @@ module GraphQL
|
|
9
9
|
class Directive < GraphQL::Schema::Member
|
10
10
|
extend GraphQL::Schema::Member::HasArguments
|
11
11
|
extend GraphQL::Schema::Member::HasArguments::HasDirectiveArguments
|
12
|
+
extend GraphQL::Schema::Member::HasValidators
|
12
13
|
|
13
14
|
class << self
|
14
15
|
# Directives aren't types, they don't have kinds.
|
@@ -75,6 +76,10 @@ module GraphQL
|
|
75
76
|
yield
|
76
77
|
end
|
77
78
|
|
79
|
+
def validate!(arguments, context)
|
80
|
+
Schema::Validator.validate!(validators, self, context, arguments)
|
81
|
+
end
|
82
|
+
|
78
83
|
def on_field?
|
79
84
|
locations.include?(FIELD)
|
80
85
|
end
|
@@ -111,6 +116,9 @@ module GraphQL
|
|
111
116
|
# @return [GraphQL::Interpreter::Arguments]
|
112
117
|
attr_reader :arguments
|
113
118
|
|
119
|
+
class InvalidArgumentError < GraphQL::Error
|
120
|
+
end
|
121
|
+
|
114
122
|
def initialize(owner, **arguments)
|
115
123
|
@owner = owner
|
116
124
|
assert_valid_owner
|
@@ -119,7 +127,19 @@ module GraphQL
|
|
119
127
|
# - lazy resolution
|
120
128
|
# Probably, those won't be needed here, since these are configuration arguments,
|
121
129
|
# not runtime arguments.
|
122
|
-
|
130
|
+
context = Query::NullContext.instance
|
131
|
+
self.class.all_argument_definitions.each do |arg_defn|
|
132
|
+
value = arguments[arg_defn.keyword]
|
133
|
+
result = arg_defn.type.validate_input(value, context)
|
134
|
+
if !result.valid?
|
135
|
+
raise InvalidArgumentError, "@#{graphql_name}.#{arg_defn.graphql_name} on #{owner.path} is invalid (#{value.inspect}): #{result.problems.first["explanation"]}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
self.class.validate!(arguments, context)
|
139
|
+
@arguments = self.class.coerce_arguments(nil, arguments, context)
|
140
|
+
if @arguments.is_a?(GraphQL::ExecutionError)
|
141
|
+
raise @arguments
|
142
|
+
end
|
123
143
|
end
|
124
144
|
|
125
145
|
def graphql_name
|
@@ -182,6 +182,10 @@ module GraphQL
|
|
182
182
|
|
183
183
|
input.each do |argument_name, value|
|
184
184
|
argument = types.argument(self, argument_name)
|
185
|
+
if argument.nil? && ctx.is_a?(Query::NullContext) && argument_name.is_a?(Symbol)
|
186
|
+
# Validating definition directive arguments which come in as Symbols
|
187
|
+
argument = types.arguments(self).find { |arg| arg.keyword == argument_name }
|
188
|
+
end
|
185
189
|
# Items in the input that are unexpected
|
186
190
|
if argument.nil?
|
187
191
|
result ||= Query::InputValidationResult.new
|
@@ -50,12 +50,7 @@ module GraphQL
|
|
50
50
|
end
|
51
51
|
|
52
52
|
if coerced_result.nil?
|
53
|
-
|
54
|
-
""
|
55
|
-
else
|
56
|
-
" #{GraphQL::Language.serialize(value)}"
|
57
|
-
end
|
58
|
-
Query::InputValidationResult.from_problem("Could not coerce value#{str_value} to #{graphql_name}")
|
53
|
+
Query::InputValidationResult.from_problem("Could not coerce value #{GraphQL::Language.serialize(value)} to #{graphql_name}")
|
59
54
|
elsif coerced_result.is_a?(GraphQL::CoercionError)
|
60
55
|
Query::InputValidationResult.from_problem(coerced_result.message, message: coerced_result.message, extensions: coerced_result.extensions)
|
61
56
|
else
|
@@ -71,15 +71,23 @@ module GraphQL
|
|
71
71
|
def execute_field(query:, field:, **_rest)
|
72
72
|
timeout_state = query.context.namespace(@timeout).fetch(:state)
|
73
73
|
# If the `:state` is `false`, then `max_seconds(query)` opted out of timeout for this query.
|
74
|
-
if timeout_state
|
74
|
+
if timeout_state == false
|
75
|
+
super
|
76
|
+
elsif Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) > timeout_state.fetch(:timeout_at)
|
75
77
|
error = GraphQL::Schema::Timeout::TimeoutError.new(field)
|
76
78
|
# Only invoke the timeout callback for the first timeout
|
77
79
|
if !timeout_state[:timed_out]
|
78
80
|
timeout_state[:timed_out] = true
|
79
81
|
@timeout.handle_timeout(error, query)
|
82
|
+
timeout_state = query.context.namespace(@timeout).fetch(:state)
|
80
83
|
end
|
81
84
|
|
82
|
-
|
85
|
+
# `handle_timeout` may have set this to be `false`
|
86
|
+
if timeout_state != false
|
87
|
+
error
|
88
|
+
else
|
89
|
+
super
|
90
|
+
end
|
83
91
|
else
|
84
92
|
super
|
85
93
|
end
|
@@ -102,6 +110,15 @@ module GraphQL
|
|
102
110
|
# override to do something interesting
|
103
111
|
end
|
104
112
|
|
113
|
+
# Call this method (eg, from {#handle_timeout}) to disable timeout tracking
|
114
|
+
# for the given query.
|
115
|
+
# @param query [GraphQL::Query]
|
116
|
+
# @return [void]
|
117
|
+
def disable_timeout(query)
|
118
|
+
query.context.namespace(self)[:state] = false
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
105
122
|
# This error is raised when a query exceeds `max_seconds`.
|
106
123
|
# Since it's a child of {GraphQL::ExecutionError},
|
107
124
|
# its message will be added to the response's `errors` key.
|
@@ -99,10 +99,10 @@ module GraphQL
|
|
99
99
|
argument_definitions = @validated.arguments(context).values
|
100
100
|
required_names = @one_of.map do |arg_keyword|
|
101
101
|
if arg_keyword.is_a?(Array)
|
102
|
-
names = arg_keyword.map { |arg|
|
102
|
+
names = arg_keyword.map { |arg| arg_keyword_to_graphql_name(argument_definitions, arg) }
|
103
103
|
"(" + names.join(" and ") + ")"
|
104
104
|
else
|
105
|
-
|
105
|
+
arg_keyword_to_graphql_name(argument_definitions, arg_keyword)
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -113,7 +113,7 @@ module GraphQL
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
def
|
116
|
+
def arg_keyword_to_graphql_name(argument_definitions, arg_keyword)
|
117
117
|
argument_definition = argument_definitions.find { |defn| defn.keyword == arg_keyword }
|
118
118
|
argument_definition.graphql_name
|
119
119
|
end
|
@@ -232,7 +232,9 @@ module GraphQL
|
|
232
232
|
|
233
233
|
# @return [Boolean] True if this type is used for `loads:` but not in the schema otherwise and not _explicitly_ hidden.
|
234
234
|
def loadable?(type, _ctx)
|
235
|
-
|
235
|
+
visible_type?(type) &&
|
236
|
+
!referenced?(type) &&
|
237
|
+
(type.respond_to?(:interfaces) ? interfaces(type).all? { |i| loadable?(i, _ctx) } : true)
|
236
238
|
end
|
237
239
|
|
238
240
|
def loadable_possible_types(union_type, _ctx)
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-28 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: base64
|