mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
a06912f9b0
improvement: pass `tenant` to context in custom changes improvement: `Ash.context_to_opts` now checks for a `tenant`
288 lines
7.5 KiB
Elixir
288 lines
7.5 KiB
Elixir
defmodule Ash do
|
|
@moduledoc """
|
|
General purpose tools for working with Ash and Ash resources.
|
|
"""
|
|
|
|
for {function, arity} <- Ash.Api.Functions.functions() do
|
|
if function == :load do
|
|
def load({:ok, result}, load) do
|
|
load(result, load)
|
|
end
|
|
|
|
def load({:error, error}, _), do: {:error, error}
|
|
|
|
def load([], _), do: {:ok, []}
|
|
def load(nil, _), do: {:ok, nil}
|
|
|
|
def load(%page_struct{results: []} = page, _)
|
|
when page_struct in [Ash.Page.Keyset, Ash.Page.Offset] do
|
|
{:ok, page}
|
|
end
|
|
end
|
|
|
|
if function == :load! do
|
|
def load!({:ok, result}, load) do
|
|
{:ok, load!(result, load)}
|
|
end
|
|
|
|
def load!({:error, error}, _), do: raise(Ash.Error.to_error_class(error))
|
|
def load!([], _), do: []
|
|
def load!(nil, _), do: nil
|
|
|
|
def load!(%page_struct{results: []} = page, _)
|
|
when page_struct in [Ash.Page.Keyset, Ash.Page.Offset] do
|
|
page
|
|
end
|
|
end
|
|
|
|
args = Macro.generate_arguments(arity, __MODULE__)
|
|
|
|
docs_arity =
|
|
if function in Ash.Api.Functions.no_opts_functions() do
|
|
arity
|
|
else
|
|
arity + 1
|
|
end
|
|
|
|
@doc "Calls `c:Ash.Api.#{function}/#{docs_arity}` on the resource's configured api. See those callback docs for more."
|
|
def unquote(function)(unquote_splicing(args)) do
|
|
resource =
|
|
Ash.Api.GlobalInterface.resource_from_args!(unquote(function), unquote(arity), [
|
|
unquote_splicing(args)
|
|
])
|
|
|
|
api = Ash.Resource.Info.api(resource)
|
|
|
|
if !api do
|
|
Ash.Api.GlobalInterface.raise_no_api_error!(resource, unquote(function), unquote(arity))
|
|
end
|
|
|
|
apply(api, unquote(function), [unquote_splicing(args)])
|
|
end
|
|
|
|
unless function in Ash.Api.Functions.no_opts_functions() do
|
|
args = Macro.generate_arguments(arity + 1, __MODULE__)
|
|
|
|
if function == :load! do
|
|
def load!({:ok, result}, load, opts) do
|
|
{:ok, load(result, load, opts)}
|
|
end
|
|
|
|
def load!({:error, error}, _, _), do: raise(Ash.Error.to_error_class(error))
|
|
|
|
def load!(nil, _, _), do: nil
|
|
def load!([], _, _), do: []
|
|
|
|
def load!(%page_struct{results: []} = page, _, _)
|
|
when page_struct in [Ash.Page.Keyset, Ash.Page.Offset] do
|
|
page
|
|
end
|
|
end
|
|
|
|
if function == :load do
|
|
def load({:ok, result}, load, opts) do
|
|
load(result, load, opts)
|
|
end
|
|
|
|
def load({:error, error}, _, _), do: {:error, error}
|
|
def load([], _, _), do: {:ok, []}
|
|
def load(nil, _, _), do: {:ok, nil}
|
|
|
|
def load(%page_struct{results: []} = page, _, _)
|
|
when page_struct in [Ash.Page.Keyset, Ash.Page.Offset] do
|
|
{:ok, page}
|
|
end
|
|
end
|
|
|
|
@doc "Calls `c:Ash.Api.#{function}/#{arity + 1}` on the resource's configured api. See those callback docs for more."
|
|
def unquote(function)(unquote_splicing(args)) do
|
|
resource =
|
|
Ash.Api.GlobalInterface.resource_from_args!(unquote(function), unquote(arity), [
|
|
unquote_splicing(args)
|
|
])
|
|
|
|
api = Ash.Resource.Info.api(resource)
|
|
|
|
if !api do
|
|
Ash.Api.GlobalInterface.raise_no_api_error!(resource, unquote(function), unquote(arity))
|
|
end
|
|
|
|
apply(api, unquote(function), [unquote_splicing(args)])
|
|
end
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Converts a context map to opts to be passed into an action.
|
|
"""
|
|
def context_to_opts(map, add_to \\ []) when is_map(map) do
|
|
add_to
|
|
|> add_if_present(map, :actor)
|
|
|> add_if_present(map, :authorize?)
|
|
|> add_if_present(map, :tracer)
|
|
|> add_if_present(map, :tenant)
|
|
end
|
|
|
|
defp add_if_present(opts, map, key) do
|
|
case Map.fetch(map, key) do
|
|
{:ok, value} -> Keyword.put(opts, key, value)
|
|
:error -> opts
|
|
end
|
|
end
|
|
|
|
@doc deprecated: "See `Ash.ProcessHelpers`. This alias will be removed in 3.0"
|
|
defdelegate get_context_for_transfer(opts \\ []), to: Ash.ProcessHelpers
|
|
@doc deprecated: "See `Ash.ProcessHelpers`. This alias will be removed in 3.0"
|
|
defdelegate transfer_context(term, opts \\ []), to: Ash.ProcessHelpers
|
|
|
|
@doc deprecated: """
|
|
Sets context into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec set_context(map) :: :ok
|
|
def set_context(map) do
|
|
Process.put(:ash_context, map)
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Deep merges context into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec merge_context(map) :: :ok
|
|
def merge_context(map) do
|
|
update_context(&Ash.Helpers.deep_merge_maps(&1, map))
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Updates the context into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec update_context((map -> map)) :: :ok
|
|
def update_context(fun) do
|
|
context = Process.get(:ash_context, %{})
|
|
set_context(fun.(context))
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Sets actor into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec set_actor(map) :: :ok
|
|
def set_actor(map) do
|
|
Process.put(:ash_actor, {:actor, map})
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Sets authorize? into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec set_authorize?(map) :: :ok
|
|
def set_authorize?(map) do
|
|
Process.put(:ash_authorize?, {:authorize?, map})
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Sets the tracer into the process dictionary that will be used to trace requests
|
|
"""
|
|
@spec set_tracer(module | list(module)) :: :ok
|
|
def set_tracer(module) do
|
|
case Process.get(:ash_tracer, module) do
|
|
nil -> Process.put(:ash_tracer, module)
|
|
tracer -> Process.put(:ash_tracer, Enum.uniq(List.wrap(tracer) ++ List.wrap(module)))
|
|
end
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Removes a tracer from the process dictionary.
|
|
"""
|
|
@spec remove_tracer(module | list(module)) :: :ok
|
|
def remove_tracer(module) do
|
|
case Process.get(:ash_tracer, module) do
|
|
nil -> :ok
|
|
tracer -> Process.put(:ash_tracer, List.wrap(tracer) -- List.wrap(module))
|
|
end
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Gets the current actor from the process dictionary
|
|
"""
|
|
@spec get_actor() :: term()
|
|
def get_actor do
|
|
case Process.get(:ash_actor) do
|
|
{:actor, value} ->
|
|
value
|
|
|
|
_ ->
|
|
nil
|
|
end
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Gets the current tracer
|
|
"""
|
|
@spec get_tracer() :: term()
|
|
def get_tracer do
|
|
case Process.get(:ash_tracer) do
|
|
{:tracer, value} ->
|
|
value
|
|
|
|
_ ->
|
|
Application.get_env(:ash, :tracer)
|
|
end
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Gets the current authorize? from the process dictionary
|
|
"""
|
|
@spec get_authorize?() :: term()
|
|
def get_authorize? do
|
|
case Process.get(:ash_authorize?) do
|
|
{:authorize?, value} ->
|
|
value
|
|
|
|
_ ->
|
|
nil
|
|
end
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Sets tenant into the process dictionary that is used for all changesets and queries.
|
|
"""
|
|
@spec set_tenant(term()) :: :ok
|
|
def set_tenant(tenant) do
|
|
Process.put(:ash_tenant, {:tenant, tenant})
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Gets the current tenant from the process dictionary
|
|
"""
|
|
@spec get_tenant() :: term()
|
|
def get_tenant do
|
|
case Process.get(:ash_tenant) do
|
|
{:tenant, value} ->
|
|
value
|
|
|
|
_ ->
|
|
nil
|
|
end
|
|
end
|
|
|
|
@doc deprecated: """
|
|
Gets the current context from the process dictionary
|
|
"""
|
|
@spec get_context() :: term()
|
|
def get_context do
|
|
Process.get(:ash_context, %{}) || %{}
|
|
end
|
|
end
|