Packages
ash
1.47.1
3.29.3
3.29.2
3.29.1
3.29.0
3.28.0
3.27.8
3.27.7
3.27.6
3.27.5
3.27.4
3.27.3
3.27.2
3.27.1
3.27.0
3.26.0
3.25.2
3.25.1
3.25.0
retired
3.24.7
3.24.6
3.24.5
3.24.4
3.24.3
3.24.2
3.24.1
3.24.0
3.23.1
3.23.0
3.22.2
3.22.1
3.22.0
3.21.3
3.21.2
3.21.1
3.21.0
3.20.0
3.19.3
3.19.2
3.19.1
3.19.0
3.18.0
3.17.1
3.17.0
3.16.0
3.15.0
3.14.1
3.14.0
retired
3.13.2
3.13.1
3.13.0
3.12.0
3.11.3
3.11.2
3.11.1
3.11.0
3.10.1
3.10.0
3.9.0
3.8.0
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
retired
3.6.3
retired
3.6.2
3.6.1
3.6.0
3.5.43
3.5.42
3.5.41
3.5.40
3.5.39
3.5.38
3.5.37
3.5.36
3.5.35
3.5.34
3.5.33
3.5.32
3.5.31
3.5.30
3.5.29
3.5.28
3.5.27
3.5.26
3.5.25
3.5.24
3.5.23
3.5.22
3.5.21
3.5.20
3.5.19
3.5.18
3.5.17
3.5.16
3.5.15
3.5.14
3.5.13
3.5.12
3.5.11
3.5.10
3.5.9
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.4.74
retired
3.4.73
3.4.72
3.4.71
3.4.70
3.4.69
3.4.68
3.4.67
3.4.66
3.4.65
3.4.64
3.4.63
3.4.62
3.4.61
3.4.60
3.4.59
3.4.58
3.4.57
3.4.56
3.4.55
3.4.54
3.4.53
3.4.52
3.4.51
3.4.50
3.4.49
3.4.48
3.4.47
3.4.46
3.4.45
3.4.44
3.4.43
3.4.42
3.4.41
3.4.40
3.4.39
3.4.38
3.4.37
3.4.36
3.4.35
3.4.34
3.4.33
3.4.32
3.4.31
3.4.30
3.4.29
3.4.28
3.4.27
3.4.26
3.4.25
3.4.24
3.4.23
3.4.22
3.4.21
3.4.20
3.4.19
3.4.18
3.4.17
3.4.16
3.4.15
3.4.14
3.4.13
3.4.12
3.4.11
3.4.10
3.4.9
3.4.8
3.4.7
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.3
3.3.2
3.3.1
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.16
3.0.15
3.0.14
3.0.13
3.0.12
3.0.11
3.0.10
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.46
3.0.0-rc.45
3.0.0-rc.44
3.0.0-rc.43
3.0.0-rc.42
3.0.0-rc.41
3.0.0-rc.40
3.0.0-rc.39
3.0.0-rc.38
3.0.0-rc.37
3.0.0-rc.36
3.0.0-rc.35
3.0.0-rc.34
3.0.0-rc.33
3.0.0-rc.32
3.0.0-rc.31
3.0.0-rc.29
3.0.0-rc.28
3.0.0-rc.27
3.0.0-rc.26
3.0.0-rc.25
3.0.0-rc.24
3.0.0-rc.23
3.0.0-rc.22
3.0.0-rc.21
3.0.0-rc.20
3.0.0-rc.19
3.0.0-rc.18
3.0.0-rc.17
3.0.0-rc.16
3.0.0-rc.15
3.0.0-rc.14
3.0.0-rc.13
3.0.0-rc.12
3.0.0-rc.11
3.0.0-rc.10
3.0.0-rc.9
3.0.0-rc.8
3.0.0-rc.7
3.0.0-rc.6
3.0.0-rc.5
3.0.0-rc.4
3.0.0-rc.3
3.0.0-rc.1
3.0.0-rc.0
2.21.15
2.21.14
2.21.13
2.21.12
2.21.11
2.21.10
2.21.9
2.21.8
2.21.7
2.21.6
2.21.5
2.21.4
2.21.3
2.21.2
2.21.1
2.21.0
2.20.3
2.20.2
2.20.1
2.20.0
2.19.14
2.19.13
2.19.12
2.19.11
2.19.10
2.19.9
2.19.8
2.19.7
2.19.6
2.19.5
2.19.4
2.19.3
retired
2.19.2
retired
2.19.1
retired
2.19.0
retired
2.18.2
2.18.1
2.18.0
2.17.24
2.17.23
2.17.22
2.17.21
2.17.20
2.17.19
2.17.18
2.17.17
2.17.16
2.17.15
2.17.14
2.17.13
2.17.12
2.17.11
2.17.10
2.17.9
2.17.8
2.17.7
2.17.6
2.17.5
2.17.4
2.17.3
2.17.2
2.17.1
2.17.0
2.16.1
2.16.0
2.15.20
2.15.19
2.15.18
2.15.17
2.15.16
2.15.15
2.15.14
2.15.13
2.15.12
2.15.11
2.15.10
2.15.9
2.15.8
2.15.7
2.15.6
2.15.5
2.15.4
2.15.2
2.15.1
2.15.0
2.14.21
2.14.20
2.14.19
2.14.18
2.14.17
2.14.16
2.14.15
2.14.14
2.14.13
2.14.12
2.14.11
2.14.10
2.14.9
2.14.8
2.14.7
2.14.6
2.14.5
2.14.4
2.14.3
2.14.2
2.14.1
2.14.0
2.13.4
retired
2.13.3
2.13.2
2.13.1
2.13.0
2.12.1
2.12.0
2.11.11
2.11.10
2.11.9
2.11.8
2.11.7
2.11.6
2.11.5
2.11.4
2.11.3
2.11.2
2.11.1
2.11.0
2.11.0-rc.3
2.11.0-rc.2
2.11.0-rc.1
2.11.0-rc.0
2.10.2
2.10.1
2.10.0
2.9.29
2.9.28
2.9.27
2.9.26
2.9.25
2.9.24
2.9.23
2.9.22
2.9.21
2.9.20
2.9.19
2.9.18
2.9.17
2.9.16
2.9.15
2.9.14
2.9.13
2.9.12
2.9.11
2.9.10
2.9.9
2.9.8
2.9.7
2.9.6
2.9.5
2.9.4
2.9.3
2.9.2
2.9.1
2.9.0
2.8.1
2.8.0
2.7.1
2.7.0
2.6.31
2.6.30
2.6.29
2.6.28
2.6.27
2.6.26
2.6.25
2.6.24
2.6.23
2.6.22
2.6.21
2.6.20
2.6.19
2.6.18
2.6.17
2.6.16
2.6.15
2.6.14
2.6.13
2.6.11
2.6.10
2.6.9
2.6.8
2.6.7
2.6.6
2.6.5
2.6.4
2.6.3
2.6.2
2.6.1
2.6.0
2.5.16
2.5.15
2.5.14
2.5.13
2.5.12
2.5.11
2.5.10
2.5.9
2.5.8
2.5.7
2.5.6
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.5.0-rc.6
2.5.0-rc.5
2.5.0-rc.4
2.5.0-rc.3
2.5.0-rc.2
2.5.0-rc.1
2.5.0-rc.0
2.4.30
2.4.29
2.4.28
2.4.27
2.4.26
2.4.25
2.4.24
2.4.23
2.4.22
2.4.21
2.4.20
2.4.19
2.4.18
2.4.17
2.4.16
2.4.15
2.4.14
2.4.13
2.4.12
2.4.11
2.4.10
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
2.0.0-rc.15
2.0.0-rc.14
2.0.0-rc.13
2.0.0-rc.12
2.0.0-rc.11
2.0.0-rc.10
2.0.0-rc.9
2.0.0-rc.8
2.0.0-rc.7
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-pre.8
2.0.0-pre.7
2.0.0-pre.6
2.0.0-pre.5
2.0.0-pre.4
2.0.0-pre.3
2.0.0-pre.2
2.0.0-pre.1
2.0.0-pre.0
1.53.3
1.53.2
1.53.0
1.52.0-rc.22
1.52.0-rc.21
1.52.0-rc.20
1.52.0-rc.19
1.52.0-rc.18
1.52.0-rc.17
1.52.0-rc.16
1.52.0-rc.15
1.52.0-rc.14
1.52.0-rc.13
1.52.0-rc.12
1.52.0-rc.11
1.52.0-rc.10
1.52.0-rc.9
1.52.0-rc.8
1.52.0-rc.7
1.52.0-rc.6
1.52.0-rc.5
1.52.0-rc.4
1.52.0-rc.3
1.52.0-rc.2
1.52.0-rc.1
1.52.0-rc.0
1.51.2
1.51.1
retired
1.51.0
1.50.21
1.50.20
1.50.19
1.50.18
1.50.17
1.50.16
1.50.15
1.50.14
1.50.13
1.50.12
1.50.11
1.50.10
1.50.9
1.50.8
1.50.7
1.50.6
1.50.5
1.50.4
1.50.3
1.50.2
1.50.1
1.50.0
1.49.0
1.48.0-rc.30
1.48.0-rc.29
1.48.0-rc.28
1.48.0-rc.27
1.48.0-rc.26
1.48.0-rc.25
1.48.0-rc.24
1.48.0-rc.23
1.48.0-rc.22
1.48.0-rc.21
1.48.0-rc.20
1.48.0-rc.19
1.48.0-rc.18
1.48.0-rc.17
1.48.0-rc.16
1.48.0-rc.15
1.48.0-rc.14
1.48.0-rc.13
1.48.0-rc.12
1.48.0-rc.11
1.48.0-rc.10
1.48.0-rc.9
1.48.0-rc.8
1.48.0-rc.7
1.48.0-rc.6
1.48.0-rc.5
1.48.0-rc.4
1.48.0-rc.3
1.48.0-rc.2
1.48.0-rc.1
1.48.0-rc.0
1.47.12
1.47.11
1.47.10
1.47.9
1.47.8
1.47.7
1.47.6
1.47.5
1.47.4
1.47.3
1.47.2
1.47.1
1.47.0
1.46.13
1.46.12
1.46.11
1.46.10
1.46.9
1.46.8
1.46.7
1.46.6
1.46.5
1.46.4
1.46.3
1.46.2
1.46.1
1.46.0
1.45.0-rc9
1.45.0-rc8
1.45.0-rc7
1.45.0-rc6
1.45.0-rc5
1.45.0-rc4
1.45.0-rc3
1.45.0-rc20
1.45.0-rc2
1.45.0-rc19
1.45.0-rc18
1.45.0-rc17
1.45.0-rc16
1.45.0-rc15
1.45.0-rc14
1.45.0-rc13
1.45.0-rc12
1.45.0-rc11
1.45.0-rc10
1.45.0-rc1
1.45.0-rc0
1.44.13
1.44.12
1.44.11
1.44.10
1.44.9
1.44.8
1.44.7
1.44.6
1.44.5
1.44.4
1.44.3
1.44.2
1.44.1
1.44.0
1.43.12
1.43.11
1.43.10
1.43.9
1.43.8
1.43.7
1.43.6
1.43.5
1.43.4
1.43.3
1.43.2
1.43.1
1.43.0
1.42.0
1.41.12
1.41.11
1.41.10
1.41.9
1.41.8
1.41.7
1.41.6
1.41.5
1.41.4
1.41.3
1.41.2
1.41.1
1.41.0
1.40.0
1.39.7
1.39.6
1.39.5
1.39.4
1.39.3
1.39.2
1.39.1
1.39.0
1.38.0
1.37.2
1.37.1
1.37.0
1.36.22
1.36.21
1.36.19
1.36.18
1.36.17
1.36.16
1.36.15
1.36.14
1.36.13
1.36.12
1.36.11
1.36.10
1.36.9
1.36.8
1.36.7
1.36.6
1.36.5
1.36.4
1.36.3
1.36.2
1.36.0
1.35.1
1.35.0
1.34.9
1.34.8
1.34.7
1.34.6
1.34.5
1.34.4
1.34.3
1.34.2
1.34.1
1.34.0
1.33.0
1.32.2
1.32.1
1.32.0
1.31.1
1.31.0
1.30.2
1.30.1
1.29.0-rc1
1.29.0-rc0
1.28.1
1.28.0
1.27.1
1.27.0
1.26.13
1.26.12
1.26.11
1.26.10
1.26.9
1.26.8
1.26.7
1.26.6
1.26.5
1.26.4
1.26.2
1.26.1
1.26.0
1.25.8
1.25.7
1.25.6
1.25.5
1.25.4
1.25.3
1.25.2
1.25.1
1.25.0
1.24.2
1.24.1
1.24.0
1.23.3
1.23.2
1.23.1
1.23.0
1.22.1
1.22.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.1
1.18.0
1.17.1
1.17.0
1.16.2
1.15.1
1.15.0
1.14.0
1.13.4
1.13.3
1.13.2
1.13.1
1.13.0
1.12.0
1.11.1
1.11.0
1.10.0
1.9.0
1.8.0
1.7.0
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.1
1.4.0
1.3.1
1.3.0
1.2.1
1.2.0
1.1.3
1.1.2
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
0.13.1
0.13.0
0.12.0
0.10.0
0.9.1
0.9.0
0.8.0
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.9
0.1.8
0.1.3
0.1.1
0.1.0
A declarative, extensible framework for building Elixir applications.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash/api/interface.ex
defmodule Ash.Api.Interface do
@moduledoc false
@doc false
def require_action(resource, interface) do
action = Ash.Resource.Info.action(resource, interface.action || interface.name)
unless action do
raise Ash.Error.Dsl.DslError,
module: resource,
message:
"The interface of #{inspect(resource)} refers to a non-existent action #{
interface.action || interface.name
}",
path: [:interfaces, :interface, interface.name]
end
action
end
defmacro define_interface(api, resource) do
quote bind_quoted: [api: api, resource: resource], generated: true, location: :keep do
for interface <- Ash.Resource.Info.interfaces(resource) do
action = Ash.Api.Interface.require_action(resource, interface)
args = interface.args || []
arg_vars = Enum.map(args, &{&1, [], Elixir})
doc = """
#{
action.description ||
"Calls the #{action.name} action on the #{inspect(resource)} resource."
}
## Options
#{Ash.OptionsHelpers.docs(Ash.Resource.Interface.interface_options(action.type))}
"""
case action.type do
:read ->
@doc doc
@dialyzer {:nowarn_function, {interface.name, Enum.count(args) + 2}}
def unquote(interface.name)(
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(
__MODULE__,
elem(__ENV__.function, 0),
[
unquote_splicing(arg_vars),
%{},
params_or_opts
]
)
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
query =
opts[:query]
|> Kernel.||(unquote(resource))
|> Ash.Query.for_read(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
if unquote(interface.get?) do
query
|> unquote(api).read_one(Keyword.drop(opts, [:query, :tenant]))
|> case do
{:ok, nil} ->
{:error, Ash.Error.Query.NotFound.exception(resource: query.resource)}
{:ok, result} ->
{:ok, result}
{:error, error} ->
{:error, error}
end
else
unquote(api).read(query, Keyword.drop(opts, [:query, :tenant]))
end
end
end
@doc doc
# sobelow_skip ["DOS.BinToAtom"]
@dialyzer {:nowarn_function, {:"#{interface.name}!", Enum.count(args) + 2}}
def unquote(:"#{interface.name}!")(
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(
__MODULE__,
elem(__ENV__.function, 0),
[
unquote_splicing(arg_vars),
%{},
params_or_opts
]
)
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
query =
opts[:query]
|> Kernel.||(unquote(resource))
|> Ash.Query.for_read(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
if unquote(interface.get?) do
query
|> unquote(api).read_one!(Keyword.drop(opts, [:query, :tenant]))
|> case do
nil ->
raise Ash.Error.Query.NotFound, resource: query.resource
result ->
result
end
else
unquote(api).read!(query, Keyword.drop(opts, [:query, :tenant]))
end
end
end
:create ->
@doc doc
@dialyzer {:nowarn_function, {interface.name, Enum.count(args) + 2}}
def unquote(interface.name)(
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
opts[:changeset]
|> Kernel.||(unquote(resource))
|> Ash.Changeset.for_create(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).create(changeset, Keyword.drop(opts, [:changeset, :tenant]))
end
end
@doc doc
@dialyzer {:nowarn_function, {:"#{interface.name}!", Enum.count(args) + 2}}
# sobelow_skip ["DOS.BinToAtom"]
def unquote(:"#{interface.name}!")(
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
unquote(resource)
|> Ash.Changeset.for_create(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).create!(changeset, Keyword.drop(opts, [:actor, :tenant]))
end
end
:update ->
@doc doc
@dialyzer {:nowarn_function, {interface.name, Enum.count(args) + 3}}
def unquote(interface.name)(
record,
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
record,
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
record
|> Ash.Changeset.for_update(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).update(changeset, Keyword.drop(opts, [:actor, :tenant]))
end
end
@doc doc
# sobelow_skip ["DOS.BinToAtom"]
@dialyzer {:nowarn_function, {:"#{interface.name}!", Enum.count(args) + 3}}
def unquote(:"#{interface.name}!")(
record,
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
record,
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
record
|> Ash.Changeset.for_update(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).update!(changeset, Keyword.drop(opts, [:actor, :tenant]))
end
end
:destroy ->
@doc doc
@dialyzer {:nowarn_function, {interface.name, Enum.count(args) + 3}}
def unquote(interface.name)(
record,
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
record,
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
record
|> Ash.Changeset.for_destroy(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).destroy(changeset, Keyword.drop(opts, [:actor, :tenant]))
end
end
@doc doc
# sobelow_skip ["DOS.BinToAtom"]
@dialyzer {:nowarn_function, {:"#{interface.name}!", Enum.count(args) + 3}}
def unquote(:"#{interface.name}!")(
record,
unquote_splicing(arg_vars),
params_or_opts \\ %{},
opts \\ []
) do
if opts == [] && Keyword.keyword?(params_or_opts) do
apply(__MODULE__, elem(__ENV__.function, 0), [
record,
unquote_splicing(arg_vars),
%{},
params_or_opts
])
else
input =
unquote(args)
|> Enum.zip([unquote_splicing(arg_vars)])
|> Enum.reduce(params_or_opts, fn {key, value}, params_or_opts ->
Map.put(params_or_opts, key, value)
end)
changeset =
record
|> Ash.Changeset.for_destroy(
unquote(action.name),
input,
Keyword.take(opts, [:actor, :tenant])
)
unquote(api).destroy!(changeset, Keyword.drop(opts, [:actor, :tenant]))
end
end
end
end
end
end
defmacro __using__(_) do
quote bind_quoted: [], generated: true do
alias Ash.Api
for resource <- Ash.Api.resources(__MODULE__) do
Ash.Api.Interface.define_interface(__MODULE__, resource)
end
def get!(resource, id_or_filter, params \\ []) do
Ash.Api.Interface.enforce_resource!(resource)
Api.get!(__MODULE__, resource, id_or_filter, params)
end
def get(resource, id_or_filter, params \\ []) do
Ash.Api.Interface.enforce_resource!(resource)
Ash.Api.Interface.enforce_keyword_list!(params)
case Api.get(__MODULE__, resource, id_or_filter, params) do
{:ok, instance} -> {:ok, instance}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def read!(query, opts \\ [])
def read!(query, opts) do
Ash.Api.Interface.enforce_query_or_resource!(query)
Ash.Api.Interface.enforce_keyword_list!(opts)
Api.read!(__MODULE__, query, opts)
end
def read(query, opts \\ [])
def read(query, opts) do
Ash.Api.Interface.enforce_query_or_resource!(query)
Ash.Api.Interface.enforce_keyword_list!(opts)
case Api.read(__MODULE__, query, opts) do
{:ok, results, query} -> {:ok, results, query}
{:ok, results} -> {:ok, results}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def read_one!(query, opts \\ [])
def read_one!(query, opts) do
Ash.Api.Interface.enforce_query_or_resource!(query)
Ash.Api.Interface.enforce_keyword_list!(opts)
Api.read_one!(__MODULE__, query, opts)
end
def read_one(query, opts \\ [])
def read_one(query, opts) do
Ash.Api.Interface.enforce_query_or_resource!(query)
Ash.Api.Interface.enforce_keyword_list!(opts)
case Api.read_one(__MODULE__, query, opts) do
{:ok, result} -> {:ok, result}
{:ok, result, query} -> {:ok, result, query}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def page!(page, request) do
Api.page!(__MODULE__, page, request)
end
def page(page, request) do
case Api.page(__MODULE__, page, request) do
{:ok, page} -> {:ok, page}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def load!(data, query, opts \\ []) do
Api.load!(__MODULE__, data, query, opts)
end
def load(data, query, opts \\ []) do
case Api.load(__MODULE__, data, query, opts) do
{:ok, results} -> {:ok, results}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def create!(changeset, params \\ []) do
Api.create!(__MODULE__, changeset, params)
end
def create(changeset, params \\ []) do
case Api.create(__MODULE__, changeset, params) do
{:ok, instance} -> {:ok, instance}
{:ok, instance, notifications} -> {:ok, instance, notifications}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def update!(changeset, params \\ []) do
Api.update!(__MODULE__, changeset, params)
end
def update(changeset, params \\ []) do
case Api.update(__MODULE__, changeset, params) do
{:ok, instance} -> {:ok, instance}
{:ok, instance, notifications} -> {:ok, instance, notifications}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def destroy!(record, params \\ []) do
Api.destroy!(__MODULE__, record, params)
end
def destroy(record, params \\ []) do
case Api.destroy(__MODULE__, record, params) do
:ok -> :ok
{:ok, notifications} -> {:ok, notifications}
{:error, error} -> {:error, Ash.Error.to_ash_error(error)}
end
end
def reload!(%resource{} = record, params \\ []) do
id = record |> Map.take(Ash.Resource.Info.primary_key(resource)) |> Enum.to_list()
params = Keyword.put_new(params, :tenant, Map.get(record.__metadata__, :tenant))
get!(resource, id, params)
end
def reload(%resource{} = record, params \\ []) do
id = record |> Map.take(Ash.Resource.Info.primary_key(resource)) |> Enum.to_list()
params = Keyword.put_new(params, :tenant, Map.get(record.__metadata__, :tenant))
get(resource, id, params)
end
end
end
@doc false
def set_tenant(query_or_changeset, opts) do
case Keyword.fetch(opts, :tenant) do
{:ok, tenant} ->
case query_or_changeset do
%Ash.Query{} = query ->
Ash.Query.set_tenant(query, tenant)
%Ash.Changeset{} = changeset ->
Ash.Changeset.set_tenant(changeset, tenant)
other ->
other
end
:error ->
query_or_changeset
end
end
@doc false
def action_interface(api) do
api
|> Ash.Api.resource_references()
|> Enum.flat_map(fn %{resource: resource} = reference ->
resource_name = name(reference)
resource
|> Ash.Resource.Info.actions()
|> Enum.map(fn action ->
{resource, resource_name, action}
end)
end)
end
@doc false
def getters(api) do
api
|> Ash.Api.resource_references()
|> Enum.flat_map(fn %{resource: resource} = reference ->
if Ash.Resource.Info.primary_action(resource, :read) do
resource_name = name(reference)
resource
|> Ash.Resource.Info.identities()
|> Enum.map(fn identity ->
{resource, resource_name, identity}
end)
else
[]
end
end)
end
@doc false
def resources_with_names(api) do
api
|> Ash.Api.resource_references()
|> Enum.map(fn ref ->
{ref.resource, name(ref)}
end)
end
@doc false
def name(reference) do
reference
|> Map.get(:as)
|> Kernel.||(
reference.resource
|> Module.split()
|> List.last()
|> to_string()
|> Macro.underscore()
)
|> to_string()
end
defmacro enforce_query_or_resource!(query_or_resource) do
quote generated: true do
case Ash.Api.Interface.do_enforce_query_or_resource!(unquote(query_or_resource)) do
:ok ->
:ok
_ ->
{fun, arity} = __ENV__.function
mfa = "#{inspect(__ENV__.module)}.#{fun}/#{arity}"
raise "#{mfa} expected an %Ash.Query{} or an Ash Resource but instead got #{
inspect(unquote(query_or_resource))
}"
end
end
end
def do_enforce_query_or_resource!(query_or_resource)
def do_enforce_query_or_resource!(%Ash.Query{}), do: :ok
def do_enforce_query_or_resource!(resource) when is_atom(resource) do
if Ash.Resource.Info.resource?(resource), do: :ok, else: :error
end
def do_enforce_query_or_resource!(_something), do: :error
defmacro enforce_resource!(resource) do
quote generated: true do
if Ash.Resource.Info.resource?(unquote(resource)) do
:ok
else
{fun, arity} = __ENV__.function
mfa = "#{inspect(__ENV__.module)}.#{fun}/#{arity}"
raise Ash.Error.Invalid.NoSuchResource,
message: "#{mfa} expected an Ash Resource but instead got #{inspect(unquote(resource))}"
end
end
end
defmacro enforce_keyword_list!(list) do
quote generated: true do
if Keyword.keyword?(unquote(list)) do
:ok
else
{fun, arity} = __ENV__.function
mfa = "#{inspect(__ENV__.module)}.#{fun}/#{arity}"
raise "#{mfa} expected a keyword list, but instead got #{inspect(unquote(list))}"
end
end
end
end