graphql 1.12.8 → 1.12.13

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.

Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install_generator.rb +1 -1
  3. data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
  4. data/lib/graphql.rb +10 -10
  5. data/lib/graphql/backtrace/table.rb +14 -2
  6. data/lib/graphql/backtrace/tracer.rb +1 -1
  7. data/lib/graphql/dataloader.rb +59 -15
  8. data/lib/graphql/dataloader/null_dataloader.rb +1 -0
  9. data/lib/graphql/execution/execute.rb +1 -1
  10. data/lib/graphql/execution/interpreter.rb +4 -8
  11. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -2
  12. data/lib/graphql/execution/interpreter/resolve.rb +6 -2
  13. data/lib/graphql/execution/interpreter/runtime.rb +496 -222
  14. data/lib/graphql/execution/lazy.rb +5 -1
  15. data/lib/graphql/introspection/schema_type.rb +1 -1
  16. data/lib/graphql/pagination/connections.rb +1 -1
  17. data/lib/graphql/query/null_context.rb +7 -1
  18. data/lib/graphql/rake_task.rb +3 -0
  19. data/lib/graphql/schema.rb +44 -218
  20. data/lib/graphql/schema/addition.rb +238 -0
  21. data/lib/graphql/schema/argument.rb +55 -36
  22. data/lib/graphql/schema/directive/transform.rb +13 -1
  23. data/lib/graphql/schema/enum.rb +10 -1
  24. data/lib/graphql/schema/input_object.rb +13 -17
  25. data/lib/graphql/schema/loader.rb +8 -0
  26. data/lib/graphql/schema/member/base_dsl_methods.rb +3 -15
  27. data/lib/graphql/schema/object.rb +19 -5
  28. data/lib/graphql/schema/printer.rb +11 -16
  29. data/lib/graphql/schema/resolver.rb +52 -25
  30. data/lib/graphql/schema/scalar.rb +3 -1
  31. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
  32. data/lib/graphql/static_validation/rules/fields_will_merge.rb +17 -8
  33. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
  34. data/lib/graphql/static_validation/validator.rb +5 -0
  35. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
  36. data/lib/graphql/subscriptions/serialize.rb +8 -1
  37. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  38. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  39. data/lib/graphql/types/relay/node_field.rb +2 -2
  40. data/lib/graphql/types/relay/nodes_field.rb +2 -2
  41. data/lib/graphql/version.rb +1 -1
  42. data/readme.md +0 -3
  43. metadata +7 -21
  44. data/lib/graphql/execution/interpreter/hash_response.rb +0 -46
@@ -48,7 +48,11 @@ module GraphQL
48
48
  end
49
49
  end
50
50
 
51
- if @value.is_a?(StandardError)
51
+ # `SKIP` was made into a subclass of `GraphQL::Error` to improve runtime performance
52
+ # (fewer clauses in a hot `case` block), but now it requires special handling here.
53
+ # I think it's still worth it for the performance win, but if the number of special
54
+ # cases grows, then maybe it's worth rethinking somehow.
55
+ if @value.is_a?(StandardError) && @value != GraphQL::Execution::Execute::SKIP
52
56
  raise @value
53
57
  else
54
58
  @value
@@ -31,7 +31,7 @@ module GraphQL
31
31
  end
32
32
 
33
33
  def directives
34
- context.schema.directives.values
34
+ @context.warden.directives
35
35
  end
36
36
 
37
37
  private
@@ -79,7 +79,7 @@ module GraphQL
79
79
  context: context,
80
80
  parent: parent,
81
81
  field: field,
82
- max_page_size: field.max_page_size || context.schema.default_max_page_size,
82
+ max_page_size: field.has_max_page_size? ? field.max_page_size : context.schema.default_max_page_size,
83
83
  first: arguments[:first],
84
84
  after: arguments[:after],
85
85
  last: arguments[:last],
@@ -9,10 +9,16 @@ module GraphQL
9
9
  def visible_type?(t); true; end
10
10
  end
11
11
 
12
+ class NullQuery
13
+ def with_error_handling
14
+ yield
15
+ end
16
+ end
17
+
12
18
  attr_reader :schema, :query, :warden, :dataloader
13
19
 
14
20
  def initialize
