Skip to content

Commit 0f3cd9f

Browse files
committed
dedupe interfaces in introspection query
unsure if this is the right way to do it
1 parent bddf759 commit 0f3cd9f

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

lib/graphql/language/printer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def print_object_type_definition(object_type)
170170
end
171171

172172
def print_implements(type)
173-
" implements #{type.interfaces.map(&:name).uniq.join(" & ")}"
173+
" implements #{type.interfaces.map(&:name).join(" & ")}"
174174
end
175175

176176
def print_input_value_definition(input_value)

lib/graphql/schema/member/has_interfaces.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def interfaces(context = GraphQL::Query::NullContext)
8080
visible_interfaces.concat(superclass.interfaces(context))
8181
end
8282

83-
visible_interfaces
83+
visible_interfaces.uniq
8484
end
8585
end
8686
end

spec/graphql/schema/interface_spec.rb

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,100 @@ class Query < GraphQL::Schema::Object
224224
end
225225
end
226226

227+
describe "transitive implemention of same interface twice" do
228+
class TransitiveInterfaceSchema < GraphQL::Schema
229+
module Node
230+
include GraphQL::Schema::Interface
231+
field :id, ID
232+
233+
def id; "id"; end
234+
end
235+
236+
module Named
237+
include GraphQL::Schema::Interface
238+
implements Node
239+
field :name, String
240+
241+
def name; "name"; end
242+
end
243+
244+
module Timestamped
245+
include GraphQL::Schema::Interface
246+
implements Node
247+
field :timestamp, String
248+
249+
def timestamp; "ts"; end
250+
end
251+
252+
class Query < GraphQL::Schema::Object
253+
implements Named
254+
implements Timestamped
255+
end
256+
257+
query(Query)
258+
end
259+
260+
it "allows running queries on transitive interfaces" do
261+
result = TransitiveInterfaceSchema.execute("{ id name timestamp }")
262+
263+
assert_equal "id", result["data"]["id"]
264+
assert_equal "name", result["data"]["name"]
265+
assert_equal "ts", result["data"]["timestamp"]
266+
267+
result2 = TransitiveInterfaceSchema.execute(<<-GRAPHQL)
268+
{
269+
...on Node { id }
270+
...on Named {
271+
nid: id name
272+
...on Node { nnid: id }
273+
}
274+
... on Timestamped { tid: id timestamp }
275+
}
276+
GRAPHQL
277+
278+
assert_equal "id", result2["data"]["id"]
279+
assert_equal "id", result2["data"]["nid"]
280+
assert_equal "id", result2["data"]["tid"]
281+
assert_equal "name", result2["data"]["name"]
282+
assert_equal "ts", result2["data"]["timestamp"]
283+
end
284+
285+
it "has the right structure" do
286+
expected_schema = <<-SCHEMA
287+
interface Named implements Node {
288+
id: ID
289+
name: String
290+
}
291+
292+
interface Node {
293+
id: ID
294+
}
295+
296+
type Query implements Named & Node & Timestamped {
297+
id: ID
298+
name: String
299+
timestamp: String
300+
}
301+
302+
interface Timestamped implements Node {
303+
id: ID
304+
timestamp: String
305+
}
306+
SCHEMA
307+
assert_equal expected_schema, TransitiveInterfaceSchema.to_definition
308+
end
309+
310+
it "only lists each implemented interface once when introspecting" do
311+
introspection = TransitiveInterfaceSchema.as_json
312+
query_type = introspection.dig("data", "__schema", "types").find do |type|
313+
type["name"] == "Query"
314+
end
315+
interfaces_names = query_type["interfaces"].map { |i| i["name"] }.sort
316+
317+
assert_equal interfaces_names, ["Named", "Node", "Timestamped"]
318+
end
319+
end
320+
227321
describe "migrated legacy tests" do
228322
let(:interface) { Dummy::Edible }
229323

0 commit comments

Comments
 (0)