Packages
ash
3.10.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/helpers.ex
# SPDX-FileCopyrightText: 2019 ash contributors <https://github.com/ash-project/ash/graphs.contributors>
#
# SPDX-License-Identifier: MIT
defmodule Ash.Helpers do
@moduledoc false
require Logger
@dialyzer {:nowarn_function, {:unwrap_or_raise!, 2}}
@spec try_compile(term) :: :ok
def try_compile(module) when is_atom(module) do
try do
# This is to get the compiler to ensure that the resource is compiled
# For some very strange reason, `Code.ensure_compiled/1` isn't enough
module.ash_dsl_config()
rescue
_ ->
:ok
end
Code.ensure_compiled!(module)
:ok
end
def try_compile(_), do: :ok
def flatten_preserving_keywords(list) do
if Keyword.keyword?(list) do
[list]
else
list
|> List.wrap()
|> Enum.flat_map(fn item ->
cond do
Keyword.keyword?(item) ->
[item]
is_list(item) ->
flatten_preserving_keywords(item)
true ->
[item]
end
end)
end
end
defmacro expect_resource!(resource) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [resource: resource, formatted: formatted] do
if !Ash.Resource.Info.resource?(resource) do
raise ArgumentError,
"Expected an `Ash.Resource` in #{formatted}, got: #{inspect(resource)}"
end
end
end
defmacro expect_resource_or_query!(resource_or_query) do
formatted = format_caller(__CALLER__)
quote generated: true,
bind_quoted: [resource_or_query: resource_or_query, formatted: formatted] do
case resource_or_query do
%Ash.Query{} ->
:ok
other ->
if !Ash.Resource.Info.resource?(other) do
raise ArgumentError,
"Expected an `%Ash.Query{}` or an `Ash.Resource` in #{formatted}, got: #{inspect(other)}"
end
end
end
end
defmacro expect_query!(query) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [query: query, formatted: formatted] do
case query do
%Ash.Query{} ->
:ok
other ->
raise ArgumentError,
"Expected an `%Ash.Query{}` in #{formatted}, got: #{inspect(other)}"
end
end
end
defmacro expect_changeset!(changeset) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [changeset: changeset, formatted: formatted] do
case changeset do
%Ash.Changeset{} ->
:ok
other ->
raise ArgumentError,
"Expected an `%Ash.Changeset{}` in #{formatted}, got: #{inspect(other)}"
end
end
end
defmacro expect_resource_or_record!(resource) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [resource: resource, formatted: formatted] do
case resource do
%resource{} = record ->
if !Ash.Resource.Info.resource?(resource) do
raise ArgumentError,
"Expected an `Ash.Resource` or a record in #{formatted}, got: #{inspect(record)}"
end
other ->
if !Ash.Resource.Info.resource?(resource) do
raise ArgumentError,
"Expected an `Ash.Resource` or a record in #{formatted}, got: #{inspect(other)}"
end
end
end
end
defmacro expect_changeset_or_record!(changeset_or_record) do
formatted = format_caller(__CALLER__)
quote generated: true,
bind_quoted: [changeset_or_record: changeset_or_record, formatted: formatted] do
case changeset_or_record do
%Ash.Changeset{} ->
:ok
%resource{} = record ->
if !Ash.Resource.Info.resource?(resource) do
raise ArgumentError,
"Expected an `Ash.Resource` or a record in #{formatted}, got: #{inspect(record)}"
end
other ->
raise ArgumentError,
"Expected an `Ash.Resource` or a record in #{formatted}, got: #{inspect(other)}"
end
end
end
defmacro expect_record!(record) do
formatted = format_caller(__CALLER__)
quote bind_quoted: [record: record, formatted: formatted] do
case record do
%resource{} = record ->
if !Ash.Resource.Info.resource?(resource) do
raise ArgumentError,
"Expected a record in #{formatted}, got: #{inspect(record)}"
end
other ->
raise ArgumentError,
"Expected a record in #{formatted}, got: #{inspect(other)}"
end
end
end
defmacro expect_options!(options) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [options: options, formatted: formatted] do
case options do
[] ->
:ok
[{atom, _} | _] when is_atom(atom) ->
:ok
other ->
raise ArgumentError,
"Expected a keyword list in #{formatted}, got: #{inspect(other)}"
end
end
end
defmacro expect_map_or_nil!(map_or_nil) do
formatted = format_caller(__CALLER__)
quote generated: true, bind_quoted: [map_or_nil: map_or_nil, formatted: formatted] do
case map_or_nil do
nil ->
:ok
map when is_map(map) ->
:ok
other ->
raise ArgumentError,
"Expected a keyword list in #{formatted}, got: #{inspect(other)}"
end
end
end
def resource_from_query_or_stream(domain, query_or_stream, opts) do
resource =
opts[:resource] ||
case query_or_stream do
[%resource{} | _] ->
resource
%Ash.Query{resource: resource} ->
resource
resource when is_atom(resource) ->
if Ash.Resource.Info.resource?(resource) do
resource
end
_ ->
nil
end
if !resource do
raise ArgumentError,
"Could not determine resource for bulk action. Please provide the `resource` option if providing a stream of inputs."
end
Ash.Domain.Info.resource(domain, resource)
end
def get_action(resource, params, type, preset \\ nil) do
case Keyword.fetch(params, :action) do
{:ok, %_{} = action} ->
{:ok, action}
{:ok, nil} ->
if preset do
get_action(resource, Keyword.put(params, :action, preset), type)
else
get_action(resource, Keyword.delete(params, :action), type)
end
{:ok, action} ->
case Ash.Resource.Info.action(resource, action) do
nil ->
{:error,
Ash.Error.Invalid.NoSuchAction.exception(
resource: resource,
action: action,
type: type
)}
action ->
if action.type == type do
{:ok, action}
else
{:error,
Ash.Error.Invalid.InvalidActionType.exception(
resource: resource,
action: action,
type: type
)}
end
end
:error ->
if preset do
get_action(resource, Keyword.put(params, :action, preset), type)
else
case Ash.Resource.Info.primary_action(resource, type) do
nil ->
if Ash.Resource.Info.resource?(resource) do
{:error,
Ash.Error.Invalid.NoPrimaryAction.exception(resource: resource, type: type)}
else
{:error, Ash.Error.Invalid.NoSuchResource.exception(resource: resource)}
end
action ->
{:ok, action}
end
end
end
end
@doc """
Returns {params, opts} from ambiguous inputs.
"""
def get_params_and_opts(params_or_opts, opts) do
if opts == [] && Keyword.keyword?(params_or_opts) do
{%{}, params_or_opts}
else
{params_or_opts, opts}
end
end
def pagination_check(action, query, opts) do
page = query.page || opts[:page]
if page && page != [] && !Map.get(action, :pagination) do
{:error,
Ash.Error.to_error_class(
Ash.Error.Invalid.ActionRequiresPagination.exception(
resource: query.resource,
action: action
)
)}
else
{:ok, action}
end
end
def unwrap_one({:error, error}) do
{:error, error}
end
def unwrap_one({:ok, result, query}) do
case unwrap_one({:ok, result}) do
{:ok, result} ->
{:ok, result, query}
{:error, error} ->
{:error, Ash.Error.to_ash_error(error, nil, query: query)}
end
end
def unwrap_one({:ok, result}) do
case unwrap_one(result) do
{:ok, result} ->
{:ok, result}
{:error, error} ->
{:error, error}
end
end
def unwrap_one(%{results: results}) do
unwrap_one(results)
end
def unwrap_one([]), do: {:ok, nil}
def unwrap_one([result]), do: {:ok, result}
def unwrap_one([_ | _] = results) do
error =
Ash.Error.Invalid.MultipleResults.exception(
count: Enum.count(results),
at_least?: true
)
{:error, error}
end
def resource_from_data!(data, query, opts) do
if opts[:resource] do
opts[:resource]
else
case query do
%Ash.Query{resource: resource} -> resource
_ -> do_resource_from_data!(data)
end
end
end
defp do_resource_from_data!(%struct{rerun: {%Ash.Query{resource: resource}, _}})
when struct in [Ash.Page.Offset, Ash.Page.Keyset] do
resource
end
defp do_resource_from_data!(%struct{results: [%resource{} | _]} = data)
when struct in [Ash.Page.Offset, Ash.Page.Keyset] do
if Ash.Resource.Info.resource?(resource) do
resource
else
raise_no_resource_error!(data)
end
end
defp do_resource_from_data!(%resource{} = data) do
if Ash.Resource.Info.resource?(resource) do
resource
else
raise_no_resource_error!(data)
end
end
defp do_resource_from_data!([%resource{} | _] = data) do
if Ash.Resource.Info.resource?(resource) do
resource
else
raise_no_resource_error!(data)
end
end
defp do_resource_from_data!(data) do
raise_no_resource_error!(data)
end
defp raise_no_resource_error!(data) do
raise ArgumentError,
message: """
Could not determine a resource from the provided input:
#{inspect(data)}
"""
end
defmacro domain!(
subject,
opts,
instructions \\ "Please specify the `:domain` option, or adjust the input."
) do
formatted = format_caller(__CALLER__)
quote generated: true,
bind_quoted: [
subject: subject,
opts: opts,
formatted: formatted,
instructions: instructions
] do
domain = Ash.Helpers.get_domain(subject, opts)
if !domain do
expanded =
if not is_nil(subject) do
"\n\n#{inspect(subject)}"
end
raise(
ArgumentError,
"""
Could not determine domain for input in #{formatted}. #{instructions}#{expanded}
"""
)
end
domain
end
end
defp format_caller(caller) do
mod = caller.module
{func, arity} = caller.function
"`#{inspect(mod)}.#{func}/#{arity}`"
end
def get_domain(nil, nil) do
nil
end
def get_domain(%input_struct{domain: domain}, _opts)
when input_struct in [Ash.Query, Ash.Changeset, Ash.ActionInput] and not is_nil(domain) do
domain
end
def get_domain(%input_struct{resource: resource}, opts)
when input_struct in [Ash.Query, Ash.Changeset, Ash.ActionInput] do
get_domain(resource, opts)
end
def get_domain([record | _], opts) do
get_domain(record, opts)
end
def get_domain({%input_struct{} = input, _}, opts)
when input_struct in [Ash.Query, Ash.Changeset, Ash.ActionInput] do
get_domain(input, opts)
end
def get_domain({%input_struct{} = input, _, _}, opts)
when input_struct in [Ash.Query, Ash.Changeset, Ash.ActionInput] do
get_domain(input, opts)
end
def get_domain({%resource{}, _}, opts) do
get_domain(resource, opts)
end
def get_domain({%resource{}, _, _}, opts) do
get_domain(resource, opts)
end
def get_domain({resource, _}, opts) when is_atom(resource) do
get_domain(resource, opts)
end
def get_domain({resource, _, _}, opts) when is_atom(resource) do
get_domain(resource, opts)
end
def get_domain(%page_struct{rerun: {query, _}}, opts)
when page_struct in [Ash.Page.Offset, Ash.Page.Keyset] do
get_domain(query, opts)
end
def get_domain(%page_struct{results: results}, opts)
when page_struct in [Ash.Page.Offset, Ash.Page.Keyset] do
get_domain(results, opts)
end
def get_domain(%{resource: resource}, opts) when not is_nil(resource) do
get_domain(resource, opts)
end
def get_domain(nil, opts) do
cond do
domain = opts[:domain] ->
domain
resource = opts[:resource] ->
get_domain(resource, Keyword.delete(opts, :resource))
true ->
nil
end
end
def get_domain(%resource{}, opts) do
if Ash.Resource.Info.resource?(resource) do
get_domain(resource, opts)
else
get_domain(nil, opts)
end
end
def get_domain(resource, opts) do
domain_from_resource(resource) || opts[:domain]
end
defp domain_from_resource(resource) do
if Ash.Resource.Info.resource?(resource) || (is_map(resource) and not is_struct(resource)) do
Ash.Resource.Info.domain(resource) ||
Ash.Actions.Helpers.maybe_embedded_domain(resource)
end
end
def unwrap_or_raise!(first, destroy? \\ false)
def unwrap_or_raise!(%Ash.BulkResult{} = bulk_result, _), do: bulk_result
def unwrap_or_raise!(:ok, _), do: :ok
def unwrap_or_raise!({:ok, result}, false), do: result
def unwrap_or_raise!({:ok, _result}, true), do: :ok
def unwrap_or_raise!({:ok, result, other}, _), do: {result, other}
def unwrap_or_raise!({:error, error}, destroy?) when is_list(error) do
unwrap_or_raise!({:error, Ash.Error.to_error_class(error)}, destroy?)
end
def unwrap_or_raise!({:error, error}, _) do
exception = Ash.Error.to_error_class(error)
case exception do
%{stacktrace: %{stacktrace: stacktrace}} = exception ->
reraise exception, stacktrace
_ ->
raise exception
end
end
def implements_behaviour?(module, behaviour) do
:attributes
|> module.module_info()
|> Enum.flat_map(fn
{:behaviour, value} -> List.wrap(value)
_ -> []
end)
|> Enum.any?(&(&1 == behaviour))
rescue
_ ->
false
end
# sobelow_skip ["Misc.BinToTerm"]
def non_executable_binary_to_term(binary, opts \\ []) when is_binary(binary) do
term = :erlang.binary_to_term(binary, opts)
non_executable_terms(term)
term
end
defp non_executable_terms(list) when is_list(list) do
non_executable_list(list)
end
defp non_executable_terms(tuple) when is_tuple(tuple) do
non_executable_tuple(tuple, tuple_size(tuple))
end
defp non_executable_terms(map) when is_map(map) do
folder = fn key, value, acc ->
non_executable_terms(key)
non_executable_terms(value)
acc
end
:maps.fold(folder, map, map)
end
defp non_executable_terms(other)
when is_atom(other) or is_number(other) or is_bitstring(other) or is_pid(other) or
is_reference(other) do
other
end
defp non_executable_terms(other) do
raise ArgumentError,
"cannot deserialize #{inspect(other)}, the term is not safe for deserialization"
end
defp non_executable_list([]), do: :ok
defp non_executable_list([h | t]) when is_list(t) do
non_executable_terms(h)
non_executable_list(t)
end
defp non_executable_list([h | t]) do
non_executable_terms(h)
non_executable_terms(t)
end
defp non_executable_tuple(_tuple, 0), do: :ok
defp non_executable_tuple(tuple, n) do
non_executable_terms(:erlang.element(n, tuple))
non_executable_tuple(tuple, n - 1)
end
def deep_merge_maps(nil, right), do: right
def deep_merge_maps(left, nil), do: left
def deep_merge_maps(left, right), do: do_deep_merge_maps(left, right)
@doc false
def do_deep_merge_maps(left, right) when left == %{} do
right
end
def do_deep_merge_maps(left, right) when right == %{} do
left
end
def do_deep_merge_maps(left, right)
when is_map(left) and is_map(right) and not is_struct(left) and not is_struct(right) do
Map.merge(left, right, fn _, left, right ->
do_deep_merge_maps(left, right)
end)
end
def do_deep_merge_maps(_left, right), do: right
@doc false
if Application.compile_env(:ash, :show_sensitive?, false) do
def redact(value), do: value
else
def redact(_value), do: "**redacted**"
end
@spec verify_stream_options(options :: Keyword.t()) :: :ok
def verify_stream_options(options) do
with true <- Keyword.get(options, :return_stream?, false),
false <- Keyword.get(options, :return_notifications?, false),
false <- Keyword.get(options, :return_records?, false),
false <- Keyword.get(options, :return_errors?, false),
false <- Keyword.get(options, :return_nothing?, false) do
Logger.warning("""
Bulk action was called with :return_stream? set to true, but no other :return_*? options were set.
You probably want to set :return_notifications?, :return_records?, or :return_errors? as well.
To disable this message, set :return_nothing? to true.\
""")
end
:ok
end
def json_module do
# there are libraries depending on our use of `Jason` here
# we are going to be stuck with `Jason` for a while
# if Code.ensure_loaded?(JSON) do
# JSON
# else
Jason
# end
end
end