Skip to content

Commit 826625b

Browse files
committed
Fix loads-only Interface type check
1 parent 0b31daa commit 826625b

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

lib/graphql/schema/member/has_arguments.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ def authorize_application_object(argument, id, context, loaded_application_objec
370370
end
371371

372372
passes_possible_types_check = if context.types.loadable?(arg_loads_type, context)
373-
if arg_loads_type.kind.union?
374-
# This union is used in `loads:` but not otherwise visible to this query
373+
if arg_loads_type.kind.abstract?
374+
# This union/interface is used in `loads:` but not otherwise visible to this query
375375
context.types.loadable_possible_types(arg_loads_type, context).include?(application_object_type)
376376
else
377377
true

lib/graphql/schema/warden.rb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,17 @@ def loadable?(type, _ctx)
237237
(type.respond_to?(:interfaces) ? interfaces(type).all? { |i| loadable?(i, _ctx) } : true)
238238
end
239239

240-
def loadable_possible_types(union_type, _ctx)
240+
# This abstract type was determined to be used for `loads` only.
241+
# All its possible types are valid possibilities here -- no filtering.
242+
def loadable_possible_types(abstract_type, _ctx)
241243
@loadable_possible_types ||= read_through do |t|
242-
t.possible_types # unfiltered
244+
if t.is_a?(Class) # union
245+
t.possible_types
246+
else
247+
@schema.possible_types(abstract_type)
248+
end
243249
end
244-
@loadable_possible_types[union_type]
250+
@loadable_possible_types[abstract_type]
245251
end
246252

247253
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)

spec/graphql/schema/interface_spec.rb

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,4 +699,72 @@ def pet(name:)
699699
assert_nil int2.comment
700700
end
701701
end
702+
703+
describe "when used as loads" do
704+
class InterfaceLoadsSchema < GraphQL::Schema
705+
module Sharpenable
706+
include GraphQL::Schema::Interface
707+
field :is_sharp, Boolean
708+
end
709+
710+
class Pencil < GraphQL::Schema::Object
711+
implements Sharpenable
712+
field :color, String
713+
end
714+
715+
class Chisel < GraphQL::Schema::Object
716+
implements Sharpenable
717+
field :width, Float
718+
end
719+
720+
class Mallet < GraphQL::Schema::Object
721+
field :weight, Float
722+
end
723+
724+
class Tool < GraphQL::Schema::Union
725+
possible_types(Mallet, Chisel, Pencil)
726+
end
727+
728+
class Query < GraphQL::Schema::Object
729+
field :tool, Tool do
730+
argument :id, ID, loads: Sharpenable, as: :sharpenable_object
731+
end
732+
733+
def tool(sharpenable_object:)
734+
sharpenable_object
735+
end
736+
end
737+
738+
query(Query)
739+
if ADD_WARDEN
740+
use GraphQL::Schema::Warden
741+
else
742+
use GraphQL::Schema::Visibility
743+
end
744+
745+
def self.resolve_type(abs_type, obj, ctx)
746+
obj[:object_type]
747+
end
748+
749+
def self.object_from_id(id, ctx)
750+
case id
751+
when "chisel"
752+
{ width: 5, is_sharp: true, object_type: Chisel }
753+
when "pencil"
754+
{ color: "gray", is_sharp: false, object_type: Pencil }
755+
when "mallet"
756+
{ weight: 16, object_type: Mallet }
757+
else
758+
nil
759+
end
760+
end
761+
end
762+
763+
it "typechecks the loaded object" do
764+
assert_equal({ "tool" => { "__typename" => "Chisel" } }, InterfaceLoadsSchema.execute("{ tool(id: \"chisel\") { __typename } }")["data"])
765+
assert_equal({ "tool" => { "__typename" => "Pencil" } }, InterfaceLoadsSchema.execute("{ tool(id: \"pencil\") { __typename } }")["data"])
766+
767+
assert_equal(["No object found for `id: \"mallet\"`"], InterfaceLoadsSchema.execute("{ tool(id: \"mallet\") { __typename } }")["errors"].map {|e| e["message"]})
768+
end
769+
end
702770
end

0 commit comments

Comments
 (0)