graphql 2.4.3 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/visitor.rb +1 -1
- data/lib/graphql/analysis.rb +3 -3
- data/lib/graphql/autoload.rb +37 -0
- data/lib/graphql/current.rb +1 -1
- data/lib/graphql/dataloader/async_dataloader.rb +4 -4
- data/lib/graphql/dataloader/source.rb +1 -1
- data/lib/graphql/dataloader.rb +6 -9
- data/lib/graphql/execution/interpreter/resolve.rb +3 -3
- data/lib/graphql/execution/interpreter/runtime.rb +7 -7
- data/lib/graphql/execution/interpreter.rb +4 -4
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/document_from_schema_definition.rb +8 -7
- data/lib/graphql/language/lexer.rb +4 -1
- data/lib/graphql/language/printer.rb +8 -8
- data/lib/graphql/pagination/connection.rb +1 -1
- data/lib/graphql/query/context/scoped_context.rb +1 -1
- data/lib/graphql/query/context.rb +6 -5
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query.rb +12 -10
- data/lib/graphql/railtie.rb +7 -0
- data/lib/graphql/schema/addition.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +10 -10
- data/lib/graphql/schema/field_extension.rb +1 -1
- data/lib/graphql/schema/has_single_input_argument.rb +3 -1
- data/lib/graphql/schema/input_object.rb +64 -27
- data/lib/graphql/schema/interface.rb +1 -1
- data/lib/graphql/schema/loader.rb +1 -1
- data/lib/graphql/schema/member/has_arguments.rb +12 -12
- data/lib/graphql/schema/member/has_directives.rb +3 -3
- data/lib/graphql/schema/member/has_fields.rb +18 -0
- data/lib/graphql/schema/member/has_interfaces.rb +4 -4
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
- data/lib/graphql/schema/resolver.rb +5 -5
- data/lib/graphql/schema/subscription.rb +2 -2
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/validator.rb +1 -1
- data/lib/graphql/schema/visibility/profile.rb +61 -235
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +162 -26
- data/lib/graphql/schema/warden.rb +4 -4
- data/lib/graphql/schema.rb +33 -12
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
- data/lib/graphql/subscriptions.rb +1 -1
- data/lib/graphql/testing/helpers.rb +2 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +2 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
- data/lib/graphql/types.rb +18 -11
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +80 -47
- metadata +4 -2
@@ -38,38 +38,17 @@ module GraphQL
|
|
38
38
|
@all_types = {}
|
39
39
|
@all_types_loaded = false
|
40
40
|
@unvisited_types = []
|
41
|
-
@referenced_types = Hash.new { |h, type_defn| h[type_defn] = [] }.compare_by_identity
|
42
|
-
@cached_directives = {}
|
43
41
|
@all_directives = nil
|
44
|
-
@cached_visible = Hash.new { |h, member|
|
45
|
-
h[member] = @schema.visible?(member, @context)
|
46
|
-
}.compare_by_identity
|
42
|
+
@cached_visible = Hash.new { |h, member| h[member] = @schema.visible?(member, @context) }.compare_by_identity
|
47
43
|
|
48
44
|
@cached_visible_fields = Hash.new { |h, owner|
|
49
45
|
h[owner] = Hash.new do |h2, field|
|
50
|
-
h2[field] =
|
51
|
-
(ret_type = field.type.unwrap) &&
|
52
|
-
@cached_visible[ret_type] &&
|
53
|
-
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
54
|
-
|
55
|
-
if !field.introspection?
|
56
|
-
# The problem is that some introspection fields may have references
|
57
|
-
# to non-custom introspection types.
|
58
|
-
# If those were added here, they'd cause a DuplicateNamesError.
|
59
|
-
# This is basically a bug -- those fields _should_ reference the custom types.
|
60
|
-
add_type(ret_type, field)
|
61
|
-
end
|
62
|
-
true
|
63
|
-
else
|
64
|
-
false
|
65
|
-
end
|
46
|
+
h2[field] = visible_field_for(owner, field)
|
66
47
|
end.compare_by_identity
|
67
48
|
}.compare_by_identity
|
68
49
|
|
69
50
|
@cached_visible_arguments = Hash.new do |h, arg|
|
70
51
|
h[arg] = if @cached_visible[arg] && (arg_type = arg.type.unwrap) && @cached_visible[arg_type]
|
71
|
-
add_type(arg_type, arg)
|
72
|
-
arg.validate_default_value
|
73
52
|
true
|
74
53
|
else
|
75
54
|
false
|
@@ -88,39 +67,7 @@ module GraphQL
|
|
88
67
|
end
|
89
68
|
end.compare_by_identity
|
90
69
|
|
91
|
-
@cached_possible_types = Hash.new
|
92
|
-
h[type] = case type.kind.name
|
93
|
-
when "INTERFACE"
|
94
|
-
load_all_types
|
95
|
-
pts = []
|
96
|
-
@unfiltered_interface_type_memberships[type].each { |itm|
|
97
|
-
if @cached_visible[itm] && (ot = itm.object_type) && @cached_visible[ot] && referenced?(ot)
|
98
|
-
pts << ot
|
99
|
-
end
|
100
|
-
}
|
101
|
-
pts
|
102
|
-
when "UNION"
|
103
|
-
pts = []
|
104
|
-
type.type_memberships.each { |tm|
|
105
|
-
if @cached_visible[tm] &&
|
106
|
-
(ot = tm.object_type) &&
|
107
|
-
@cached_visible[ot] &&
|
108
|
-
referenced?(ot)
|
109
|
-
pts << ot
|
110
|
-
end
|
111
|
-
}
|
112
|
-
pts
|
113
|
-
when "OBJECT"
|
114
|
-
load_all_types
|
115
|
-
if @all_types[type.graphql_name] == type
|
116
|
-
[type]
|
117
|
-
else
|
118
|
-
EmptyObjects::EMPTY_ARRAY
|
119
|
-
end
|
120
|
-
else
|
121
|
-
GraphQL::EmptyObjects::EMPTY_ARRAY
|
122
|
-
end
|
123
|
-
end.compare_by_identity
|
70
|
+
@cached_possible_types = Hash.new { |h, type| h[type] = possible_types_for(type) }.compare_by_identity
|
124
71
|
|
125
72
|
@cached_enum_values = Hash.new do |h, enum_t|
|
126
73
|
values = non_duplicate_items(enum_t.enum_values(@context), @cached_visible)
|
@@ -164,17 +111,12 @@ module GraphQL
|
|
164
111
|
end
|
165
112
|
|
166
113
|
def type(type_name)
|
167
|
-
t =
|
168
|
-
loaded_t
|
169
|
-
elsif !@all_types_loaded
|
170
|
-
load_all_types
|
171
|
-
@all_types[type_name]
|
172
|
-
end
|
114
|
+
t = @schema.visibility.get_type(type_name) # rubocop:disable Development/ContextIsPassedCop
|
173
115
|
if t
|
174
116
|
if t.is_a?(Array)
|
175
117
|
vis_t = nil
|
176
118
|
t.each do |t_defn|
|
177
|
-
if @cached_visible[t_defn]
|
119
|
+
if @cached_visible[t_defn] && referenced?(t_defn)
|
178
120
|
if vis_t.nil?
|
179
121
|
vis_t = t_defn
|
180
122
|
else
|
@@ -184,7 +126,7 @@ module GraphQL
|
|
184
126
|
end
|
185
127
|
vis_t
|
186
128
|
else
|
187
|
-
if t && @cached_visible[t]
|
129
|
+
if t && @cached_visible[t] && referenced?(t)
|
188
130
|
t
|
189
131
|
else
|
190
132
|
nil
|
@@ -267,15 +209,15 @@ module GraphQL
|
|
267
209
|
end
|
268
210
|
|
269
211
|
def query_root
|
270
|
-
|
212
|
+
((t = @schema.query) && @cached_visible[t]) ? t : nil
|
271
213
|
end
|
272
214
|
|
273
215
|
def mutation_root
|
274
|
-
|
216
|
+
((t = @schema.mutation) && @cached_visible[t]) ? t : nil
|
275
217
|
end
|
276
218
|
|
277
219
|
def subscription_root
|
278
|
-
|
220
|
+
((t = @schema.subscription) && @cached_visible[t]) ? t : nil
|
279
221
|
end
|
280
222
|
|
281
223
|
def all_types
|
@@ -293,28 +235,17 @@ module GraphQL
|
|
293
235
|
end
|
294
236
|
|
295
237
|
def directive_exists?(dir_name)
|
296
|
-
|
297
|
-
!!dir
|
298
|
-
else
|
299
|
-
load_all_types
|
300
|
-
!!@cached_directives[dir_name]
|
301
|
-
end
|
238
|
+
directives.any? { |d| d.graphql_name == dir_name }
|
302
239
|
end
|
303
240
|
|
304
241
|
def directives
|
305
|
-
@all_directives ||=
|
306
|
-
|
307
|
-
|
308
|
-
@schema.directives.each do |name, dir_defn|
|
309
|
-
if !@cached_directives[name] && @cached_visible[dir_defn]
|
310
|
-
dirs << dir_defn
|
311
|
-
end
|
312
|
-
end
|
313
|
-
dirs.concat(@cached_directives.values)
|
314
|
-
end
|
242
|
+
@all_directives ||= @schema.visibility.all_directives.select { |dir|
|
243
|
+
@cached_visible[dir] && @schema.visibility.all_references[dir].any? { |ref| ref == true || (@cached_visible[ref] && referenced?(ref)) }
|
244
|
+
}
|
315
245
|
end
|
316
246
|
|
317
247
|
def loadable?(t, _ctx)
|
248
|
+
load_all_types
|
318
249
|
!@all_types[t.graphql_name] && @cached_visible[t]
|
319
250
|
end
|
320
251
|
|
@@ -322,9 +253,9 @@ module GraphQL
|
|
322
253
|
@all_types.values
|
323
254
|
end
|
324
255
|
|
325
|
-
def reachable_type?(
|
256
|
+
def reachable_type?(type_name)
|
326
257
|
load_all_types
|
327
|
-
!!@all_types[
|
258
|
+
!!@all_types[type_name]
|
328
259
|
end
|
329
260
|
|
330
261
|
def visible_enum_value?(enum_value, _ctx = nil)
|
@@ -333,29 +264,6 @@ module GraphQL
|
|
333
264
|
|
334
265
|
private
|
335
266
|
|
336
|
-
def add_if_visible(t)
|
337
|
-
(t && @cached_visible[t]) ? (add_type(t, true); t) : nil
|
338
|
-
end
|
339
|
-
|
340
|
-
def add_type(t, by_member)
|
341
|
-
if t && @cached_visible[t]
|
342
|
-
n = t.graphql_name
|
343
|
-
if (prev_t = @all_types[n])
|
344
|
-
if !prev_t.equal?(t)
|
345
|
-
raise_duplicate_definition(prev_t, t)
|
346
|
-
end
|
347
|
-
false
|
348
|
-
else
|
349
|
-
@referenced_types[t] << by_member
|
350
|
-
@all_types[n] = t
|
351
|
-
@unvisited_types << t
|
352
|
-
true
|
353
|
-
end
|
354
|
-
else
|
355
|
-
false
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
267
|
def non_duplicate_items(definitions, visibility_cache)
|
360
268
|
non_dups = []
|
361
269
|
definitions.each do |defn|
|
@@ -373,153 +281,71 @@ module GraphQL
|
|
373
281
|
raise DuplicateNamesError.new(duplicated_name: first_defn.path, duplicated_definition_1: first_defn.inspect, duplicated_definition_2: second_defn.inspect)
|
374
282
|
end
|
375
283
|
|
376
|
-
def referenced?(t)
|
377
|
-
load_all_types
|
378
|
-
@referenced_types[t].any? { |reference| (reference == true) || @cached_visible[reference] }
|
379
|
-
end
|
380
|
-
|
381
284
|
def load_all_types
|
382
285
|
return if @all_types_loaded
|
383
286
|
@all_types_loaded = true
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
# Don't include any orphan_types whose interfaces aren't visible.
|
392
|
-
@schema.orphan_types.each do |orphan_type|
|
393
|
-
if @cached_visible[orphan_type] &&
|
394
|
-
orphan_type.interface_type_memberships.any? { |tm| @cached_visible[tm] && @cached_visible[tm.abstract_type] }
|
395
|
-
entry_point_types << orphan_type
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
@schema.directives.each do |_dir_name, dir_class|
|
400
|
-
if @cached_visible[dir_class]
|
401
|
-
arguments(dir_class).each do |arg|
|
402
|
-
entry_point_types << arg.type.unwrap
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
entry_point_types.compact! # Root types might be nil
|
408
|
-
entry_point_types.flatten! # handle multiple defns
|
409
|
-
entry_point_types.each { |t| add_type(t, true) }
|
410
|
-
|
411
|
-
@unfiltered_interface_type_memberships = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
412
|
-
@add_possible_types = Set.new
|
413
|
-
@late_types = []
|
414
|
-
|
415
|
-
while @unvisited_types.any? || @late_types.any?
|
416
|
-
while t = @unvisited_types.pop
|
417
|
-
# These have already been checked for `.visible?`
|
418
|
-
visit_type(t)
|
419
|
-
end
|
420
|
-
@add_possible_types.each do |int_t|
|
421
|
-
itms = @unfiltered_interface_type_memberships[int_t]
|
422
|
-
itms.each do |itm|
|
423
|
-
if @cached_visible[itm] && (obj_type = itm.object_type) && @cached_visible[obj_type]
|
424
|
-
add_type(obj_type, itm)
|
287
|
+
visit = Visibility::Visit.new(@schema) do |member|
|
288
|
+
if member.is_a?(Module) && member.respond_to?(:kind)
|
289
|
+
if @cached_visible[member]
|
290
|
+
type_name = member.graphql_name
|
291
|
+
if (prev_t = @all_types[type_name]) && !prev_t.equal?(member)
|
292
|
+
raise_duplicate_definition(member, prev_t)
|
425
293
|
end
|
294
|
+
@all_types[type_name] = member
|
295
|
+
true
|
296
|
+
else
|
297
|
+
false
|
426
298
|
end
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
while (union_tm = @late_types.shift)
|
431
|
-
late_obj_t = union_tm.object_type
|
432
|
-
obj_t = @all_types[late_obj_t.graphql_name] || raise("Failed to resolve #{late_obj_t.graphql_name.inspect} from #{union_tm.inspect}")
|
433
|
-
union_tm.abstract_type.assign_type_membership_object_type(obj_t)
|
299
|
+
else
|
300
|
+
@cached_visible[member]
|
434
301
|
end
|
435
302
|
end
|
436
|
-
|
303
|
+
visit.visit_each
|
437
304
|
@all_types.delete_if { |type_name, type_defn| !referenced?(type_defn) }
|
438
305
|
nil
|
439
306
|
end
|
440
307
|
|
441
|
-
def
|
442
|
-
|
443
|
-
|
444
|
-
when "OBJECT", "INTERFACE"
|
445
|
-
if type.kind.object?
|
446
|
-
type.interface_type_memberships.each do |itm|
|
447
|
-
@unfiltered_interface_type_memberships[itm.abstract_type] << itm
|
448
|
-
end
|
449
|
-
# recurse into visible implemented interfaces
|
450
|
-
interfaces(type).each do |interface|
|
451
|
-
add_type(interface, type)
|
452
|
-
end
|
453
|
-
else
|
454
|
-
type.orphan_types.each { |t| add_type(t, type)}
|
455
|
-
end
|
456
|
-
|
457
|
-
# recurse into visible fields
|
458
|
-
t_f = type.all_field_definitions
|
459
|
-
t_f.each do |field|
|
460
|
-
field.ensure_loaded
|
461
|
-
if @cached_visible[field]
|
462
|
-
visit_directives(field)
|
463
|
-
field_type = field.type.unwrap
|
464
|
-
if field_type.kind.interface?
|
465
|
-
@add_possible_types.add(field_type)
|
466
|
-
end
|
467
|
-
add_type(field_type, field)
|
308
|
+
def referenced?(type_defn)
|
309
|
+
@schema.visibility.all_references[type_defn].any? { |r| r == true || @cached_visible[r] }
|
310
|
+
end
|
468
311
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
312
|
+
def possible_types_for(type)
|
313
|
+
case type.kind.name
|
314
|
+
when "INTERFACE"
|
315
|
+
pts = []
|
316
|
+
@schema.visibility.all_interface_type_memberships[type].each do |itm|
|
317
|
+
if @cached_visible[itm] && (ot = itm.object_type) && @cached_visible[ot] && referenced?(ot)
|
318
|
+
pts << ot
|
474
319
|
end
|
475
320
|
end
|
476
|
-
|
477
|
-
# recurse into visible arguments
|
478
|
-
arguments(type).each do |argument|
|
479
|
-
visit_directives(argument)
|
480
|
-
add_type(argument.type.unwrap, argument)
|
481
|
-
end
|
321
|
+
pts
|
482
322
|
when "UNION"
|
483
|
-
|
484
|
-
type.type_memberships.each
|
485
|
-
if @cached_visible[tm]
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
if obj_t.is_a?(String)
|
491
|
-
obj_t = Member::BuildType.constantize(obj_t)
|
492
|
-
tm.object_type = obj_t
|
493
|
-
end
|
494
|
-
if @cached_visible[obj_t]
|
495
|
-
add_type(obj_t, tm)
|
496
|
-
end
|
497
|
-
end
|
323
|
+
pts = []
|
324
|
+
type.type_memberships.each { |tm|
|
325
|
+
if @cached_visible[tm] &&
|
326
|
+
(ot = tm.object_type) &&
|
327
|
+
@cached_visible[ot] &&
|
328
|
+
referenced?(ot)
|
329
|
+
pts << ot
|
498
330
|
end
|
331
|
+
}
|
332
|
+
pts
|
333
|
+
when "OBJECT"
|
334
|
+
if @cached_visible[type]
|
335
|
+
[type]
|
336
|
+
else
|
337
|
+
EmptyObjects::EMPTY_ARRAY
|
499
338
|
end
|
500
|
-
|
501
|
-
|
502
|
-
visit_directives(val)
|
503
|
-
end
|
504
|
-
when "SCALAR"
|
505
|
-
# pass
|
339
|
+
else
|
340
|
+
GraphQL::EmptyObjects::EMPTY_ARRAY
|
506
341
|
end
|
507
342
|
end
|
508
343
|
|
509
|
-
def
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
if (existing_dir = @cached_directives[dir_name])
|
515
|
-
if existing_dir != dir_class
|
516
|
-
raise ArgumentError, "Two directives for `@#{dir_name}`: #{existing_dir}, #{dir.class}"
|
517
|
-
end
|
518
|
-
else
|
519
|
-
@cached_directives[dir.graphql_name] = dir_class
|
520
|
-
end
|
521
|
-
end
|
522
|
-
}
|
344
|
+
def visible_field_for(owner, field)
|
345
|
+
@cached_visible[field] &&
|
346
|
+
(ret_type = field.type.unwrap) &&
|
347
|
+
@cached_visible[ret_type] &&
|
348
|
+
(owner == field.owner || (!owner.kind.object?) || field_on_visible_interface?(field, owner))
|
523
349
|
end
|
524
350
|
end
|
525
351
|
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Visibility
|
5
|
+
class Visit
|
6
|
+
def initialize(schema, &visit_block)
|
7
|
+
@schema = schema
|
8
|
+
@late_bound_types = nil
|
9
|
+
@unvisited_types = nil
|
10
|
+
# These accumulate between calls to prevent re-visiting the same types
|
11
|
+
@visited_types = Set.new.compare_by_identity
|
12
|
+
@visited_directives = Set.new.compare_by_identity
|
13
|
+
@visit_block = visit_block
|
14
|
+
end
|
15
|
+
|
16
|
+
def entry_point_types
|
17
|
+
ept = [
|
18
|
+
@schema.query,
|
19
|
+
@schema.mutation,
|
20
|
+
@schema.subscription,
|
21
|
+
*@schema.introspection_system.types.values,
|
22
|
+
*@schema.orphan_types,
|
23
|
+
]
|
24
|
+
ept.compact!
|
25
|
+
ept
|
26
|
+
end
|
27
|
+
|
28
|
+
def entry_point_directives
|
29
|
+
@schema.directives.values
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_each(types: entry_point_types, directives: entry_point_directives)
|
33
|
+
@unvisited_types && raise("Can't re-enter `visit_each` on this Visit (another visit is already in progress)")
|
34
|
+
@unvisited_types = types
|
35
|
+
@late_bound_types = []
|
36
|
+
directives_to_visit = directives
|
37
|
+
|
38
|
+
while !@unvisited_types.empty? || !@late_bound_types.empty?
|
39
|
+
while (type = @unvisited_types.pop)
|
40
|
+
if @visited_types.add?(type) && @visit_block.call(type)
|
41
|
+
directives_to_visit.concat(type.directives)
|
42
|
+
case type.kind.name
|
43
|
+
when "OBJECT", "INTERFACE"
|
44
|
+
type.interface_type_memberships.each do |itm|
|
45
|
+
append_unvisited_type(type, itm.abstract_type)
|
46
|
+
end
|
47
|
+
if type.kind.interface?
|
48
|
+
type.orphan_types.each do |orphan_type|
|
49
|
+
append_unvisited_type(type, orphan_type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
type.all_field_definitions.each do |field|
|
54
|
+
field.ensure_loaded
|
55
|
+
if @visit_block.call(field)
|
56
|
+
directives_to_visit.concat(field.directives)
|
57
|
+
append_unvisited_type(type, field.type.unwrap)
|
58
|
+
field.all_argument_definitions.each do |argument|
|
59
|
+
if @visit_block.call(argument)
|
60
|
+
directives_to_visit.concat(argument.directives)
|
61
|
+
append_unvisited_type(field, argument.type.unwrap)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
when "INPUT_OBJECT"
|
67
|
+
type.all_argument_definitions.each do |argument|
|
68
|
+
if @visit_block.call(argument)
|
69
|
+
directives_to_visit.concat(argument.directives)
|
70
|
+
append_unvisited_type(type, argument.type.unwrap)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
when "UNION"
|
74
|
+
type.type_memberships.each do |tm|
|
75
|
+
append_unvisited_type(type, tm.object_type)
|
76
|
+
end
|
77
|
+
when "ENUM"
|
78
|
+
type.all_enum_value_definitions.each do |val|
|
79
|
+
if @visit_block.call(val)
|
80
|
+
directives_to_visit.concat(val.directives)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
when "SCALAR"
|
84
|
+
# pass -- nothing else to visit
|
85
|
+
else
|
86
|
+
raise "Invariant: unhandled type kind: #{type.kind.inspect}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
directives_to_visit.each do |dir|
|
92
|
+
dir_class = dir.is_a?(Class) ? dir : dir.class
|
93
|
+
if @visited_directives.add?(dir_class) && @visit_block.call(dir_class)
|
94
|
+
dir_class.all_argument_definitions.each do |arg_defn|
|
95
|
+
if @visit_block.call(arg_defn)
|
96
|
+
directives_to_visit.concat(arg_defn.directives)
|
97
|
+
append_unvisited_type(dir_class, arg_defn.type.unwrap)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
missed_late_types_streak = 0
|
104
|
+
while (owner, late_type = @late_bound_types.shift)
|
105
|
+
if (late_type.is_a?(String) && (type = Member::BuildType.constantize(type))) ||
|
106
|
+
(late_type.is_a?(LateBoundType) && (type = @visited_types.find { |t| t.graphql_name == late_type.graphql_name }))
|
107
|
+
missed_late_types_streak = 0 # might succeed next round
|
108
|
+
update_type_owner(owner, type)
|
109
|
+
append_unvisited_type(owner, type)
|
110
|
+
else
|
111
|
+
# Didn't find it -- keep trying
|
112
|
+
missed_late_types_streak += 1
|
113
|
+
@late_bound_types << [owner, late_type]
|
114
|
+
if missed_late_types_streak == @late_bound_types.size
|
115
|
+
raise UnresolvedLateBoundTypeError.new(type: late_type)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
@unvisited_types = nil
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def append_unvisited_type(owner, type)
|
128
|
+
if type.is_a?(LateBoundType) || type.is_a?(String)
|
129
|
+
@late_bound_types << [owner, type]
|
130
|
+
else
|
131
|
+
@unvisited_types << type
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def update_type_owner(owner, type)
|
136
|
+
case owner
|
137
|
+
when Module
|
138
|
+
if owner.kind.union?
|
139
|
+
owner.assign_type_membership_object_type(type)
|
140
|
+
elsif type.kind.interface?
|
141
|
+
new_interfaces = []
|
142
|
+
owner.interfaces.each do |int_t|
|
143
|
+
if int_t.is_a?(String) && int_t == type.graphql_name
|
144
|
+
new_interfaces << type
|
145
|
+
elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
|
146
|
+
new_interfaces << type
|
147
|
+
else
|
148
|
+
# Don't re-add proper interface definitions,
|
149
|
+
# they were probably already added, maybe with options.
|
150
|
+
end
|
151
|
+
end
|
152
|
+
owner.implements(*new_interfaces)
|
153
|
+
new_interfaces.each do |int|
|
154
|
+
pt = @possible_types[int] ||= []
|
155
|
+
if !pt.include?(owner) && owner.is_a?(Class)
|
156
|
+
pt << owner
|
157
|
+
end
|
158
|
+
int.interfaces.each do |indirect_int|
|
159
|
+
if indirect_int.is_a?(LateBoundType) && (indirect_int_type = get_type(indirect_int.graphql_name)) # rubocop:disable Development/ContextIsPassedCop
|
160
|
+
update_type_owner(owner, indirect_int_type)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
when GraphQL::Schema::Argument, GraphQL::Schema::Field
|
166
|
+
orig_type = owner.type
|
167
|
+
# Apply list/non-null wrapper as needed
|
168
|
+
if orig_type.respond_to?(:of_type)
|
169
|
+
transforms = []
|
170
|
+
while (orig_type.respond_to?(:of_type))
|
171
|
+
if orig_type.kind.non_null?
|
172
|
+
transforms << :to_non_null_type
|
173
|
+
elsif orig_type.kind.list?
|
174
|
+
transforms << :to_list_type
|
175
|
+
else
|
176
|
+
raise "Invariant: :of_type isn't non-null or list"
|
177
|
+
end
|
178
|
+
orig_type = orig_type.of_type
|
179
|
+
end
|
180
|
+
transforms.reverse_each { |t| type = type.public_send(t) }
|
181
|
+
end
|
182
|
+
owner.type = type
|
183
|
+
else
|
184
|
+
raise "Unexpected update: #{owner.inspect} #{type.inspect}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|