Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use absinthe directive macros instead of meta #52

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ defmodule MyApp.MySchema do
+ use Absinthe.Federation.Schema

query do
+ extends()
+ directive :extends

field :review, :review do
arg(:id, non_null(:id))
Expand All @@ -62,12 +62,10 @@ defmodule MyApp.MySchema do
end

object :product do
+ key_fields("upc")
+ extends()
+ directive :key, fields: "upc"
+ directive :extends

field :upc, non_null(:string) do
+ external()
end
+ field :upc, non_null(:string), directives: [:external]

field(:reviews, list_of(:review)) do
resolve(&ReviewResolver.get_reviews_for_product/3)
Expand Down
29 changes: 21 additions & 8 deletions lib/absinthe/federation/notation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,18 @@ defmodule Absinthe.Federation.Notation do
id: ID!
}
"""
defmacro key_fields(fields) when is_binary(fields) or is_list(fields) do
@deprecated "Use absinthe built in directive/2 macro"
defmacro key_fields(fieldset) when is_binary(fieldset) do
quote do
meta :key_fields, unquote(fields)
directive :key, fields: unquote(fieldset)
end
end

defmacro key_fields(fields) when is_list(fields) do
for fieldset <- fields do
quote do
directive :key, fields: unquote(fieldset)
end
end
end

Expand Down Expand Up @@ -75,9 +84,10 @@ defmodule Absinthe.Federation.Notation do
This type extension in the Reviews service extends the User type from the Users service.
It extends it for the purpose of adding a new field called reviews, which returns a list of `Review`s.
"""
@deprecated "Use absinthe built in directive/2 macro"
defmacro external() do
quote do
meta :external, true
directive :external
end
end

Expand Down Expand Up @@ -117,9 +127,10 @@ defmodule Absinthe.Federation.Notation do
to know the `email` of the `User` from the Users service in order to look up the `reviews`.
This means the `reviews` field / resolver requires the `email` field from the base `User` type.
"""
defmacro requires_fields(fields) when is_binary(fields) do
@deprecated "Use absinthe built in directive/2 macro"
defmacro requires_fields(fieldset) when is_binary(fieldset) do
quote do
meta :requires_fields, unquote(fields)
directive :requires, fields: unquote(fieldset)
end
end

Expand Down Expand Up @@ -164,9 +175,10 @@ defmodule Absinthe.Federation.Notation do
can provide it when going from review to product. `Product.name` is an external field
on an external type which is why the local type extension of `Product` and annotation of `name` is required.
"""
defmacro provides_fields(fields) when is_binary(fields) do
@deprecated "Use absinthe built in directive/2 macro"
defmacro provides_fields(fieldset) when is_binary(fieldset) do
quote do
meta :provides_fields, unquote(fields)
directive :provides, fields: unquote(fieldset)
end
end

Expand All @@ -188,9 +200,10 @@ defmodule Absinthe.Federation.Notation do
id: ID!
}
"""
@deprecated "Use absinthe built in directive/2 macro"
defmacro extends() do
quote do
meta :extends, true
directive :extends
end
end
end
1 change: 0 additions & 1 deletion lib/absinthe/federation/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ defmodule Absinthe.Federation.Schema do
def pipeline(pipeline) do
Pipeline.insert_after(pipeline, TypeImports, [
__MODULE__.Phase.AddFederatedTypes,
__MODULE__.Phase.AddFederatedDirectives,
__MODULE__.Phase.Validation.KeyFieldsMustExist,
__MODULE__.Phase.Validation.KeyFieldsMustBeValidWhenExtends
])
Expand Down
86 changes: 0 additions & 86 deletions lib/absinthe/federation/schema/phase/add_federated_directives.ex

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ defmodule Absinthe.Federation.Schema.Phase.Validation.KeyFieldsMustExist do
object

true ->
key_fields = get_in(object.__private__, [:meta, :key_fields])
key_fields = object.directives
|> Enum.filter(fn %{name: name} -> name == "key" end)
|> Enum.map(fn
%{arguments: [%{input_value: %{content: %{value: fieldset}}}]} -> fieldset
%{arguments: [%{value: fieldset}]} -> fieldset
end)
# IO.inspect(object.directives, label: "object.directives")
# IO.inspect(key_fields, label: "key_fields")

validate_key_fields(key_fields, object, adapter)
end
end
Expand Down Expand Up @@ -82,7 +90,7 @@ defmodule Absinthe.Federation.Schema.Phase.Validation.KeyFieldsMustExist do
end

defp is_defining_or_extending?(object) do
not is_nil(get_in(object.__private__, [:meta, :key_fields]))
Enum.find_value(object.directives, false, fn %{name: name} -> name == "key" end)
end

defp in?(key, fields, adapter) do
Expand Down
66 changes: 66 additions & 0 deletions lib/absinthe/federation/schema/prototype.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,25 @@ defmodule Absinthe.Federation.Schema.Prototype do
parse &{:ok, &1}
end

enum :link_purpose, name: "link__Purpose" do
value :security
value :execution
end

scalar :link_import, name: "link__Import" do
serialize & &1
parse &{:ok, &1}
end

@desc """
The `@key` directive is used to indicate a combination of fields that can be used
to uniquely identify and fetch an object or interface.
"""
directive :key do
arg :fields, non_null(:_field_set)
arg :resolvable, :boolean, default_value: true

repeatable true
on [:object, :interface]
end

Expand Down Expand Up @@ -53,4 +66,57 @@ defmodule Absinthe.Federation.Schema.Prototype do
directive :extends do
on [:object, :interface]
end

@desc """
Indicates that an object type's field is allowed to be resolved by multiple subgraphs
(by default, each field can be resolved by only one subgraph).
"""
directive :shareable do
on [:field_definition, :object]
end

@desc """
Indicates that a field or type should be omitted from the gateway's API schema,
even if it's also defined in other subgraphs.
"""
directive :inaccessible do
on [:field_definition, :object, :interface, :union]
end

@desc """
Indicates that a field is now resolved by this subgraph
instead of another subgraph where it's also defined.
"""
directive :override do
arg :from, non_null(:string)
on [:field_definition]
end

@desc """
The @link directive links definitions within the document to external schemas.

