defmodule Ash do
@moduledoc """
General purpose tools for working with Ash.
Currently only contains setters/getters for process context.
"""
@doc """
Gets all of the ash context so it can be set into a new process.
Use `transfer_context/1` in the new process to set the context.
"""
@spec get_context_for_transfer(opts :: Keyword.t()) :: term
def get_context_for_transfer(opts \\ []) do
context = Ash.get_context()
actor = Process.get(:ash_actor)
authorize? = Process.get(:ash_authorize?)
tenant = Process.get(:ash_tenant)
tracer = Process.get(:ash_tracer)
tracer_context =
if opts[:tracer] do
{:tracer_context, opts[:tracer].get_span_context()}
else
case tracer do
{:tracer, tracer} ->
{:tracer_context, tracer.get_span_context()}
_ ->
nil
end
end
%{
context: context,
actor: actor,
tenant: tenant,
authorize?: authorize?,
tracer: tracer,
tracer_context: tracer_context
}
end
@spec transfer_context(term, opts :: Keyword.t()) :: :ok
def transfer_context(
%{
context: context,
actor: actor,
tenant: tenant,
authorize?: authorize?,
tracer: tracer,
tracer_context: tracer_context
},
opts \\ []
) do
case actor do
{:actor, actor} ->
Ash.set_actor(actor)
_ ->
:ok
end
case tenant do
{:tenant, tenant} ->
Ash.set_tenant(tenant)
_ ->
:ok
end
case authorize? do
{:authorize?, authorize?} ->
Ash.set_authorize?(authorize?)
_ ->
:ok
end
if opts[:tracer] do
case tracer_context do
{:tracer_context, tracer_context} ->
opts[:tracer].set_span_context(tracer_context)
_ ->
:ok
end
else
case tracer do
{:tracer, tracer} ->
Ash.set_tracer(tracer)
case tracer_context do
{:tracer_context, tracer_context} ->
tracer.set_span_context(tracer_context)
_ ->
:ok
end
_ ->
tracer = Application.get_env(:ash, :tracer) || opts[:tracer]
if tracer do
case tracer_context do
{:tracer_context, tracer_context} ->
tracer.set_span_context(tracer_context)
_ ->
:ok
end
end
:ok
end
end
Ash.set_context(context)
end
@doc """
Sets context into the process dictionary that is used for all changesets and queries.
In Ash 3.0, this will be updated to deep merge
"""
@spec set_context(map) :: :ok
def set_context(map) do
Process.put(:ash_context, map)
:ok
end
@doc """
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 """
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 """
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 """
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 """
Sets the tracer into the process dictionary that will be used to trace requests
"""
@spec set_tracer(module) :: :ok
def set_tracer(module) do
Process.put(:ash_tracer, module)
:ok
end
@doc """
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 """
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 """
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 """
Sets tenant into the process dictionary that is used for all changesets and queries.
"""
@spec set_tenant(String.t()) :: :ok
def set_tenant(tenant) do
Process.put(:ash_tenant, {:tenant, tenant})
:ok
end
@doc """
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 """
Gets the current context from the process dictionary
"""
@spec get_context() :: term()
def get_context do
Process.get(:ash_context, %{}) || %{}
end
end