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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/visitor.rb +1 -1
  3. data/lib/graphql/analysis.rb +3 -3
  4. data/lib/graphql/autoload.rb +37 -0
  5. data/lib/graphql/current.rb +1 -1
  6. data/lib/graphql/dataloader/async_dataloader.rb +4 -4
  7. data/lib/graphql/dataloader/source.rb +1 -1
  8. data/lib/graphql/dataloader.rb +6 -9
  9. data/lib/graphql/execution/interpreter/resolve.rb +3 -3
  10. data/lib/graphql/execution/interpreter/runtime.rb +7 -7
  11. data/lib/graphql/execution/interpreter.rb +4 -4
  12. data/lib/graphql/language/cache.rb +13 -0
  13. data/lib/graphql/language/document_from_schema_definition.rb +8 -7
  14. data/lib/graphql/language/lexer.rb +4 -1
  15. data/lib/graphql/language/printer.rb +8 -8
  16. data/lib/graphql/pagination/connection.rb +1 -1
  17. data/lib/graphql/query/context/scoped_context.rb +1 -1
  18. data/lib/graphql/query/context.rb +6 -5
  19. data/lib/graphql/query/variable_validation_error.rb +1 -1
  20. data/lib/graphql/query.rb +12 -10
  21. data/lib/graphql/railtie.rb +7 -0
  22. data/lib/graphql/schema/addition.rb +1 -1
  23. data/lib/graphql/schema/directive/flagged.rb +1 -1
  24. data/lib/graphql/schema/directive.rb +1 -1
  25. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  26. data/lib/graphql/schema/field.rb +10 -10
  27. data/lib/graphql/schema/field_extension.rb +1 -1
  28. data/lib/graphql/schema/has_single_input_argument.rb +3 -1
  29. data/lib/graphql/schema/input_object.rb +64 -27
  30. data/lib/graphql/schema/interface.rb +1 -1
  31. data/lib/graphql/schema/loader.rb +1 -1
  32. data/lib/graphql/schema/member/has_arguments.rb +12 -12
  33. data/lib/graphql/schema/member/has_directives.rb +3 -3
  34. data/lib/graphql/schema/member/has_fields.rb +18 -0
  35. data/lib/graphql/schema/member/has_interfaces.rb +4 -4
  36. data/lib/graphql/schema/member/has_validators.rb +1 -1
  37. data/lib/graphql/schema/object.rb +8 -0
  38. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  39. data/lib/graphql/schema/resolver.rb +5 -5
  40. data/lib/graphql/schema/subscription.rb +2 -2
  41. data/lib/graphql/schema/union.rb +1 -1
  42. data/lib/graphql/schema/validator.rb +1 -1
  43. data/lib/graphql/schema/visibility/profile.rb +61 -235
  44. data/lib/graphql/schema/visibility/visit.rb +190 -0
  45. data/lib/graphql/schema/visibility.rb +162 -26
  46. data/lib/graphql/schema/warden.rb +4 -4
  47. data/lib/graphql/schema.rb +33 -12
  48. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  49. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
  50. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  51. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  52. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  53. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  54. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  55. data/lib/graphql/static_validation/validation_context.rb +1 -0
  56. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  57. data/lib/graphql/subscriptions.rb +1 -1
  58. data/lib/graphql/testing/helpers.rb +2 -2
  59. data/lib/graphql/types/relay/connection_behaviors.rb +2 -2
  60. data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
  61. data/lib/graphql/types.rb +18 -11
  62. data/lib/graphql/version.rb +1 -1
  63. data/lib/graphql.rb +80 -47
  64. 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] = if @cached_visible[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 do |h, type|
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 = if (loaded_t = @all_types[type_name])
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
- add_if_visible(@schema.query)
212
+ ((t = @schema.query) && @cached_visible[t]) ? t : nil
271
213
  end
272
214
 
273
215
  def mutation_root
274
- add_if_visible(@schema.mutation)
216
+ ((t = @schema.mutation) && @cached_visible[t]) ? t : nil
275
217
  end
276
218
 
277
219
  def subscription_root
278
- add_if_visible(@schema.subscription)
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
- if (dir = @schema.directives[dir_name]) && @cached_visible[dir]
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 ||= begin
306
- load_all_types
307
- dirs = []
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?(name)
256
+ def reachable_type?(type_name)
326
257
  load_all_types
327
- !!@all_types[name]
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
- entry_point_types = [
385
- query_root,
386
- mutation_root,
387
- subscription_root,
388
- *@schema.introspection_system.types.values,
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
- end
428
- @add_possible_types.clear
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 visit_type(type)
442
- visit_directives(type)
443
- case type.kind.name
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
- # recurse into visible arguments
470
- arguments(field).each do |argument|
471
- visit_directives(argument)
472
- add_type(argument.type.unwrap, argument)
473
- end
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
- when "INPUT_OBJECT"
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
- # recurse into visible possible types
484
- type.type_memberships.each do |tm|
485
- if @cached_visible[tm]
486
- obj_t = tm.object_type
487
- if obj_t.is_a?(GraphQL::Schema::LateBoundType)
488
- @late_types << tm
489
- else
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
- when "ENUM"
501
- enum_values(type).each do |val|
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 visit_directives(member)
510
- member.directives.each { |dir|
511
- dir_class = dir.class
512
- if @cached_visible[dir_class]
513
- dir_name = dir_class.graphql_name
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