Skip to content

Commit da44191

Browse files
author
Robert Mosolgo
authored
Merge pull request #3496 from rmosolgo/better-schema-setup
Extract logic for schema setup
2 parents d7a5bc3 + ce87338 commit da44191

File tree

4 files changed

+400
-200
lines changed

4 files changed

+400
-200
lines changed

lib/graphql/schema.rb

Lines changed: 26 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# frozen_string_literal: true
2+
require "graphql/schema/addition"
23
require "graphql/schema/base_64_encoder"
34
require "graphql/schema/catchall_middleware"
45
require "graphql/schema/default_parse_error"
@@ -1582,10 +1583,7 @@ def directives(*new_directives)
15821583
# @param new_directive [Class]
15831584
# @return void
15841585
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)
15891587
end
15901588

15911589
def default_directives
@@ -1709,6 +1707,30 @@ def query_stack_error(query, err)
17091707

17101708
private
17111709

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+
17121734
def lazy_methods
17131735
if !defined?(@lazy_methods)
17141736
if inherited_map = find_inherited_value(:lazy_methods)
@@ -1774,202 +1796,6 @@ def own_middleware
17741796
def own_multiplex_analyzers
17751797
@own_multiplex_analyzers ||= []
17761798
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
19731799
end
19741800

19751801
def dataloader_class

0 commit comments

Comments
 (0)