15
- @query = nil
21
+ @query = NullQuery.new
16
22
  @dataloader = GraphQL::Dataloader::NullDataloader.new
17
23
  @schema = GraphQL::Schema.new
18
24
  @warden = NullWarden.new(
@@ -98,6 +98,9 @@ module GraphQL
98
98
  result = schema.public_send(method_name, only: @only, except: @except, context: context)
99
99
  dir = File.dirname(file)
100
100
  FileUtils.mkdir_p(dir)
101
+ if !result.end_with?("\n")
102
+ result += "\n"
103
+ end
101
104
  File.write(file, result)
102
105
  end
103
106
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/schema/addition"
2
3
  require "graphql/schema/base_64_encoder"
3
4
  require "graphql/schema/catchall_middleware"
4
5
  require "graphql/schema/default_parse_error"
@@ -355,23 +356,6 @@ module GraphQL
355
356
  # For forwards-compatibility with Schema classes
356
357
  alias :graphql_definition :itself
357
358
 
358
- # Validate a query string according to this schema.
359
- # @param string_or_document [String, GraphQL::Language::Nodes::Document]
360
- # @return [Array<GraphQL::StaticValidation::Error >]
361
- def validate(string_or_document, rules: nil, context: nil)
362
- doc = if string_or_document.is_a?(String)
363
- GraphQL.parse(string_or_document)
364
- else
365
- string_or_document
366
- end
367
- query = GraphQL::Query.new(self, document: doc, context: context)
368
- validator_opts = { schema: self }
369
- rules && (validator_opts[:rules] = rules)
370
- validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
371
- res = validator.validate(query, timeout: validate_timeout)
372
- res[:errors]
373
- end
374
-
375
359
  def deprecated_define(**kwargs, &block)
376
360
  super
377
361
  ensure_defined
@@ -712,6 +696,7 @@ module GraphQL
712
696
  def_delegators :_schema_class, :unauthorized_object, :unauthorized_field, :inaccessible_fields
713
697
  def_delegators :_schema_class, :directive
714
698
  def_delegators :_schema_class, :error_handler
699
+ def_delegators :_schema_class, :validate
715
700
 
716
701
 
717
702
  # Given this schema member, find the class-based definition object
@@ -861,7 +846,6 @@ module GraphQL
861
846
  def_delegators :graphql_definition,
862
847
  # Execution
863
848
  :execution_strategy_for_operation,
864
- :validate,
865
849
  # Configuration
866
850
  :metadata, :redefine,
867
851
  :id_from_object_proc, :object_from_id_proc,
@@ -1293,6 +1277,23 @@ module GraphQL
1293
1277
  end
1294
1278
  end
1295
1279
 
1280
+ # Validate a query string according to this schema.
1281
+ # @param string_or_document [String, GraphQL::Language::Nodes::Document]
1282
+ # @return [Array<GraphQL::StaticValidation::Error >]
1283
+ def validate(string_or_document, rules: nil, context: nil)
1284
+ doc = if string_or_document.is_a?(String)
1285
+ GraphQL.parse(string_or_document)
1286
+ else
1287
+ string_or_document
1288
+ end
1289
+ query = GraphQL::Query.new(self, document: doc, context: context)
1290
+ validator_opts = { schema: self }
1291
+ rules && (validator_opts[:rules] = rules)
1292
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
1293
+ res = validator.validate(query, timeout: validate_timeout)
1294
+ res[:errors]
1295
+ end
1296
+
1296
1297
  attr_writer :max_complexity
1297
1298
 
1298
1299
  def max_complexity(max_complexity = nil)
@@ -1582,10 +1583,7 @@ module GraphQL
1582
1583
  # @param new_directive [Class]
1583
1584
  # @return void
1584
1585
  def directive(new_directive)
1585
- own_directives[new_directive.graphql_name] ||= begin
1586
- add_type_and_traverse(new_directive, root: false)
1587
- new_directive
1588
- end
1586
+ add_type_and_traverse(new_directive, root: false)
1589
1587
  end
1590
1588
 
1591
1589
  def default_directives
@@ -1709,6 +1707,30 @@ module GraphQL
1709
1707
 
1710
1708
  private
1711
1709
 
1710
+ # @param t [Module, Array<Module>]
1711
+ # @return [void]
1712
+ def add_type_and_traverse(t, root:)
1713
+ if root
1714
+ @root_types ||= []
1715
+ @root_types << t
1716
+ end
1717
+ new_types = Array(t)
1718
+ addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
1719
+ own_types.merge!(addition.types)
1720
+ own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
1721
+ own_union_memberships.merge!(addition.union_memberships)
1722
+
1723
+ addition.references.each { |thing, pointers|
1724
+ pointers.each { |pointer| references_to(thing, from: pointer) }
1725
+ }
1726
+
1727
+ addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
1728
+
1729
+ addition.arguments_with_default_values.each do |arg|
1730
+ arg.validate_default_value
1731
+ end
1732
+ end
1733
+
1712
1734
  def lazy_methods
1713
1735
  if !defined?(@lazy_methods)
1714
1736
  if inherited_map = find_inherited_value(:lazy_methods)
@@ -1774,202 +1796,6 @@ module GraphQL
1774
1796
  def own_multiplex_analyzers
1775
1797
  @own_multiplex_analyzers ||= []
1776
1798
  end
1777
-
1778
- # @param t [Module, Array<Module>]
1779
- # @return [void]
1780
- def add_type_and_traverse(t, root:)
1781
- if root
1782
- @root_types ||= []
1783
- @root_types << t
1784
- end
1785
- late_types = []
1786
- new_types = Array(t)
1787
- new_types.each { |t| add_type(t, owner: nil, late_types: late_types, path: [t.graphql_name]) }
1788
- missed_late_types = 0
1789
- while (late_type_vals = late_types.shift)
1790
- type_owner, lt = late_type_vals
1791
- if lt.is_a?(String)
1792
- type = Member::BuildType.constantize(lt)
1793
- # Reset the counter, since we might succeed next go-round
1794
- missed_late_types = 0
1795
- update_type_owner(type_owner, type)
1796
- add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
1797
- elsif lt.is_a?(LateBoundType)
1798
- if (type = get_type(lt.graphql_name))
1799
- # Reset the counter, since we might succeed next go-round
1800
- missed_late_types = 0
1801
- update_type_owner(type_owner, type)
1802
- add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
1803
- else
1804
- missed_late_types += 1
1805
- # Add it back to the list, maybe we'll be able to resolve it later.
1806
- late_types << [type_owner, lt]
1807
- if missed_late_types == late_types.size
1808
- # We've looked at all of them and haven't resolved one.
1809
- raise UnresolvedLateBoundTypeError.new(type: lt)
1810
- else
1811
- # Try the next one
1812
- end
1813
- end
1814
- else
1815
- raise ArgumentError, "Unexpected late type: #{lt.inspect}"
1816
- end
1817
- end
1818
- nil
1819
- end
1820
-
1821
- def update_type_owner(owner, type)
1822
- case owner
1823
- when Class
1824
- if owner.kind.union?
1825
- # It's a union with possible_types
1826
- # Replace the item by class name
1827
- owner.assign_type_membership_object_type(type)
1828
- own_possible_types[owner.graphql_name] = owner.possible_types
1829
- elsif type.kind.interface? && owner.kind.object?
1830
- new_interfaces = []
1831
- owner.interfaces.each do |int_t|
1832
- if int_t.is_a?(String) && int_t == type.graphql_name
1833
- new_interfaces << type
1834
- elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
1835
- new_interfaces << type
1836
- else
1837
- # Don't re-add proper interface definitions,
1838
- # they were probably already added, maybe with options.
1839
- end
1840
- end
1841
- owner.implements(*new_interfaces)
1842
- new_interfaces.each do |int|
1843
- pt = own_possible_types[int.graphql_name] ||= []
1844
- if !pt.include?(owner)
1845
- pt << owner
1846
- end
1847
- end
1848
- end
1849
-
1850
- when nil
1851
- # It's a root type
1852
- own_types[type.graphql_name] = type
1853
- when GraphQL::Schema::Field, GraphQL::Schema::Argument
1854
- orig_type = owner.type
1855
- # Apply list/non-null wrapper as needed
1856
- if orig_type.respond_to?(:of_type)
1857
- transforms = []
1858
- while (orig_type.respond_to?(:of_type))
1859
- if orig_type.kind.non_null?
1860
- transforms << :to_non_null_type
1861
- elsif orig_type.kind.list?
1862
- transforms << :to_list_type
1863
- else
1864
- raise "Invariant: :of_type isn't non-null or list"
1865
- end
1866
- orig_type = orig_type.of_type
1867
- end
1868
- transforms.reverse_each { |t| type = type.public_send(t) }
1869
- end
1870
- owner.type = type
1871
- else
1872
- raise "Unexpected update: #{owner.inspect} #{type.inspect}"
1873
- end
1874
- end
1875
-
1876
- def add_type(type, owner:, late_types:, path:)
1877
- if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
1878
- type_class = type.metadata[:type_class]
1879
- if type_class.nil?
1880
- raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
1881
- else
1882
- type = type_class
1883
- end
1884
- elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
1885
- late_types << [owner, type]
1886
- return
1887
- end
1888
-
1889
- if owner.is_a?(Class) && owner < GraphQL::Schema::Union
1890
- um = own_union_memberships[type.graphql_name] ||= []
1891
- um << owner
1892
- end
1893
-
1894
- if (prev_type = own_types[type.graphql_name])
1895
- if prev_type != type
1896
- raise DuplicateTypeNamesError.new(
1897
- type_name: type.graphql_name,
1898
- first_definition: prev_type,
1899
- second_definition: type,
1900
- path: path,
1901
- )
1902
- else
1903
- # This type was already added
1904
- end
1905
- elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
1906
- type.arguments.each do |name, arg|
1907
- arg_type = arg.type.unwrap
1908
- references_to(arg_type, from: arg)
1909
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [name])
1910
- end
1911
- else
1912
- own_types[type.graphql_name] = type
1913
- add_directives_from(type)
1914
- if type.kind.fields?
1915
- type.fields.each do |name, field|
1916
- field_type = field.type.unwrap
1917
- references_to(field_type, from: field)
1918
- field_path = path + [name]
1919
- add_type(field_type, owner: field, late_types: late_types, path: field_path)
1920
- add_directives_from(field)
1921
- field.arguments.each do |arg_name, arg|
1922
- add_directives_from(arg)
1923
- arg_type = arg.type.unwrap
1924
- references_to(arg_type, from: arg)
1925
- add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
1926
- end
1927
- end
1928
- end
1929
- if type.kind.input_object?
1930
- type.arguments.each do |arg_name, arg|
1931
- add_directives_from(arg)
1932
- arg_type = arg.type.unwrap
1933
- references_to(arg_type, from: arg)
1934
- add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
1935
- end
1936
- end
1937
- if type.kind.union?
1938
- own_possible_types[type.graphql_name] = type.possible_types
1939
- type.possible_types.each do |t|
1940
- add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
1941
- end
1942
- end
1943
- if type.kind.interface?
1944
- type.orphan_types.each do |t|
1945
- add_type(t, owner: type, late_types: late_types, path: path + ["orphan_types"])
1946
- end
1947
- end
1948
- if type.kind.object?
1949
- own_possible_types[type.graphql_name] = [type]
1950
- type.interface_type_memberships.each do |interface_type_membership|
1951
- case interface_type_membership
1952
- when Schema::TypeMembership
1953
- interface_type = interface_type_membership.abstract_type
1954
- # We can get these now; we'll have to get late-bound types later
1955
- if interface_type.is_a?(Module)
1956
- implementers = own_possible_types[interface_type.graphql_name] ||= []
1957
- implementers << type
1958
- end
1959
- when String, Schema::LateBoundType
1960
- interface_type = interface_type_membership
1961
- else
1962
- raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
1963
- end
1964
- add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
1965
- end
1966
- end
1967
- end
1968
- end
1969
-
1970
- def add_directives_from(owner)
1971
- owner.directives.each { |dir| directive(dir.class) }
1972
- end
1973
1799
  end
