graphql 1.12.10 → 1.12.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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"
@@ -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