Skip to content

Commit 756fd3f

Browse files
committed
start on abstract types support
1 parent ddde2d9 commit 756fd3f

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

lib/graphql/execution/next.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def initialize(schema, document, context, variables, root_object)
2121
@data = {}
2222
end
2323

24-
attr_reader :steps_queue, :schema, :context
24+
attr_reader :steps_queue, :schema, :context, :document
2525

2626
def execute
2727
operation = @document.definitions.first # TODO select named operation
@@ -148,6 +148,16 @@ def execute
148148

149149
private
150150

151+
def type_condition_applies?(type_name)
152+
if type_name == @parent_type.graphql_name
153+
true
154+
else
155+
abs_t = @runner.schema.get_type(type_name, @runner.context)
156+
p_types = @runner.schema.possible_types(abs_t, @runner.context)
157+
p_types.include?(@parent_type)
158+
end
159+
end
160+
151161
def gather_selections(ast_selections, into:)
152162
ast_selections.each do |ast_selection|
153163
case ast_selection
@@ -166,9 +176,15 @@ def gather_selections(ast_selections, into:)
166176
step.append_selection(ast_selection)
167177
when GraphQL::Language::Nodes::InlineFragment
168178
type_condition = ast_selection.type.name
169-
if type_condition == @parent_type.graphql_name
179+
if type_condition_applies?(type_condition)
170180
gather_selections(ast_selection.selections, into: into)
171181
end
182+
when GraphQL::Language::Nodes::FragmentSpread
183+
fragment_definition = @runner.document.definitions.find { |defn| defn.is_a?(GraphQL::Language::Nodes::FragmentDefinition) && defn.name == ast_selection.name }
184+
type_condition = fragment_definition.type.name
185+
if type_condition_applies?(type_condition)
186+
gather_selections(fragment_definition.selections, into: into)
187+
end
172188
else
173189
raise ArgumentError, "Unsupported graphql selection node: #{ast_selection.class} (#{ast_selection.inspect})"
174190
end

spec/graphql/execution/next_spec.rb

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ class BaseObject < GraphQL::Schema::Object
2626
field_class BaseField
2727
end
2828

29+
module BaseInterface
30+
include GraphQL::Schema::Interface
31+
field_class BaseField
32+
end
33+
2934
ALL_FAMILIES = [
3035
OpenStruct.new(name: "Legumes", grows_in: ["SPRING", "SUMMER", "FALL"], species: [OpenStruct.new(name: "Snow Pea")]),
3136
OpenStruct.new(name: "Nightshades", grows_in: ["SUMMER"], species: [OpenStruct.new(name: "Tomato")]),
@@ -39,16 +44,34 @@ class Season < GraphQL::Schema::Enum
3944
value "FALL"
4045
end
4146

42-
class PlantSpecies < BaseObject
47+
module Nameable
48+
include BaseInterface
4349
field :name, String, object_method: :name
50+
51+
def self.resolve_type(obj, ctx)
52+
if obj.respond_to?(:grows_in)
53+
PlantFamily
54+
else
55+
PlantSpecies
56+
end
57+
end
58+
end
59+
60+
class PlantSpecies < BaseObject
61+
implements Nameable
62+
field :poisonous, Boolean, value: false
4463
end
4564

4665
class PlantFamily < BaseObject
47-
field :name, String, object_method: :name
66+
implements Nameable
4867
field :grows_in, Season, object_method: :grows_in
4968
field :species, [PlantSpecies], object_method: :species
5069
end
5170

71+
class Thing < GraphQL::Schema::Union
72+
possible_types(PlantFamily, PlantSpecies)
73+
end
74+
5275

5376
class Query < BaseObject
5477
field :families, [PlantFamily], value: ALL_FAMILIES
@@ -72,6 +95,8 @@ def self.all_find_species(objects, context, name:)
7295
end
7396
Array.new(objects.length, species)
7497
end
98+
99+
field :all_things, [Thing], value: ALL_FAMILIES + ALL_FAMILIES.map { |f| f.species }.flatten
75100
end
76101

77102
query(Query)
@@ -86,14 +111,28 @@ def run_next(query_str, root_object: nil)
86111
result = run_next("{
87112
str
88113
families {
89-
name
114+
... on Nameable { name }
90115
... on PlantFamily { growsIn }
91116
}
92117
families { species { name } }
93-
t: findSpecies(name: \"Tomato\") { name }
94-
c: findSpecies(name: \"Cucumber\") { name }
118+
t: findSpecies(name: \"Tomato\") { ...SpeciesInfo ... NameableInfo }
119+
c: findSpecies(name: \"Cucumber\") { name ...SpeciesInfo }
95120
x: findSpecies(name: \"Blue Rasperry\") { name }
96-
}", root_object: "Abc")
121+
allThings {
122+
# __typename
123+
... on Nameable { name }
124+
... on PlantFamily { growsIn }
125+
}
126+
}
127+
128+
fragment SpeciesInfo on PlantSpecies {
129+
poisonous
130+
}
131+
132+
fragment NameableInfo on Nameable {
133+
name
134+
}
135+
", root_object: "Abc")
97136
expected_result = {
98137
"data" => {
99138
"str" => "String",
@@ -102,9 +141,17 @@ def run_next(query_str, root_object: nil)
102141
{"name" => "Nightshades", "growsIn" => ["SUMMER"], "species" => [{"name" => "Tomato"}]},
103142
{"name" => "Curcurbits", "growsIn" => ["SUMMER"], "species" => [{"name" => "Cucumber"}]}
104143
],
105-
"t" => { "name" => "Tomato" },
106-
"c" => { "name" => "Cucumber" },
107-
"x" => nil
144+
"t" => { "name" => "Tomato", "poisonous" => false },
145+
"c" => { "name" => "Cucumber", "poisonous" => false },
146+
"x" => nil,
147+
"allThings" => [
148+
{"name" => "Legumes", "growsIn" => ["SPRING", "SUMMER", "FALL"]},
149+
{"name" => "Nightshades", "growsIn" => ["SUMMER"]},
150+
{"name" => "Curcurbits", "growsIn" => ["SUMMER"]},
151+
{"name" => "Snow Pea"},
152+
{"name" => "Tomato"},
153+
{"name" => "Cucumber"},
154+
]
108155
}
109156
}
110157
assert_equal(expected_result, result)

0 commit comments

Comments
 (0)