Skip to content

Commit

Permalink
Allow interface fields to reference other interfaces (#1089)
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Jul 30, 2021
1 parent 62483e4 commit 0b62790
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ defmodule Absinthe.Phase.Schema.Validation.ObjectMustImplementInterfaces do
:ok
end

defp check_covariant(
%Blueprint.TypeReference.Name{name: iface_name},
%Blueprint.TypeReference.Name{name: type_name},
field_ident,
types
) do
{_, itype} = Enum.find(types, fn {_, %{name: name}} -> name == iface_name end)
{_, type} = Enum.find(types, fn {_, %{name: name}} -> name == type_name end)

check_covariant(itype, type, field_ident, types)
end

defp check_covariant(nil, _, field_ident, _), do: {:error, field_ident}
defp check_covariant(_, nil, field_ident, _), do: {:error, field_ident}

Expand Down
28 changes: 28 additions & 0 deletions test/absinthe/schema/notation/experimental/import_sdl_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule Absinthe.Schema.Notation.Experimental.ImportSdlTest do
scalarEcho(input: CoolScalar): CoolScalar
namedThings: [Named]
titledThings: [Titled]
playerField: PlayerInterface
}
scalar CoolScalar
Expand Down Expand Up @@ -97,6 +98,22 @@ defmodule Absinthe.Schema.Notation.Experimental.ImportSdlTest do
duration: Int!
}
interface PlayerInterface {
metadata: PlayerMetadataInterface
}
interface PlayerMetadataInterface {
displayName: String
}
type HumanPlayer implements PlayerInterface {
metadata: HumanMetadata
}
type HumanMetadata implements PlayerMetadataInterface {
displayName: String
}
scalar B
union SearchResult = Post | User
Expand Down Expand Up @@ -173,6 +190,14 @@ defmodule Absinthe.Schema.Notation.Experimental.ImportSdlTest do
[{:resolve_type, &__MODULE__.titled_resolve_type/2}]
end

def hydrate(%{identifier: :player_interface}, _) do
[{:resolve_type, &__MODULE__.player_interface/2}]
end

def hydrate(%{identifier: :player_metadata_interface}, _) do
[{:resolve_type, &__MODULE__.player_metadata_interface/2}]
end

def hydrate(%{identifier: :content}, _) do
[{:resolve_type, &__MODULE__.content_resolve_type/2}]
end
Expand Down Expand Up @@ -231,6 +256,9 @@ defmodule Absinthe.Schema.Notation.Experimental.ImportSdlTest do

def parse_cool_scalar(value), do: {:ok, value}
def serialize_cool_scalar(%{value: value}), do: value

def player_interface(_, _), do: :human_player
def player_metadata_interface(_, _), do: :human_metadata
end

describe "custom prototype schema" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,60 @@ defmodule Absinthe.Schema.Rule.ObjectMustImplementInterfacesTest do
InterfaceImplementsInterfaces.__absinthe_interface_implementors__()
end

defmodule InterfaceFieldsReferenceInterfaces do
use Absinthe.Schema

import_sdl """
interface Pet {
food: PetFood!
}
interface PetFood {
brand: String!
}
type Dog implements Pet {
food: DogFood!
}
type DogFood implements PetFood {
brand: String!
}
type Cat implements Pet {
food: CatFood!
}
type CatFood implements PetFood {
brand: String!
}
"""

query do
end

def hydrate(%{identifier: :pet}, _) do
[{:resolve_type, &__MODULE__.pet/2}]
end

def hydrate(%{identifier: :pet_food}, _) do
[{:resolve_type, &__MODULE__.pet_food/2}]
end

def hydrate(_, _), do: []

def pet(_, _), do: nil
def pet_food(_, _), do: nil
end

test "interface fields can reference other interfaces" do
assert %{
pet: [:dog, :cat],
pet_food: [:dog_food, :cat_food]
} ==
InterfaceImplementsInterfaces.__absinthe_interface_implementors__()
end

test "is enforced" do
assert_schema_error("invalid_interface_types", [
%{
Expand Down

0 comments on commit 0b62790

Please sign in to comment.