graphql 1.12.8 → 1.12.14
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/generators/graphql/install_generator.rb +1 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -2
- data/lib/graphql.rb +10 -10
- data/lib/graphql/backtrace/table.rb +14 -2
- data/lib/graphql/backtrace/tracer.rb +7 -4
- data/lib/graphql/cop/nullability.rb +28 -0
- data/lib/graphql/cop/resolve_methods.rb +28 -0
- data/lib/graphql/dataloader.rb +59 -15
- data/lib/graphql/dataloader/null_dataloader.rb +1 -0
- data/lib/graphql/execution/execute.rb +1 -1
- data/lib/graphql/execution/interpreter.rb +4 -8
- data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -2
- data/lib/graphql/execution/interpreter/resolve.rb +6 -2
- data/lib/graphql/execution/interpreter/runtime.rb +496 -222
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/introspection/schema_type.rb +1 -1
- data/lib/graphql/pagination/connections.rb +1 -1
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/query/null_context.rb +7 -1
- data/lib/graphql/rake_task.rb +3 -0
- data/lib/graphql/schema.rb +52 -218
- data/lib/graphql/schema/addition.rb +238 -0
- data/lib/graphql/schema/argument.rb +55 -36
- data/lib/graphql/schema/build_from_definition.rb +8 -2
- data/lib/graphql/schema/directive/transform.rb +13 -1
- data/lib/graphql/schema/enum.rb +10 -1
- data/lib/graphql/schema/input_object.rb +13 -17
- data/lib/graphql/schema/loader.rb +8 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +3 -15
- data/lib/graphql/schema/member/build_type.rb +1 -0
- data/lib/graphql/schema/object.rb +19 -5
- data/lib/graphql/schema/printer.rb +11 -16
- data/lib/graphql/schema/resolver.rb +52 -25
- data/lib/graphql/schema/scalar.rb +3 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +17 -8
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +5 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +4 -3
- data/lib/graphql/subscriptions/serialize.rb +8 -1
- data/lib/graphql/types/relay/has_node_field.rb +1 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
- data/lib/graphql/types/relay/node_field.rb +2 -2
- data/lib/graphql/types/relay/nodes_field.rb +2 -2
- data/lib/graphql/version.rb +1 -1
- data/readme.md +0 -3
- metadata +9 -21
- 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
|
-
|
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
|
@@ -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
|
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],
|
data/lib/graphql/query.rb
CHANGED
@@ -270,7 +270,7 @@ module GraphQL
|
|
270
270
|
# @return [String, nil] Returns nil if the query is invalid.
|
271
271
|
def sanitized_query_string(inline_variables: true)
|
272
272
|
with_prepared_ast {
|
273
|
-
|
273
|
+
schema.sanitized_printer.new(self, inline_variables: inline_variables).sanitized_query_string
|
274
274
|
}
|
275
275
|
end
|
276
276
|
|
@@ -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 =
|
21
|
+
@query = NullQuery.new
|
16
22
|
@dataloader = GraphQL::Dataloader::NullDataloader.new
|
17
23
|
@schema = GraphQL::Schema.new
|
18
24
|
@warden = NullWarden.new(
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -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
|
|
data/lib/graphql/schema.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -1633,6 +1631,14 @@ module GraphQL
|
|
1633
1631
|
find_inherited_value(:multiplex_analyzers, EMPTY_ARRAY) + own_multiplex_analyzers
|
1634
1632
|
end
|
1635
1633
|
|
1634
|
+
def sanitized_printer(new_sanitized_printer = nil)
|
1635
|
+
if new_sanitized_printer
|
1636
|
+
@own_sanitized_printer = new_sanitized_printer
|
1637
|
+
else
|
1638
|
+
@own_sanitized_printer || GraphQL::Language::SanitizedPrinter
|
1639
|
+
end
|
1640
|
+
end
|
1641
|
+
|
1636
1642
|
# Execute a query on itself.
|
1637
1643
|
# @see {Query#initialize} for arguments.
|
1638
1644
|
# @return [Hash] query result, ready to be serialized as JSON
|
@@ -1709,6 +1715,30 @@ module GraphQL
|
|
1709
1715
|
|
1710
1716
|
private
|
1711
1717
|
|
1718
|
+
# @param t [Module, Array<Module>]
|
1719
|
+
# @return [void]
|
1720
|
+
def add_type_and_traverse(t, root:)
|
1721
|
+
if root
|
1722
|
+
@root_types ||= []
|
1723
|
+
@root_types << t
|
1724
|
+
end
|
1725
|
+
new_types = Array(t)
|
1726
|
+
addition = Schema::Addition.new(schema: self, own_types: own_types, new_types: new_types)
|
1727
|
+
own_types.merge!(addition.types)
|
1728
|
+
own_possible_types.merge!(addition.possible_types) { |key, old_val, new_val| old_val + new_val }
|
1729
|
+
own_union_memberships.merge!(addition.union_memberships)
|
1730
|
+
|
1731
|
+
addition.references.each { |thing, pointers|
|
1732
|
+
pointers.each { |pointer| references_to(thing, from: pointer) }
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
addition.directives.each { |dir_class| own_directives[dir_class.graphql_name] = dir_class }
|
1736
|
+
|
1737
|
+
addition.arguments_with_default_values.each do |arg|
|
1738
|
+
arg.validate_default_value
|
1739
|
+
end
|
1740
|
+
end
|
1741
|
+
|
1712
1742
|
def lazy_methods
|
1713
1743
|
if !defined?(@lazy_methods)
|
1714
1744
|
if inherited_map = find_inherited_value(:lazy_methods)
|
@@ -1774,202 +1804,6 @@ module GraphQL
|
|
1774
1804
|
def own_multiplex_analyzers
|
1775
1805
|
@own_multiplex_analyzers ||= []
|
1776
1806
|
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
1807
|
end
|
1974
1808
|
|
1975
1809
|
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
|