graphql 2.1.3 → 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/execution/interpreter/runtime.rb +7 -26
- data/lib/graphql/execution/lookahead.rb +87 -20
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/connection.rb +15 -10
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context.rb +4 -0
- data/lib/graphql/query/null_context.rb +2 -10
- data/lib/graphql/query.rb +10 -0
- data/lib/graphql/schema/build_from_definition.rb +0 -11
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +2 -2
- data/lib/graphql/schema/field/scope_extension.rb +4 -3
- data/lib/graphql/schema/field.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +2 -2
- data/lib/graphql/schema/input_object.rb +1 -1
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/loader.rb +0 -2
- data/lib/graphql/schema/member/has_arguments.rb +46 -38
- data/lib/graphql/schema/member/has_fields.rb +4 -4
- data/lib/graphql/schema/member/has_interfaces.rb +2 -2
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/resolver.rb +3 -3
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/warden.rb +10 -6
- data/lib/graphql/schema.rb +52 -10
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c20f3924267df0e3f7b2a0b65a642572677d6f5cb041c37a098f8bb0cfaa32e
|
4
|
+
data.tar.gz: 8dacd2476d5471297a82348551ea8e34429d14edef9dbb1c2c8f34073c18abfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1fb9466a19755ce3e7f0ee9693428d1b2e5c8017287909e624975e49727376729ec5fda28318953ec6fda606a693f842c1caad5419dc410938a59506c994fae
|
7
|
+
data.tar.gz: d048fc02aece1781f4d15a700bc2cde8c1baf929917f35a9ae23567d5f720dabd5f4d18e47e3b8af2d9d6ecc6dde146f750a08b28de9fef769a960dc60ac0444
|
@@ -52,13 +52,6 @@ module GraphQL
|
|
52
52
|
# { Class => Boolean }
|
53
53
|
@lazy_cache = {}
|
54
54
|
@lazy_cache.compare_by_identity
|
55
|
-
|
56
|
-
@gathered_selections_cache = Hash.new { |h, k|
|
57
|
-
cache = {}
|
58
|
-
cache.compare_by_identity
|
59
|
-
h[k] = cache
|
60
|
-
}
|
61
|
-
@gathered_selections_cache.compare_by_identity
|
62
55
|
end
|
63
56
|
|
64
57
|
def final_result
|
@@ -98,7 +91,7 @@ module GraphQL
|
|
98
91
|
@response = nil
|
99
92
|
else
|
100
93
|
call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
|
101
|
-
gathered_selections = gather_selections(runtime_object, root_type,
|
94
|
+
gathered_selections = gather_selections(runtime_object, root_type, root_operation.selections)
|
102
95
|
# This is kind of a hack -- `gathered_selections` is an Array if any of the selections
|
103
96
|
# require isolation during execution (because of runtime directives). In that case,
|
104
97
|
# make a new, isolated result hash for writing the result into. (That isolated response
|
@@ -143,18 +136,11 @@ module GraphQL
|
|
143
136
|
nil
|
144
137
|
end
|
145
138
|
|
146
|
-
def gather_selections(owner_object, owner_type,
|
147
|
-
if ast_node_for_caching && (cached_selections = @gathered_selections_cache[ast_node_for_caching][owner_type])
|
148
|
-
return cached_selections
|
149
|
-
end
|
150
|
-
selections_by_name ||= {} # allocate this default here so we check the cache first
|
151
|
-
|
152
|
-
should_cache = true
|
139
|
+
def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
|
153
140
|
|
154
141
|
selections.each do |node|
|
155
142
|
# Skip gathering this if the directive says so
|
156
143
|
if !directives_include?(node, owner_object, owner_type)
|
157
|
-
should_cache = false
|
158
144
|
next
|
159
145
|
end
|
160
146
|
|
@@ -179,7 +165,6 @@ module GraphQL
|
|
179
165
|
if @runtime_directive_names.any? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
180
166
|
next_selections = {}
|
181
167
|
next_selections[:graphql_directives] = node.directives
|
182
|
-
should_cache = false
|
183
168
|
if selections_to_run
|
184
169
|
selections_to_run << next_selections
|
185
170
|
else
|
@@ -197,28 +182,24 @@ module GraphQL
|
|
197
182
|
type_defn = schema.get_type(node.type.name, context)
|
198
183
|
|
199
184
|
if query.warden.possible_types(type_defn).include?(owner_type)
|
200
|
-
gather_selections(owner_object, owner_type,
|
185
|
+
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
201
186
|
end
|
202
187
|
else
|
203
188
|
# it's an untyped fragment, definitely continue
|
204
|
-
gather_selections(owner_object, owner_type,
|
189
|
+
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
205
190
|
end
|
206
191
|
when GraphQL::Language::Nodes::FragmentSpread
|
207
192
|
fragment_def = query.fragments[node.name]
|
208
193
|
type_defn = query.get_type(fragment_def.type.name)
|
209
194
|
if query.warden.possible_types(type_defn).include?(owner_type)
|
210
|
-
gather_selections(owner_object, owner_type,
|
195
|
+
gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
211
196
|
end
|
212
197
|
else
|
213
198
|
raise "Invariant: unexpected selection class: #{node.class}"
|
214
199
|
end
|
215
200
|
end
|
216
201
|
end
|
217
|
-
|
218
|
-
if should_cache
|
219
|
-
@gathered_selections_cache[ast_node_for_caching][owner_type] = result
|
220
|
-
end
|
221
|
-
result
|
202
|
+
selections_to_run || selections_by_name
|
222
203
|
end
|
223
204
|
|
224
205
|
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
@@ -619,7 +600,7 @@ module GraphQL
|
|
619
600
|
response_hash = GraphQLResultHash.new(result_name, selection_result, is_non_null)
|
620
601
|
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
621
602
|
|
622
|
-
gathered_selections = gather_selections(continue_value, current_type,
|
603
|
+
gathered_selections = gather_selections(continue_value, current_type, next_selections)
|
623
604
|
# There are two possibilities for `gathered_selections`:
|
624
605
|
# 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
|
625
606
|
# This case is handled below, and the result can be written right into the main `response_hash` above.
|
@@ -80,6 +80,22 @@ module GraphQL
|
|
80
80
|
selection(field_name, selected_type: selected_type, arguments: arguments).selected?
|
81
81
|
end
|
82
82
|
|
83
|
+
# True if this node has a selection with alias matching `alias_name`.
|
84
|
+
# If `alias_name` is a String, it is treated as a GraphQL-style (camelized)
|
85
|
+
# field name and used verbatim. If `alias_name` is a Symbol, it is
|
86
|
+
# treated as a Ruby-style (underscored) name and camelized before comparing.
|
87
|
+
#
|
88
|
+
# If `arguments:` is provided, each provided key/value will be matched
|
89
|
+
# against the arguments in the next selection. This method will return false
|
90
|
+
# if any of the given `arguments:` are not present and matching in the next selection.
|
91
|
+
# (But, the next selection may contain _more_ than the given arguments.)
|
92
|
+
# @param alias_name [String, Symbol]
|
93
|
+
# @param arguments [Hash] Arguments which must match in the selection
|
94
|
+
# @return [Boolean]
|
95
|
+
def selects_alias?(alias_name, arguments: nil)
|
96
|
+
alias_selection(alias_name, arguments: arguments).selected?
|
97
|
+
end
|
98
|
+
|
83
99
|
# @return [Boolean] True if this lookahead represents a field that was requested
|
84
100
|
def selected?
|
85
101
|
true
|
@@ -105,6 +121,7 @@ module GraphQL
|
|
105
121
|
.tap(&:flatten!)
|
106
122
|
end
|
107
123
|
|
124
|
+
|
108
125
|
if (match_by_orig_name = all_fields.find { |f| f.original_name == field_name })
|
109
126
|
match_by_orig_name
|
110
127
|
else
|
@@ -114,23 +131,29 @@ module GraphQL
|
|
114
131
|
@query.get_field(selected_type, guessed_name)
|
115
132
|
end
|
116
133
|
end
|
134
|
+
lookahead_for_selection(next_field_defn, selected_type, arguments)
|
135
|
+
end
|
117
136
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
137
|
+
# Like {#selection}, but for aliases.
|
138
|
+
# It returns a null object (check with {#selected?})
|
139
|
+
# @return [GraphQL::Execution::Lookahead]
|
140
|
+
def alias_selection(alias_name, selected_type: @selected_type, arguments: nil)
|
141
|
+
alias_cache_key = [alias_name, arguments]
|
142
|
+
return alias_selections[key] if alias_selections.key?(alias_name)
|
125
143
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
144
|
+
alias_node = lookup_alias_node(ast_nodes, alias_name)
|
145
|
+
return NULL_LOOKAHEAD unless alias_node
|
146
|
+
|
147
|
+
next_field_defn = @query.get_field(selected_type, alias_node.name)
|
148
|
+
|
149
|
+
alias_arguments = @query.arguments_for(alias_node, next_field_defn)
|
150
|
+
if alias_arguments.is_a?(::GraphQL::Execution::Interpreter::Arguments)
|
151
|
+
alias_arguments = alias_arguments.keyword_arguments
|
133
152
|
end
|
153
|
+
|
154
|
+
return NULL_LOOKAHEAD if arguments && arguments != alias_arguments
|
155
|
+
|
156
|
+
alias_selections[alias_cache_key] = lookahead_for_selection(next_field_defn, selected_type, alias_arguments, alias_name)
|
134
157
|
end
|
135
158
|
|
136
159
|
# Like {#selection}, but for all nodes.
|
@@ -258,7 +281,7 @@ module GraphQL
|
|
258
281
|
end
|
259
282
|
find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
|
260
283
|
when GraphQL::Language::Nodes::FragmentSpread
|
261
|
-
frag_defn =
|
284
|
+
frag_defn = lookup_fragment(ast_selection)
|
262
285
|
# Again, assuming a valid AST
|
263
286
|
on_type = @query.get_type(frag_defn.type.name)
|
264
287
|
subselections_on_type = subselections_by_type[on_type] ||= {}
|
@@ -271,11 +294,11 @@ module GraphQL
|
|
271
294
|
|
272
295
|
# If a selection on `node` matches `field_name` (which is backed by `field_defn`)
|
273
296
|
# and matches the `arguments:` constraints, then add that node to `matches`
|
274
|
-
def find_selected_nodes(node, field_defn, arguments:, matches:)
|
297
|
+
def find_selected_nodes(node, field_name, field_defn, arguments:, matches:, alias_name: NOT_CONFIGURED)
|
275
298
|
return if skipped_by_directive?(node)
|
276
299
|
case node
|
277
300
|
when GraphQL::Language::Nodes::Field
|
278
|
-
if node.name ==
|
301
|
+
if node.name == field_name && (NOT_CONFIGURED.equal?(alias_name) || node.alias == alias_name)
|
279
302
|
if arguments.nil? || arguments.empty?
|
280
303
|
# No constraint applied
|
281
304
|
matches << node
|
@@ -284,10 +307,10 @@ module GraphQL
|
|
284
307
|
end
|
285
308
|
end
|
286
309
|
when GraphQL::Language::Nodes::InlineFragment
|
287
|
-
node.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
|
310
|
+
node.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches, alias_name: alias_name) }
|
288
311
|
when GraphQL::Language::Nodes::FragmentSpread
|
289
|
-
frag_defn =
|
290
|
-
frag_defn.selections.each { |s| find_selected_nodes(s, field_defn, arguments: arguments, matches: matches) }
|
312
|
+
frag_defn = lookup_fragment(node)
|
313
|
+
frag_defn.selections.each { |s| find_selected_nodes(s, field_name, field_defn, arguments: arguments, matches: matches, alias_name: alias_name) }
|
291
314
|
else
|
292
315
|
raise "Unexpected selection comparison on #{node.class.name} (#{node})"
|
293
316
|
end
|
@@ -306,6 +329,50 @@ module GraphQL
|
|
306
329
|
query_kwargs.key?(arg_name_sym) && query_kwargs[arg_name_sym] == arg_value
|
307
330
|
end
|
308
331
|
end
|
332
|
+
|
333
|
+
def lookahead_for_selection(field_defn, selected_type, arguments, alias_name = NOT_CONFIGURED)
|
334
|
+
return NULL_LOOKAHEAD unless field_defn
|
335
|
+
|
336
|
+
next_nodes = []
|
337
|
+
field_name = field_defn.name
|
338
|
+
@ast_nodes.each do |ast_node|
|
339
|
+
ast_node.selections.each do |selection|
|
340
|
+
find_selected_nodes(selection, field_name, field_defn, arguments: arguments, matches: next_nodes, alias_name: alias_name)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
return NULL_LOOKAHEAD if next_nodes.empty?
|
345
|
+
|
346
|
+
Lookahead.new(query: @query, ast_nodes: next_nodes, field: field_defn, owner_type: selected_type)
|
347
|
+
end
|
348
|
+
|
349
|
+
def alias_selections
|
350
|
+
return @alias_selections if defined?(@alias_selections)
|
351
|
+
@alias_selections ||= {}
|
352
|
+
end
|
353
|
+
|
354
|
+
def lookup_alias_node(nodes, name)
|
355
|
+
return if nodes.empty?
|
356
|
+
|
357
|
+
nodes.flat_map(&:children)
|
358
|
+
.flat_map { |child| unwrap_fragments(child) }
|
359
|
+
.find { |child| child.is_a?(GraphQL::Language::Nodes::Field) && child.alias == name }
|
360
|
+
end
|
361
|
+
|
362
|
+
def unwrap_fragments(node)
|
363
|
+
case node
|
364
|
+
when GraphQL::Language::Nodes::InlineFragment
|
365
|
+
node.children
|
366
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
367
|
+
lookup_fragment(node).children
|
368
|
+
else
|
369
|
+
[node]
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def lookup_fragment(ast_selection)
|
374
|
+
@query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
|
375
|
+
end
|
309
376
|
end
|
310
377
|
end
|
311
378
|
end
|
@@ -12,10 +12,14 @@ module GraphQL
|
|
12
12
|
attr_reader :id
|
13
13
|
# @return [Object] The value found with this ID
|
14
14
|
attr_reader :object
|
15
|
-
|
15
|
+
# @return [GraphQL::Query::Context]
|
16
|
+
attr_reader :context
|
17
|
+
|
18
|
+
def initialize(argument:, id:, object:, context:)
|
16
19
|
@id = id
|
17
20
|
@argument = argument
|
18
21
|
@object = object
|
22
|
+
@context = context
|
19
23
|
super("No object found for `#{argument.graphql_name}: #{id.inspect}`")
|
20
24
|
end
|
21
25
|
end
|
@@ -22,10 +22,11 @@ module GraphQL
|
|
22
22
|
attr_reader :context
|
23
23
|
|
24
24
|
def context=(new_ctx)
|
25
|
-
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
26
|
-
query_runtime_state = current_runtime_state[new_ctx.query]
|
27
|
-
@was_authorized_by_scope_items = query_runtime_state.was_authorized_by_scope_items
|
28
25
|
@context = new_ctx
|
26
|
+
if @was_authorized_by_scope_items.nil?
|
27
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
28
|
+
end
|
29
|
+
@context
|
29
30
|
end
|
30
31
|
|
31
32
|
# @return [Object] the object this collection belongs to
|
@@ -90,13 +91,7 @@ module GraphQL
|
|
90
91
|
else
|
91
92
|
default_page_size
|
92
93
|
end
|
93
|
-
@was_authorized_by_scope_items =
|
94
|
-
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
95
|
-
query_runtime_state = current_runtime_state[@context.query]
|
96
|
-
query_runtime_state.was_authorized_by_scope_items
|
97
|
-
else
|
98
|
-
nil
|
99
|
-
end
|
94
|
+
@was_authorized_by_scope_items = detect_was_authorized_by_scope_items
|
100
95
|
end
|
101
96
|
|
102
97
|
def was_authorized_by_scope_items?
|
@@ -226,6 +221,16 @@ module GraphQL
|
|
226
221
|
|
227
222
|
private
|
228
223
|
|
224
|
+
def detect_was_authorized_by_scope_items
|
225
|
+
if @context &&
|
226
|
+
(current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
227
|
+
(query_runtime_state = current_runtime_state[@context.query])
|
228
|
+
query_runtime_state.was_authorized_by_scope_items
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
229
234
|
# @param argument [nil, Integer] `first` or `last`, as provided by the client
|
230
235
|
# @param max_page_size [nil, Integer]
|
231
236
|
# @return [nil, Integer] `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`
|
@@ -13,8 +13,7 @@ module GraphQL
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def relation_count(relation)
|
16
|
-
|
17
|
-
relation.to_a.count
|
16
|
+
relation.all.count(relation.options.slice(:limit, :skip))
|
18
17
|
end
|
19
18
|
|
20
19
|
def null_relation(relation)
|
@@ -3,6 +3,8 @@ module GraphQL
|
|
3
3
|
class Query
|
4
4
|
# This object can be `ctx` in places where there is no query
|
5
5
|
class NullContext
|
6
|
+
include Singleton
|
7
|
+
|
6
8
|
class NullQuery
|
7
9
|
def after_lazy(value)
|
8
10
|
yield(value)
|
@@ -27,16 +29,6 @@ module GraphQL
|
|
27
29
|
def interpreter?
|
28
30
|
true
|
29
31
|
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
extend Forwardable
|
33
|
-
|
34
|
-
def instance
|
35
|
-
@instance ||= self.new
|
36
|
-
end
|
37
|
-
|
38
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
|
39
|
-
end
|
40
32
|
end
|
41
33
|
end
|
42
34
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -162,6 +162,14 @@ module GraphQL
|
|
162
162
|
|
163
163
|
@result_values = nil
|
164
164
|
@executed = false
|
165
|
+
|
166
|
+
@logger = if context && context[:logger] == false
|
167
|
+
Logger.new(IO::NULL)
|
168
|
+
elsif context && (l = context[:logger])
|
169
|
+
l
|
170
|
+
else
|
171
|
+
schema.default_logger
|
172
|
+
end
|
165
173
|
end
|
166
174
|
|
167
175
|
# If a document was provided to `GraphQL::Schema#execute` instead of the raw query string, we will need to get it from the document
|
@@ -369,6 +377,8 @@ module GraphQL
|
|
369
377
|
end
|
370
378
|
end
|
371
379
|
|
380
|
+
attr_reader :logger
|
381
|
+
|
372
382
|
private
|
373
383
|
|
374
384
|
def find_operation(operations, operation_name)
|
@@ -432,14 +432,12 @@ module GraphQL
|
|
432
432
|
builder = self
|
433
433
|
|
434
434
|
field_definitions.each do |field_definition|
|
435
|
-
type_name = resolve_type_name(field_definition.type)
|
436
435
|
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
437
436
|
schema_field_defn = owner.field(
|
438
437
|
field_definition.name,
|
439
438
|
description: field_definition.description,
|
440
439
|
type: type_resolver.call(field_definition.type),
|
441
440
|
null: true,
|
442
|
-
connection: type_name.end_with?("Connection"),
|
443
441
|
connection_extension: nil,
|
444
442
|
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
445
443
|
ast_node: field_definition,
|
@@ -487,15 +485,6 @@ module GraphQL
|
|
487
485
|
}
|
488
486
|
resolve_type_proc
|
489
487
|
end
|
490
|
-
|
491
|
-
def resolve_type_name(type)
|
492
|
-
case type
|
493
|
-
when GraphQL::Language::Nodes::TypeName
|
494
|
-
return type.name
|
495
|
-
else
|
496
|
-
resolve_type_name(type.of_type)
|
497
|
-
end
|
498
|
-
end
|
499
488
|
end
|
500
489
|
|
501
490
|
private_constant :Builder
|
@@ -6,6 +6,18 @@ module GraphQL
|
|
6
6
|
description "Requires that exactly one field must be supplied and that field must not be `null`."
|
7
7
|
locations(GraphQL::Schema::Directive::INPUT_OBJECT)
|
8
8
|
default_directive true
|
9
|
+
|
10
|
+
def initialize(...)
|
11
|
+
super
|
12
|
+
|
13
|
+
owner.extend(IsOneOf)
|
14
|
+
end
|
15
|
+
|
16
|
+
module IsOneOf
|
17
|
+
def one_of?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
9
21
|
end
|
10
22
|
end
|
11
23
|
end
|
@@ -119,7 +119,7 @@ module GraphQL
|
|
119
119
|
# - lazy resolution
|
120
120
|
# Probably, those won't be needed here, since these are configuration arguments,
|
121
121
|
# not runtime arguments.
|
122
|
-
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
|
122
|
+
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext.instance)
|
123
123
|
end
|
124
124
|
|
125
125
|
def graphql_name
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -68,7 +68,7 @@ module GraphQL
|
|
68
68
|
end
|
69
69
|
|
70
70
|
# @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
|
71
|
-
def enum_values(context = GraphQL::Query::NullContext)
|
71
|
+
def enum_values(context = GraphQL::Query::NullContext.instance)
|
72
72
|
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
|
73
73
|
visible_values = []
|
74
74
|
warden = Warden.from_context(context)
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
end
|
111
111
|
|
112
112
|
# @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
|
113
|
-
def values(context = GraphQL::Query::NullContext)
|
113
|
+
def values(context = GraphQL::Query::NullContext.instance)
|
114
114
|
enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
|
115
115
|
end
|
116
116
|
|
@@ -12,9 +12,10 @@ module GraphQL
|
|
12
12
|
if ret_type.respond_to?(:scope_items)
|
13
13
|
scoped_items = ret_type.scope_items(value, context)
|
14
14
|
if !scoped_items.equal?(value) && !ret_type.reauthorize_scoped_objects
|
15
|
-
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
16
|
-
|
17
|
-
|
15
|
+
if (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
16
|
+
(query_runtime_state = current_runtime_state[context.query])
|
17
|
+
query_runtime_state.was_authorized_by_scope_items = true
|
18
|
+
end
|
18
19
|
end
|
19
20
|
scoped_items
|
20
21
|
else
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -138,7 +138,7 @@ module GraphQL
|
|
138
138
|
# As a last ditch, try to force loading the return type:
|
139
139
|
type.unwrap.name
|
140
140
|
end
|
141
|
-
@connection = return_type_name.end_with?("Connection")
|
141
|
+
@connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
|
142
142
|
else
|
143
143
|
@connection
|
144
144
|
end
|
@@ -54,11 +54,11 @@ module GraphQL
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
57
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
58
58
|
dummy.arguments(context)
|
59
59
|
end
|
60
60
|
|
61
|
-
def get_field_argument(name, context = GraphQL::Query::NullContext)
|
61
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
62
62
|
dummy.get_argument(name, context)
|
63
63
|
end
|
64
64
|
|
@@ -20,6 +20,15 @@ module GraphQL
|
|
20
20
|
# - Added as class methods to this interface
|
21
21
|
# - Added as class methods to all child interfaces
|
22
22
|
def definition_methods(&block)
|
23
|
+
# Use an instance variable to tell whether it's been included previously or not;
|
24
|
+
# You can't use constant detection because constants are brought into scope
|
25
|
+
# by `include`, which has already happened at this point.
|
26
|
+
if !defined?(@_definition_methods)
|
27
|
+
defn_methods_module = Module.new
|
28
|
+
@_definition_methods = defn_methods_module
|
29
|
+
const_set(:DefinitionMethods, defn_methods_module)
|
30
|
+
extend(self::DefinitionMethods)
|
31
|
+
end
|
23
32
|
self::DefinitionMethods.module_eval(&block)
|
24
33
|
end
|
25
34
|
|
@@ -47,20 +56,11 @@ module GraphQL
|
|
47
56
|
|
48
57
|
child_class.type_membership_class(self.type_membership_class)
|
49
58
|
child_class.ancestors.reverse_each do |ancestor|
|
50
|
-
if ancestor.const_defined?(:DefinitionMethods)
|
59
|
+
if ancestor.const_defined?(:DefinitionMethods) && ancestor != child_class
|
51
60
|
child_class.extend(ancestor::DefinitionMethods)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
# Use an instance variable to tell whether it's been included previously or not;
|
56
|
-
# You can't use constant detection because constants are brought into scope
|
57
|
-
# by `include`, which has already happened at this point.
|
58
|
-
if !child_class.instance_variable_defined?(:@_definition_methods)
|
59
|
-
defn_methods_module = Module.new
|
60
|
-
child_class.instance_variable_set(:@_definition_methods, defn_methods_module)
|
61
|
-
child_class.const_set(:DefinitionMethods, defn_methods_module)
|
62
|
-
child_class.extend(child_class::DefinitionMethods)
|
63
|
-
end
|
64
64
|
child_class.introspection(introspection)
|
65
65
|
child_class.description(description)
|
66
66
|
# If interfaces are mixed into each other, only define this class once
|
@@ -176,7 +176,6 @@ module GraphQL
|
|
176
176
|
while (of_type = unwrapped_field_hash["ofType"])
|
177
177
|
unwrapped_field_hash = of_type
|
178
178
|
end
|
179
|
-
type_name = unwrapped_field_hash["name"]
|
180
179
|
|
181
180
|
type_defn.field(
|
182
181
|
field_hash["name"],
|
@@ -186,7 +185,6 @@ module GraphQL
|
|
186
185
|
null: true,
|
187
186
|
camelize: false,
|
188
187
|
connection_extension: nil,
|
189
|
-
connection: type_name.end_with?("Connection"),
|
190
188
|
) do
|
191
189
|
if field_hash["args"].any?
|
192
190
|
loader.build_arguments(self, field_hash["args"], type_resolver)
|
@@ -109,7 +109,7 @@ module GraphQL
|
|
109
109
|
end
|
110
110
|
|
111
111
|
# @return [Hash<String => GraphQL::Schema::Argument] Arguments defined on this thing, keyed by name. Includes inherited definitions
|
112
|
-
def arguments(context = GraphQL::Query::NullContext)
|
112
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
113
113
|
if own_arguments.any?
|
114
114
|
own_arguments_that_apply = {}
|
115
115
|
own_arguments.each do |name, args_entry|
|
@@ -133,7 +133,7 @@ module GraphQL
|
|
133
133
|
end
|
134
134
|
|
135
135
|
module InheritedArguments
|
136
|
-
def arguments(context = GraphQL::Query::NullContext)
|
136
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
137
137
|
own_arguments = super
|
138
138
|
inherited_arguments = superclass.arguments(context)
|
139
139
|
|
@@ -166,7 +166,7 @@ module GraphQL
|
|
166
166
|
end
|
167
167
|
|
168
168
|
|
169
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
169
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
170
170
|
warden = Warden.from_context(context)
|
171
171
|
for ancestor in ancestors
|
172
172
|
if ancestor.respond_to?(:own_arguments) &&
|
@@ -181,7 +181,7 @@ module GraphQL
|
|
181
181
|
end
|
182
182
|
|
183
183
|
module FieldConfigured
|
184
|
-
def arguments(context = GraphQL::Query::NullContext)
|
184
|
+
def arguments(context = GraphQL::Query::NullContext.instance)
|
185
185
|
own_arguments = super
|
186
186
|
if @resolver_class
|
187
187
|
inherited_arguments = @resolver_class.field_arguments(context)
|
@@ -236,7 +236,7 @@ module GraphQL
|
|
236
236
|
end
|
237
237
|
|
238
238
|
# @return [GraphQL::Schema::Argument, nil] Argument defined on this thing, fetched by name.
|
239
|
-
def get_argument(argument_name, context = GraphQL::Query::NullContext)
|
239
|
+
def get_argument(argument_name, context = GraphQL::Query::NullContext.instance)
|
240
240
|
warden = Warden.from_context(context)
|
241
241
|
if (arg_config = own_arguments[argument_name]) && (visible_arg = Warden.visible_entry?(:visible_argument?, arg_config, context, warden))
|
242
242
|
visible_arg
|
@@ -379,44 +379,52 @@ module GraphQL
|
|
379
379
|
def authorize_application_object(argument, id, context, loaded_application_object)
|
380
380
|
context.query.after_lazy(loaded_application_object) do |application_object|
|
381
381
|
if application_object.nil?
|
382
|
-
err = GraphQL::LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
383
|
-
load_application_object_failed(err)
|
382
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
383
|
+
application_object = load_application_object_failed(err)
|
384
384
|
end
|
385
385
|
# Double-check that the located object is actually of this type
|
386
386
|
# (Don't want to allow arbitrary access to objects this way)
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
387
|
+
if application_object.nil?
|
388
|
+
nil
|
389
|
+
else
|
390
|
+
maybe_lazy_resolve_type = context.schema.resolve_type(argument.loads, application_object, context)
|
391
|
+
context.query.after_lazy(maybe_lazy_resolve_type) do |resolve_type_result|
|
392
|
+
if resolve_type_result.is_a?(Array) && resolve_type_result.size == 2
|
393
|
+
application_object_type, application_object = resolve_type_result
|
394
|
+
else
|
395
|
+
application_object_type = resolve_type_result
|
396
|
+
# application_object is already assigned
|
397
|
+
end
|
395
398
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
context: context,
|
414
|
-
)
|
415
|
-
if self.respond_to?(:unauthorized_object)
|
416
|
-
err.set_backtrace(caller)
|
417
|
-
unauthorized_object(err)
|
399
|
+
if !(
|
400
|
+
context.warden.possible_types(argument.loads).include?(application_object_type) ||
|
401
|
+
context.warden.loadable?(argument.loads, context)
|
402
|
+
)
|
403
|
+
err = GraphQL::LoadApplicationObjectFailedError.new(context: context, argument: argument, id: id, object: application_object)
|
404
|
+
application_object = load_application_object_failed(err)
|
405
|
+
end
|
406
|
+
|
407
|
+
if application_object.nil?
|
408
|
+
nil
|
409
|
+
else
|
410
|
+
# This object was loaded successfully
|
411
|
+
# and resolved to the right type,
|
412
|
+
# now apply the `.authorized?` class method if there is one
|
413
|
+
context.query.after_lazy(application_object_type.authorized?(application_object, context)) do |authed|
|
414
|
+
if authed
|
415
|
+
application_object
|
418
416
|
else
|
419
|
-
|
417
|
+
err = GraphQL::UnauthorizedError.new(
|
418
|
+
object: application_object,
|
419
|
+
type: application_object_type,
|
420
|
+
context: context,
|
421
|
+
)
|
422
|
+
if self.respond_to?(:unauthorized_object)
|
423
|
+
err.set_backtrace(caller)
|
424
|
+
unauthorized_object(err)
|
425
|
+
else
|
426
|
+
raise err
|
427
|
+
end
|
420
428
|
end
|
421
429
|
end
|
422
430
|
end
|
@@ -97,7 +97,7 @@ module GraphQL
|
|
97
97
|
end
|
98
98
|
|
99
99
|
module InterfaceMethods
|
100
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
100
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
101
101
|
warden = Warden.from_context(context)
|
102
102
|
for ancestor in ancestors
|
103
103
|
if ancestor.respond_to?(:own_fields) &&
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
end
|
111
111
|
|
112
112
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
113
|
-
def fields(context = GraphQL::Query::NullContext)
|
113
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
114
114
|
warden = Warden.from_context(context)
|
115
115
|
# Local overrides take precedence over inherited fields
|
116
116
|
visible_fields = {}
|
@@ -130,7 +130,7 @@ module GraphQL
|
|
130
130
|
end
|
131
131
|
|
132
132
|
module ObjectMethods
|
133
|
-
def get_field(field_name, context = GraphQL::Query::NullContext)
|
133
|
+
def get_field(field_name, context = GraphQL::Query::NullContext.instance)
|
134
134
|
# Objects need to check that the interface implementation is visible, too
|
135
135
|
warden = Warden.from_context(context)
|
136
136
|
ancs = ancestors
|
@@ -148,7 +148,7 @@ module GraphQL
|
|
148
148
|
end
|
149
149
|
|
150
150
|
# @return [Hash<String => GraphQL::Schema::Field>] Fields on this object, keyed by name, including inherited fields
|
151
|
-
def fields(context = GraphQL::Query::NullContext)
|
151
|
+
def fields(context = GraphQL::Query::NullContext.instance)
|
152
152
|
# Objects need to check that the interface implementation is visible, too
|
153
153
|
warden = Warden.from_context(context)
|
154
154
|
# Local overrides take precedence over inherited fields
|
@@ -70,7 +70,7 @@ module GraphQL
|
|
70
70
|
end
|
71
71
|
|
72
72
|
module InheritedInterfaces
|
73
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
73
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
74
74
|
visible_interfaces = super
|
75
75
|
inherited_interfaces = superclass.interfaces(context)
|
76
76
|
if visible_interfaces.any?
|
@@ -99,7 +99,7 @@ module GraphQL
|
|
99
99
|
end
|
100
100
|
|
101
101
|
# param context [Query::Context] If omitted, skip filtering.
|
102
|
-
def interfaces(context = GraphQL::Query::NullContext)
|
102
|
+
def interfaces(context = GraphQL::Query::NullContext.instance)
|
103
103
|
warden = Warden.from_context(context)
|
104
104
|
visible_interfaces = nil
|
105
105
|
own_interface_type_memberships.each do |type_membership|
|
@@ -17,15 +17,15 @@ module GraphQL
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def valid_isolated_input?(v)
|
20
|
-
valid_input?(v, GraphQL::Query::NullContext)
|
20
|
+
valid_input?(v, GraphQL::Query::NullContext.instance)
|
21
21
|
end
|
22
22
|
|
23
23
|
def coerce_isolated_input(v)
|
24
|
-
coerce_input(v, GraphQL::Query::NullContext)
|
24
|
+
coerce_input(v, GraphQL::Query::NullContext.instance)
|
25
25
|
end
|
26
26
|
|
27
27
|
def coerce_isolated_result(v)
|
28
|
-
coerce_result(v, GraphQL::Query::NullContext)
|
28
|
+
coerce_result(v, GraphQL::Query::NullContext.instance)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -205,12 +205,12 @@ module GraphQL
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
-
def get_argument(name, context = GraphQL::Query::NullContext)
|
208
|
+
def get_argument(name, context = GraphQL::Query::NullContext.instance)
|
209
209
|
self.class.get_argument(name, context)
|
210
210
|
end
|
211
211
|
|
212
212
|
class << self
|
213
|
-
def field_arguments(context = GraphQL::Query::NullContext)
|
213
|
+
def field_arguments(context = GraphQL::Query::NullContext.instance)
|
214
214
|
arguments(context)
|
215
215
|
end
|
216
216
|
|
@@ -218,7 +218,7 @@ module GraphQL
|
|
218
218
|
any_arguments?
|
219
219
|
end
|
220
220
|
|
221
|
-
def get_field_argument(name, context = GraphQL::Query::NullContext)
|
221
|
+
def get_field_argument(name, context = GraphQL::Query::NullContext.instance)
|
222
222
|
get_argument(name, context)
|
223
223
|
end
|
224
224
|
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -10,7 +10,7 @@ module GraphQL
|
|
10
10
|
super
|
11
11
|
end
|
12
12
|
|
13
|
-
def possible_types(*types, context: GraphQL::Query::NullContext, **options)
|
13
|
+
def possible_types(*types, context: GraphQL::Query::NullContext.instance, **options)
|
14
14
|
if types.any?
|
15
15
|
types.each do |t|
|
16
16
|
assert_valid_union_member(t)
|
@@ -106,7 +106,7 @@ module GraphQL
|
|
106
106
|
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
107
107
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
108
108
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
109
|
-
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
109
|
+
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
110
110
|
@reachable_type_set =
|
111
111
|
nil
|
112
112
|
end
|
@@ -291,7 +291,14 @@ module GraphQL
|
|
291
291
|
if type_defn.kind.union?
|
292
292
|
possible_types(type_defn).any? && (referenced?(type_defn) || orphan_type?(type_defn))
|
293
293
|
elsif type_defn.kind.interface?
|
294
|
-
possible_types(type_defn).any?
|
294
|
+
if possible_types(type_defn).any?
|
295
|
+
true
|
296
|
+
else
|
297
|
+
if @context.respond_to?(:logger) && (logger = @context.logger)
|
298
|
+
logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementors" }
|
299
|
+
end
|
300
|
+
false
|
301
|
+
end
|
295
302
|
else
|
296
303
|
if referenced?(type_defn)
|
297
304
|
true
|
@@ -356,14 +363,11 @@ module GraphQL
|
|
356
363
|
end
|
357
364
|
|
358
365
|
def referenced?(type_defn)
|
359
|
-
@references_to ||= @schema.references_to
|
360
366
|
graphql_name = type_defn.unwrap.graphql_name
|
361
|
-
members = @references_to
|
367
|
+
members = @schema.references_to(graphql_name)
|
362
368
|
members.any? { |m| visible?(m) }
|
363
369
|
end
|
364
370
|
|
365
|
-
NO_REFERENCES = [].freeze
|
366
|
-
|
367
371
|
def orphan_type?(type_defn)
|
368
372
|
@schema.orphan_types.include?(type_defn)
|
369
373
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "logger"
|
2
3
|
require "graphql/schema/addition"
|
3
4
|
require "graphql/schema/always_visible"
|
4
5
|
require "graphql/schema/base_64_encoder"
|
@@ -325,7 +326,7 @@ module GraphQL
|
|
325
326
|
# Build a map of `{ name => type }` and return it
|
326
327
|
# @return [Hash<String => Class>] A dictionary of type classes by their GraphQL name
|
327
328
|
# @see get_type Which is more efficient for finding _one type_ by name, because it doesn't merge hashes.
|
328
|
-
def types(context = GraphQL::Query::NullContext)
|
329
|
+
def types(context = GraphQL::Query::NullContext.instance)
|
329
330
|
all_types = non_introspection_types.merge(introspection_system.types)
|
330
331
|
visible_types = {}
|
331
332
|
all_types.each do |k, v|
|
@@ -352,7 +353,7 @@ module GraphQL
|
|
352
353
|
|
353
354
|
# @param type_name [String]
|
354
355
|
# @return [Module, nil] A type, or nil if there's no type called `type_name`
|
355
|
-
def get_type(type_name, context = GraphQL::Query::NullContext)
|
356
|
+
def get_type(type_name, context = GraphQL::Query::NullContext.instance)
|
356
357
|
local_entry = own_types[type_name]
|
357
358
|
type_defn = case local_entry
|
358
359
|
when nil
|
@@ -483,7 +484,7 @@ module GraphQL
|
|
483
484
|
# @param type [Module] The type definition whose possible types you want to see
|
484
485
|
# @return [Hash<String, Module>] All possible types, if no `type` is given.
|
485
486
|
# @return [Array<Module>] Possible types for `type`, if it's given.
|
486
|
-
def possible_types(type = nil, context = GraphQL::Query::NullContext)
|
487
|
+
def possible_types(type = nil, context = GraphQL::Query::NullContext.instance)
|
487
488
|
if type
|
488
489
|
# TODO duck-typing `.possible_types` would probably be nicer here
|
489
490
|
if type.kind.union?
|
@@ -536,18 +537,17 @@ module GraphQL
|
|
536
537
|
attr_writer :dataloader_class
|
537
538
|
|
538
539
|
def references_to(to_type = nil, from: nil)
|
539
|
-
@own_references_to ||=
|
540
|
+
@own_references_to ||= {}
|
540
541
|
if to_type
|
541
542
|
if !to_type.is_a?(String)
|
542
543
|
to_type = to_type.graphql_name
|
543
544
|
end
|
544
545
|
|
545
546
|
if from
|
546
|
-
@own_references_to[to_type]
|
547
|
+
refs = @own_references_to[to_type] ||= []
|
548
|
+
refs << from
|
547
549
|
else
|
548
|
-
|
549
|
-
inherited_refs = find_inherited_value(:references_to, EMPTY_HASH)[to_type] || EMPTY_ARRAY
|
550
|
-
own_refs + inherited_refs
|
550
|
+
get_references_to(to_type) || EMPTY_ARRAY
|
551
551
|
end
|
552
552
|
else
|
553
553
|
# `@own_references_to` can be quite large for big schemas,
|
@@ -567,7 +567,7 @@ module GraphQL
|
|
567
567
|
GraphQL::Schema::TypeExpression.build_type(type_owner, ast_node)
|
568
568
|
end
|
569
569
|
|
570
|
-
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext)
|
570
|
+
def get_field(type_or_name, field_name, context = GraphQL::Query::NullContext.instance)
|
571
571
|
parent_type = case type_or_name
|
572
572
|
when LateBoundType
|
573
573
|
get_type(type_or_name.name, context)
|
@@ -590,7 +590,7 @@ module GraphQL
|
|
590
590
|
end
|
591
591
|
end
|
592
592
|
|
593
|
-
def get_fields(type, context = GraphQL::Query::NullContext)
|
593
|
+
def get_fields(type, context = GraphQL::Query::NullContext.instance)
|
594
594
|
type.fields(context)
|
595
595
|
end
|
596
596
|
|
@@ -836,6 +836,26 @@ module GraphQL
|
|
836
836
|
end
|
837
837
|
end
|
838
838
|
|
839
|
+
def default_logger(new_default_logger = NOT_CONFIGURED)
|
840
|
+
if NOT_CONFIGURED.equal?(new_default_logger)
|
841
|
+
if defined?(@default_logger)
|
842
|
+
@default_logger
|
843
|
+
elsif superclass.respond_to?(:default_logger)
|
844
|
+
superclass.default_logger
|
845
|
+
elsif defined?(Rails)
|
846
|
+
Rails.logger
|
847
|
+
else
|
848
|
+
def_logger = Logger.new($stdout)
|
849
|
+
def_logger.info! # It doesn't output debug info by default
|
850
|
+
def_logger
|
851
|
+
end
|
852
|
+
elsif new_default_logger == nil
|
853
|
+
@default_logger = Logger.new(IO::NULL)
|
854
|
+
else
|
855
|
+
@default_logger = new_default_logger
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
839
859
|
def context_class(new_context_class = nil)
|
840
860
|
if new_context_class
|
841
861
|
@context_class = new_context_class
|
@@ -922,6 +942,7 @@ module GraphQL
|
|
922
942
|
def inherited(child_class)
|
923
943
|
if self == GraphQL::Schema
|
924
944
|
child_class.directives(default_directives.values)
|
945
|
+
child_class.extend(SubclassGetReferencesTo)
|
925
946
|
end
|
926
947
|
# Make sure the child class has these built out, so that
|
927
948
|
# subclasses can be modified by later calls to `trace_with`
|
@@ -1397,6 +1418,27 @@ module GraphQL
|
|
1397
1418
|
def own_multiplex_analyzers
|
1398
1419
|
@own_multiplex_analyzers ||= []
|
1399
1420
|
end
|
1421
|
+
|
1422
|
+
# This is overridden in subclasses to check the inheritance chain
|
1423
|
+
def get_references_to(type_name)
|
1424
|
+
@own_references_to[type_name]
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
module SubclassGetReferencesTo
|
1429
|
+
def get_references_to(type_name)
|
1430
|
+
own_refs = @own_references_to[type_name]
|
1431
|
+
inherited_refs = superclass.references_to(type_name)
|
1432
|
+
if inherited_refs&.any?
|
1433
|
+
if own_refs&.any?
|
1434
|
+
own_refs + inherited_refs
|
1435
|
+
else
|
1436
|
+
inherited_refs
|
1437
|
+
end
|
1438
|
+
else
|
1439
|
+
own_refs
|
1440
|
+
end
|
1441
|
+
end
|
1400
1442
|
end
|
1401
1443
|
|
1402
1444
|
# Install these here so that subclasses will also install it.
|
@@ -37,7 +37,7 @@ module GraphQL
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# @return [String] an identifier for this unit of subscription
|
40
|
-
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
|
40
|
+
def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext.instance)
|
41
41
|
subscription = field.resolver || GraphQL::Schema::Subscription
|
42
42
|
normalized_args = stringify_args(field, arguments.to_h, context)
|
43
43
|
subscription.topic_for(arguments: normalized_args, field: field, scope: scope)
|
@@ -62,7 +62,7 @@ module GraphQL
|
|
62
62
|
# @return [void]
|
63
63
|
def trigger(event_name, args, object, scope: nil, context: {})
|
64
64
|
# Make something as context-like as possible, even though there isn't a current query:
|
65
|
-
dummy_query = GraphQL::Query.new(@schema, "", validate: false, context: context)
|
65
|
+
dummy_query = GraphQL::Query.new(@schema, "{ __typename }", validate: false, context: context)
|
66
66
|
context = dummy_query.context
|
67
67
|
event_name = event_name.to_s
|
68
68
|
|
@@ -83,7 +83,7 @@ module GraphQL
|
|
83
83
|
|
84
84
|
# Normalize symbol-keyed args to strings, try camelizing them
|
85
85
|
# Should this accept a real context somehow?
|
86
|
-
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext)
|
86
|
+
normalized_args = normalize_arguments(normalized_event_name, field, args, GraphQL::Query::NullContext.instance)
|
87
87
|
|
88
88
|
event = Subscriptions::Event.new(
|
89
89
|
name: normalized_event_name,
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: racc
|
@@ -626,7 +626,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
626
626
|
- !ruby/object:Gem::Version
|
627
627
|
version: '0'
|
628
628
|
requirements: []
|
629
|
-
rubygems_version: 3.
|
629
|
+
rubygems_version: 3.4.10
|
630
630
|
signing_key:
|
631
631
|
specification_version: 4
|
632
632
|
summary: A GraphQL language and runtime for Ruby
|