graphql 2.1.2 → 2.1.4
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- 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 +54 -13
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- metadata +17 -17
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"
|
@@ -170,9 +171,9 @@ module GraphQL
|
|
170
171
|
end
|
171
172
|
|
172
173
|
# @return [Class] Return the trace class to use for this mode, looking one up on the superclass if this Schema doesn't have one defined.
|
173
|
-
def trace_class_for(mode
|
174
|
+
def trace_class_for(mode)
|
174
175
|
own_trace_modes[mode] ||
|
175
|
-
(superclass.respond_to?(:trace_class_for) ? superclass.trace_class_for(mode) :
|
176
|
+
(superclass.respond_to?(:trace_class_for) ? superclass.trace_class_for(mode) : (own_trace_modes[mode] = build_trace_mode(mode)))
|
176
177
|
end
|
177
178
|
|
178
179
|
# Configure `trace_class` to be used whenever `context: { trace_mode: mode_name }` is requested.
|
@@ -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
|
@@ -921,8 +941,8 @@ module GraphQL
|
|
921
941
|
|
922
942
|
def inherited(child_class)
|
923
943
|
if self == GraphQL::Schema
|
924
|
-
child_class.own_trace_modes[:default] = child_class.build_trace_mode(:default)
|
925
944
|
child_class.directives(default_directives.values)
|
945
|
+
child_class.extend(SubclassGetReferencesTo)
|
926
946
|
end
|
927
947
|
# Make sure the child class has these built out, so that
|
928
948
|
# subclasses can be modified by later calls to `trace_with`
|
@@ -1398,6 +1418,27 @@ module GraphQL
|
|
1398
1418
|
def own_multiplex_analyzers
|
1399
1419
|
@own_multiplex_analyzers ||= []
|
1400
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
|
1401
1442
|
end
|
1402
1443
|
|
1403
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,15 +1,29 @@
|
|
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
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: racc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: benchmark-ips
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,20 +108,6 @@ dependencies:
|
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '1.0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: racc
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '1.4'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '1.4'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rake
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -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
|