1974
1800
 
1975
1801
  def dataloader_class
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Addition
6
+ attr_reader :directives, :possible_types, :types, :union_memberships, :references, :arguments_with_default_values
7
+
8
+ def initialize(schema:, own_types:, new_types:)
9
+ @schema = schema
10
+ @own_types = own_types
11
+ @directives = Set.new
12
+ @possible_types = {}
13
+ @types = {}
14
+ @union_memberships = {}
15
+ @references = Hash.new { |h, k| h[k] = [] }
16
+ @arguments_with_default_values = []
17
+ add_type_and_traverse(new_types)
18
+ end
19
+
20
+ private
21
+
22
+ def references_to(thing, from:)
23
+ @references[thing] << from
24
+ end
25
+
26
+ def get_type(name)
27
+ @types[name] || @schema.get_type(name)
28
+ end
29
+
30
+ # Lookup using `own_types` here because it's ok to override
31
+ # inherited types by name
32
+ def get_local_type(name)
33
+ @types[name] || @own_types[name]
34
+ end
35
+
36
+ def add_directives_from(owner)
37
+ dirs = owner.directives.map(&:class)
38
+ @directives.merge(dirs)
39
+ add_type_and_traverse(dirs)
40
+ end
41
+
42
+ def add_type_and_traverse(new_types)
43
+ late_types = []
44
+ new_types.each { |t| add_type(t, owner: nil, late_types: late_types, path: [t.graphql_name]) }
45
+ missed_late_types = 0
46
+ while (late_type_vals = late_types.shift)
47
+ type_owner, lt = late_type_vals
48
+ if lt.is_a?(String)
49
+ type = Member::BuildType.constantize(lt)
50
+ # Reset the counter, since we might succeed next go-round
51
+ missed_late_types = 0
52
+ update_type_owner(type_owner, type)
53
+ add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
54
+ elsif lt.is_a?(LateBoundType)
55
+ if (type = get_type(lt.name))
56
+ # Reset the counter, since we might succeed next go-round
57
+ missed_late_types = 0
58
+ update_type_owner(type_owner, type)
59
+ add_type(type, owner: type_owner, late_types: late_types, path: [type.graphql_name])
60
+ else
61
+ missed_late_types += 1
62
+ # Add it back to the list, maybe we'll be able to resolve it later.
63
+ late_types << [type_owner, lt]
64
+ if missed_late_types == late_types.size
65
+ # We've looked at all of them and haven't resolved one.
66
+ raise UnresolvedLateBoundTypeError.new(type: lt)
67
+ else
68
+ # Try the next one
69
+ end
70
+ end
71
+ else
72
+ raise ArgumentError, "Unexpected late type: #{lt.inspect}"
73
+ end
74
+ end
75
+ nil
76
+ end
77
+
78
+ def update_type_owner(owner, type)
79
+ case owner
80
+ when Class
81
+ if owner.kind.union?
82
+ # It's a union with possible_types
83
+ # Replace the item by class name
84
+ owner.assign_type_membership_object_type(type)
85
+ @possible_types[owner.graphql_name] = owner.possible_types
86
+ elsif type.kind.interface? && owner.kind.object?
87
+ new_interfaces = []
88
+ owner.interfaces.each do |int_t|
89
+ if int_t.is_a?(String) && int_t == type.graphql_name
90
+ new_interfaces << type
91
+ elsif int_t.is_a?(LateBoundType) && int_t.graphql_name == type.graphql_name
92
+ new_interfaces << type
93
+ else
94
+ # Don't re-add proper interface definitions,
95
+ # they were probably already added, maybe with options.
96
+ end
97
+ end
98
+ owner.implements(*new_interfaces)
99
+ new_interfaces.each do |int|
100
+ pt = @possible_types[int.graphql_name] ||= []
101
+ if !pt.include?(owner)
102
+ pt << owner
103
+ end
104
+ end
105
+ end
106
+
107
+ when nil
108
+ # It's a root type
109
+ @types[type.graphql_name] = type
110
+ when GraphQL::Schema::Field, GraphQL::Schema::Argument
111
+ orig_type = owner.type
112
+ # Apply list/non-null wrapper as needed
113
+ if orig_type.respond_to?(:of_type)
114
+ transforms = []
115
+ while (orig_type.respond_to?(:of_type))
116
+ if orig_type.kind.non_null?
117
+ transforms << :to_non_null_type
118
+ elsif orig_type.kind.list?
119
+ transforms << :to_list_type
120
+ else
121
+ raise "Invariant: :of_type isn't non-null or list"
122
+ end
123
+ orig_type = orig_type.of_type
124
+ end
125
+ transforms.reverse_each { |t| type = type.public_send(t) }
126
+ end
127
+ owner.type = type
128
+ else
129
+ raise "Unexpected update: #{owner.inspect} #{type.inspect}"
130
+ end
131
+ end
132
+
133
+ def add_type(type, owner:, late_types:, path:)
134
+ if type.respond_to?(:metadata) && type.metadata.is_a?(Hash)
135
+ type_class = type.metadata[:type_class]
136
+ if type_class.nil?
137
+ raise ArgumentError, "Can't add legacy type: #{type} (#{type.class})"
138
+ else
139
+ type = type_class
140
+ end
141
+ elsif type.is_a?(String) || type.is_a?(GraphQL::Schema::LateBoundType)
142
+ late_types << [owner, type]
143
+ return
144
+ end
145
+
146
+ if owner.is_a?(Class) && owner < GraphQL::Schema::Union
147
+ um = @union_memberships[type.graphql_name] ||= []
148
+ um << owner
149
+ end
150
+
151
+ if (prev_type = get_local_type(type.graphql_name))
152
+ if prev_type != type
153
+ raise DuplicateTypeNamesError.new(
154
+ type_name: type.graphql_name,
155
+ first_definition: prev_type,
156
+ second_definition: type,
157
+ path: path,
158
+ )
159
+ else
160
+ # This type was already added
161
+ end
162
+ elsif type.is_a?(Class) && type < GraphQL::Schema::Directive
163
+ @directives << type
164
+ type.arguments.each do |name, arg|
165
+ arg_type = arg.type.unwrap
166
+ references_to(arg_type, from: arg)
167
+ add_type(arg_type, owner: arg, late_types: late_types, path: path + [name])
168
+ if arg.default_value?
169
+ @arguments_with_default_values << arg
170
+ end
171
+ end
172
+ else
173
+ @types[type.graphql_name] = type
174
+ add_directives_from(type)
175
+ if type.kind.fields?
176
+ type.fields.each do |name, field|
177
+ field_type = field.type.unwrap
178
+ references_to(field_type, from: field)
179
+ field_path = path + [name]
180
+ add_type(field_type, owner: field, late_types: late_types, path: field_path)
181
+ add_directives_from(field)
182
+ field.arguments.each do |arg_name, arg|
183
+ add_directives_from(arg)
184
+ arg_type = arg.type.unwrap
185
+ references_to(arg_type, from: arg)
186
+ add_type(arg_type, owner: arg, late_types: late_types, path: field_path + [arg_name])
187
+ if arg.default_value?
188
+ @arguments_with_default_values << arg
189
+ end
190
+ end
191
+ end
192
+ end
193
+ if type.kind.input_object?
194
+ type.arguments.each do |arg_name, arg|
195
+ add_directives_from(arg)
196
+ arg_type = arg.type.unwrap
197
+ references_to(arg_type, from: arg)
198
+ add_type(arg_type, owner: arg, late_types: late_types, path: path + [arg_name])
199
+ if arg.default_value?
200
+ @arguments_with_default_values << arg
201
+ end
202
+ end
203
+ end
204
+ if type.kind.union?
205
+ @possible_types[type.graphql_name] = type.possible_types
206
+ type.possible_types.each do |t|
207
+ add_type(t, owner: type, late_types: late_types, path: path + ["possible_types"])
208
+ end
209
+ end
210
+ if type.kind.interface?
211
+ type.orphan_types.each do |t|
212
+ add_type(t, owner: type, late_types: late_types, path: path + ["orphan_types"])
213
+ end
214
+ end
215
+ if type.kind.object?
216
+ @possible_types[type.graphql_name] = [type]
217
+ type.interface_type_memberships.each do |interface_type_membership|
218
+ case interface_type_membership
219
+ when Schema::TypeMembership
220
+ interface_type = interface_type_membership.abstract_type
221
+ # We can get these now; we'll have to get late-bound types later
222
+ if interface_type.is_a?(Module)
223
+ implementers = @possible_types[interface_type.graphql_name] ||= []
224
+ implementers << type
225
+ end
226
+ when String, Schema::LateBoundType
227
+ interface_type = interface_type_membership
228
+ else
229
+ raise ArgumentError, "Invariant: unexpected type membership for #{type.graphql_name}: #{interface_type_membership.class} (#{interface_type_membership.inspect})"
230
+ end
231
+ add_type(interface_type, owner: type, late_types: late_types, path: path + ["implements"])
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end