External schemas are identified by their url,
which optionally ends with a name and version with the following format:
{NAME}/v{MAJOR}.{MINOR}

The presence of a @link directive makes a document a core schema.

The for argument describes the purpose of a @link.
Currently accepted values are SECURITY or EXECUTION.
Core schema-aware servers such as Apollo Router and Gateway will refuse to operate on schemas that contain @links to unsupported specs which are for: SECURITY or for: EXECUTION.

By default, @linked definitions will be namespaced,
i.e., @federation__requires.
The as argument lets you pick the name for this namespace:
"""
directive :link do
arg :url, :string
arg :as, :string
arg :for, :link_purpose
arg :import, :link_import

repeatable true

on [:schema]
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ defmodule Absinthe.Federation.MixProject do

defp deps do
[
{:absinthe, "~> 1.6.5 or ~> 1.7.0"},
{:absinthe, path: "../../absinthe-graphql/absinthe"},
{:dataloader, "~> 1.0.9"},

# Dev
Expand Down
8 changes: 4 additions & 4 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
%{
"absinthe": {:hex, :absinthe, "1.6.6", "d4b3d87c868264edf47fbf9c152155f31e8d26c370607f5fe92f6e106d190b74", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a03e18478b19bdf81ed1eef9b0853edf4496a080c2048ed17993dc945a90bedc"},
"dataloader": {:hex, :dataloader, "1.0.9", "8fb981e327fa692f741ab283ed93790203a6f6d412800f0f4f1531372e1dbf15", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f8b7566c8dda46f53bdb336fd02f03f00bf58aeb6cc0f139ccdfd6f99d265a7"},
"absinthe": {:git, "https://github.com/absinthe-graphql/absinthe.git", "453fd12c0bbfd938c43a9251a320cfae96dafe16", [branch: "master"]},
"dataloader": {:hex, :dataloader, "1.0.10", "a42f07641b1a0572e0b21a2a5ae1be11da486a6790f3d0d14512d96ff3e3bbe9", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "54cd70cec09addf4b2ace14cc186a283a149fd4d3ec5475b155951bf33cd963f"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"earmark_parser": {:hex, :earmark_parser, "1.4.16", "607709303e1d4e3e02f1444df0c821529af1c03b8578dfc81bb9cf64553d02b9", [:mix], [], "hexpm", "69fcf696168f5a274dd012e3e305027010658b2d1630cef68421d6baaeaccead"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.25.3", "3edf6a0d70a39d2eafde030b8895501b1c93692effcbd21347296c18e47618ce", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "9ebebc2169ec732a38e9e779fd0418c9189b3ca93f4a676c961be6c1527913f5"},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
}
59 changes: 42 additions & 17 deletions test/absinthe/federation/notation_test.exs
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
defmodule Absinthe.Federation.NotationTest do
use Absinthe.Federation.Case, async: true

describe "macro schema" do
defmodule MacroSchema do
use Absinthe.Schema
use Absinthe.Federation.Schema
defmodule FederatedMacroSchema do
use Absinthe.Schema
use Absinthe.Federation.Schema

query do
field :me, :user
end
query do
field :me, :user
end

object :user do
key_fields("id")
extends()
object :user do
key_fields("id")
extends()

field :id, non_null(:id) do
external()
end
field :id, non_null(:id) do
external()
end
end
end

test "can use federation macros" do
sdl = Absinthe.Schema.to_sdl(MacroSchema)
assert sdl =~ "type User @extends @key(fields: \"id\")"
assert sdl =~ "id: ID! @external"
test "can use federation macros" do
sdl = Absinthe.Schema.to_sdl(FederatedMacroSchema)
assert sdl =~ "type User @extends @key(fields: \"id\")"
assert sdl =~ "id: ID! @external"
end

defmodule AbsintheMacroSchema do
use Absinthe.Schema
use Absinthe.Federation.Schema

query do
field :me, :user
end

object :user do
directive :key, fields: "id"
directive :extends

field :id, non_null(:id) do
directive :external
end

field :name, :string, directives: [:provides]
end
end

test "can use absinthe directive macros" do
sdl = Absinthe.Schema.to_sdl(AbsintheMacroSchema)
assert sdl =~ "type User @extends @key(fields: \"id\")"
assert sdl =~ "id: ID! @external"
assert sdl =~ "name: String @provides"
end
end
Loading