Skip to content

Commit ea734f1

Browse files
committed
type extensions from definition.
1 parent 3664b84 commit ea734f1

2 files changed

Lines changed: 162 additions & 21 deletions

File tree

lib/graphql/schema/build_from_definition.rb

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,13 @@ def build(schema_superclass, document, default_resolve:, using: {}, base_types:
8686
case definition
8787
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
8888
nil # already handled
89-
when GraphQL::Language::Nodes::SchemaExtension
89+
when GraphQL::Language::Nodes::SchemaExtension,
90+
GraphQL::Language::Nodes::ScalarTypeExtension,
91+
GraphQL::Language::Nodes::ObjectTypeExtension,
92+
GraphQL::Language::Nodes::InterfaceTypeExtension,
93+
GraphQL::Language::Nodes::UnionTypeExtension,
94+
GraphQL::Language::Nodes::EnumTypeExtension,
95+
GraphQL::Language::Nodes::InputObjectTypeExtension
9096
schema_extensions ||= []
9197
schema_extensions << definition
9298
else
@@ -203,7 +209,34 @@ def self.inherited(child_class)
203209

204210
if schema_extensions
205211
schema_extensions.each do |ext|
206-
build_directives(schema_class, ext, type_resolver)
212+
case ext
213+
when GraphQL::Language::Nodes::SchemaExtension
214+
build_directives(schema_class, ext, type_resolver)
215+
when GraphQL::Language::Nodes::ScalarTypeExtension
216+
build_directives(schema_class.get_type(ext.name), ext, type_resolver)
217+
when GraphQL::Language::Nodes::ObjectTypeExtension
218+
object_type = schema_class.get_type(ext.name)
219+
build_directives(object_type, ext, type_resolver)
220+
build_fields(object_type, ext.fields, type_resolver, default_resolve: true)
221+
build_interfaces(object_type, ext.interfaces, type_resolver)
222+
when GraphQL::Language::Nodes::InterfaceTypeExtension
223+
interface_type = schema_class.get_type(ext.name)
224+
build_directives(interface_type, ext, type_resolver)
225+
build_fields(interface_type, ext.fields, type_resolver, default_resolve: nil)
226+
build_interfaces(interface_type, ext.interfaces, type_resolver)
227+
when GraphQL::Language::Nodes::UnionTypeExtension
228+
union_type = schema_class.get_type(ext.name)
229+
build_directives(union_type, ext, type_resolver)
230+
union_type.possible_types(*ext.types.map { |type_name| type_resolver.call(type_name) })
231+
when GraphQL::Language::Nodes::EnumTypeExtension
232+
enum_type = schema_class.get_type(ext.name)
233+
build_directives(enum_type, ext, type_resolver)
234+
build_values(enum_type, ext.values, type_resolver)
235+
when GraphQL::Language::Nodes::InputObjectTypeExtension
236+
input_object_type = schema_class.get_type(ext.name)
237+
build_directives(input_object_type, ext, type_resolver)
238+
build_arguments(input_object_type, ext.fields, type_resolver)
239+
end
207240
end
208241
end
209242

@@ -300,15 +333,19 @@ def build_enum_type(enum_type_definition, type_resolver, base_type)
300333
builder.build_directives(self, enum_type_definition, type_resolver)
301334
description(enum_type_definition.description)
302335
ast_node(enum_type_definition)
303-
enum_type_definition.values.each do |enum_value_definition|
304-
value(enum_value_definition.name,
305-
value: enum_value_definition.name,
306-
deprecation_reason: builder.build_deprecation_reason(enum_value_definition.directives),
307-
description: enum_value_definition.description,
308-
directives: builder.prepare_directives(enum_value_definition, type_resolver),
309-
ast_node: enum_value_definition,
310-
)
311-
end
336+
builder.build_values(self, enum_type_definition.values, type_resolver)
337+
end
338+
end
339+
340+
def build_values(type_class, enum_value_definitions, type_resolver)
341+
enum_value_definitions.each do |enum_value_definition|
342+
type_class.value(enum_value_definition.name,
343+
value: enum_value_definition.name,
344+
deprecation_reason: build_deprecation_reason(enum_value_definition.directives),
345+
description: enum_value_definition.description,
346+
directives: prepare_directives(enum_value_definition, type_resolver),
347+
ast_node: enum_value_definition,
348+
)
312349
end
313350
end
314351

@@ -364,16 +401,17 @@ def build_object_type(object_type_definition, type_resolver, base_type)
364401
description(object_type_definition.description)
365402
ast_node(object_type_definition)
366403
builder.build_directives(self, object_type_definition, type_resolver)
367-
368-
object_type_definition.interfaces.each do |interface_name|
369-
interface_defn = type_resolver.call(interface_name)
370-
implements(interface_defn)
371-
end
372-
404+
builder.build_interfaces(self, object_type_definition.interfaces, type_resolver)
373405
builder.build_fields(self, object_type_definition.fields, type_resolver, default_resolve: true)
374406
end
375407
end
376408

409+
def build_interfaces(type_class, interface_names, type_resolver)
410+
interface_names.each do |interface_name|
411+
type_class.implements(type_resolver.call(interface_name))
412+
end
413+
end
414+
377415
def build_input_object_type(input_object_type_definition, type_resolver, base_type)
378416
builder = self
379417
Class.new(base_type) do
@@ -442,10 +480,7 @@ def build_interface_type(interface_type_definition, type_resolver, base_type)
442480
include base_type
443481
graphql_name(interface_type_definition.name)
444482
description(interface_type_definition.description)
445-
interface_type_definition.interfaces.each do |interface_name|
446-
interface_defn = type_resolver.call(interface_name)
447-
implements(interface_defn)
448-
end
483+
builder.build_interfaces(self, interface_type_definition.interfaces, type_resolver)
449484
ast_node(interface_type_definition)
450485
builder.build_directives(self, interface_type_definition, type_resolver)
451486

spec/graphql/schema/build_from_definition_spec.rb

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,112 @@ module MyInterface
17921792
end
17931793
end
17941794

1795+
describe "Type extensions" do
1796+
it "Extends object types with fields and directives" do
1797+
sdl = %|
1798+
directive @a on OBJECT
1799+
directive @b on OBJECT
1800+
type T @a { a:Int }
1801+
extend type T @b { b:Int }
1802+
type Query { t:T }
1803+
|
1804+
schema = GraphQL::Schema.from_definition(sdl)
1805+
assert_equal ["a", "b"], schema.get_type("T").fields.keys.sort
1806+
assert_equal ["a", "b"], schema.get_type("T").directives.map(&:graphql_name).sort
1807+
end
1808+
1809+
it "Extends object types with interfaces" do
1810+
sdl = %|
1811+
interface A { a:Int }
1812+
interface B { b:Int }
1813+
type T implements A { a:Int }
1814+
extend type T implements B { b:Int }
1815+
type Query { t:T }
1816+
|
1817+
schema = GraphQL::Schema.from_definition(sdl)
1818+
assert_equal ["A", "B"], schema.get_type("T").interfaces.map(&:graphql_name).sort
1819+
end
1820+
1821+
it "Extends interface types with fields and directives" do
1822+
sdl = %|
1823+
directive @a on INTERFACE
1824+
directive @b on INTERFACE
1825+
interface I @a { a:Int }
1826+
extend interface I @b { b:Int }
1827+
type T implements I { a:Int b:Int }
1828+
type Query { t:T }
1829+
|
1830+
schema = GraphQL::Schema.from_definition(sdl)
1831+
assert_equal ["a", "b"], schema.get_type("I").fields.keys.sort
1832+
assert_equal ["a", "b"], schema.get_type("I").directives.map(&:graphql_name).sort
1833+
end
1834+
1835+
it "Extends interface types with interfaces" do
1836+
sdl = %|
1837+
interface A { a:Int }
1838+
interface B { b:Int }
1839+
extend interface A implements B { b:Int }
1840+
type T implements A { a:Int b:Int }
1841+
type Query { t:T }
1842+
|
1843+
schema = GraphQL::Schema.from_definition(sdl)
1844+
assert_equal ["B"], schema.get_type("A").interfaces.map(&:graphql_name).sort
1845+
end
1846+
1847+
it "Extends scalar types with directives" do
1848+
sdl = %|
1849+
directive @a on SCALAR
1850+
directive @b on SCALAR
1851+
scalar T @a
1852+
extend scalar T @b
1853+
type Query { t:T }
1854+
|
1855+
schema = GraphQL::Schema.from_definition(sdl)
1856+
assert_equal ["a", "b"], schema.get_type("T").directives.map(&:graphql_name).sort
1857+
end
1858+
1859+
it "Extends enum types with values and directives" do
1860+
sdl = %|
1861+
directive @a on ENUM
1862+
directive @b on ENUM
1863+
enum T @a { YES }
1864+
extend enum T @b { NO }
1865+
type Query { t:T }
1866+
|
1867+
schema = GraphQL::Schema.from_definition(sdl)
1868+
assert_equal ["NO", "YES"], schema.get_type("T").values.keys.sort
1869+
assert_equal ["a", "b"], schema.get_type("T").directives.map(&:graphql_name).sort
1870+
end
1871+
1872+
it "Extends input object types with arguments and directives" do
1873+
sdl = %|
1874+
directive @a on INPUT_OBJECT
1875+
directive @b on INPUT_OBJECT
1876+
input T @a { a:Int }
1877+
extend input T @b { b:Int }
1878+
type Query { t:T }
1879+
|
1880+
schema = GraphQL::Schema.from_definition(sdl)
1881+
assert_equal ["a", "b"], schema.get_type("T").arguments.keys.sort
1882+
assert_equal ["a", "b"], schema.get_type("T").directives.map(&:graphql_name).sort
1883+
end
1884+
1885+
it "Extends union types with types and directives" do
1886+
sdl = %|
1887+
directive @a on UNION
1888+
directive @b on UNION
1889+
type A { a:Int }
1890+
type B { b:Int }
1891+
union T @a = A
1892+
extend union T @b = B
1893+
type Query { t:T }
1894+
|
1895+
schema = GraphQL::Schema.from_definition(sdl)
1896+
assert_equal ["A", "B"], schema.possible_types(schema.get_type("T")).map(&:graphql_name).sort
1897+
assert_equal ["a", "b"], schema.get_type("T").directives.map(&:graphql_name).sort
1898+
end
1899+
end
1900+
17951901
if USING_C_PARSER
17961902
it "makes frozen identifiers with CParser" do
17971903
schema_class = GraphQL::Schema.from_definition("type Query { f: Boolean }")

0 commit comments

Comments
 (0)