/
notation.ex
120 lines (97 loc) · 3.13 KB
/
notation.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
defmodule Absinthe.Relay.Schema.Notation do
@moduledoc """
Used to extend a module where Absinthe types are defined with
Relay-specific macros and types.
See `Absinthe.Relay`.
"""
@typedoc "A valid flavor"
@type flavor :: :classic | :modern
@valid_flavors [:classic, :modern]
# TODO: Change to `:modern` in v1.5
@default_flavor :classic
@flavor_namespaces [
modern: Modern,
classic: Classic
]
defmacro __using__(flavor) when flavor in @valid_flavors do
notations(flavor)
end
defmacro __using__([]) do
[
# TODO: Remove warning in v1.5
quote do
warning = """
Defaulting to :classic as the flavor of Relay to target. \
Note this defaulting behavior will change to :modern in absinthe_relay v1.5. \
To prevent seeing this notice in the meantime, explicitly provide :classic \
or :modern as an option when you use Absinthe.Relay.Schema or \
Absinthe.Relay.Schema.Notation. See the Absinthe.Relay @moduledoc \
for more information. \
"""
IO.warn(warning)
end,
notations(@default_flavor)
]
end
@spec notations(flavor) :: Macro.t()
defp notations(flavor) do
mutation_notation = Absinthe.Relay.Mutation.Notation |> flavored(flavor)
quote do
import Absinthe.Relay.Node.Notation, only: :macros
import Absinthe.Relay.Node.Helpers
import Absinthe.Relay.Connection.Notation, only: :macros
import unquote(mutation_notation), only: :macros
end
end
@spec flavored(module, flavor) :: module
defp flavored(module, flavor) do
Module.safe_concat(module, Keyword.fetch!(@flavor_namespaces, flavor))
end
@doc false
def input(style, identifier, block) do
quote do
# We need to go up 2 levels so we can create the input object
Absinthe.Schema.Notation.stash()
Absinthe.Schema.Notation.stash()
input_object unquote(identifier) do
private(:absinthe_relay, :input, {:fill, unquote(style)})
unquote(block)
end
# Back down to finish the field
Absinthe.Schema.Notation.pop()
Absinthe.Schema.Notation.pop()
end
end
@doc false
def output(style, identifier, block) do
quote do
Absinthe.Schema.Notation.stash()
Absinthe.Schema.Notation.stash()
object unquote(identifier) do
private(:absinthe_relay, :payload, {:fill, unquote(style)})
unquote(block)
end
Absinthe.Schema.Notation.pop()
Absinthe.Schema.Notation.pop()
end
end
@doc false
def payload(meta, [field_ident | rest], block) do
block = rewrite_input_output(field_ident, block)
{:field, meta, [field_ident, ident(field_ident, :payload) | rest] ++ [[do: block]]}
end
defp rewrite_input_output(field_ident, block) do
Macro.prewalk(block, fn
{:input, meta, [[do: block]]} ->
{:input, meta, [ident(field_ident, :input), [do: block]]}
{:output, meta, [[do: block]]} ->
{:output, meta, [ident(field_ident, :payload), [do: block]]}
node ->
node
end)
end
@doc false
def ident(base_identifier, category) do
:"#{base_identifier}_#{category}"
end
end