Search documentation of ash

# View Source Ash.DataLayer behaviour (ash v3.4.30)

The behaviour for backing resource actions with persistence layers.

# Summary

## Types

bulk_create_options()
bulk_update_options()
data_layer_query()
feature()
lateral_join_link()
lock_type()
t()
transaction_reason()

## Callbacks

add_aggregate(data_layer_query, t, t)
add_aggregates(data_layer_query, list, t)
add_calculation(data_layer_query, t, expression, t)
add_calculations(data_layer_query, list, t)
bulk_create(t, t, options)
calculate(t, list, context)
can?(arg1, feature)
create(t, t)
destroy(t, t)
destroy_query(data_layer_query, t, t, opts)
distinct(data_layer_query, list, resource)
distinct_sort(data_layer_query, t, resource)
filter(data_layer_query, t, resource)
functions(t)
in_transaction?(t)
limit(data_layer_query, limit, resource)
lock(data_layer_query, lock_type, resource)
offset(data_layer_query, offset, resource)
prefer_lateral_join_for_many_to_many?()
resource_to_query(t, t)
return_query(data_layer_query, t)
rollback(t, term)
run_aggregate_query(data_layer_query, list, t)
run_aggregate_query_with_lateral_join(data_layer_query, list, list, destination_resource, list)
run_query(data_layer_query, t)
run_query_with_lateral_join(data_layer_query, list, source_resource, list)
select(data_layer_query, select, resource)
set_context(t, data_layer_query, map)
set_tenant(t, data_layer_query, term)
sort(data_layer_query, t, resource)
source(t)
transaction(t, function, arg3, reason)
transform_query(t)
update(t, t)
update_query(data_layer_query, t, t, opts)
upsert(t, t, list)
upsert(t, t, list, arg4)

## Functions

add_aggregates(query, aggregates, resource)
add_calculations(query, calculations, resource)
bulk_create(resource, changesets, options)
calculate(resource, exprs, context)
can?(feature, resource)
create(resource, changeset)
data_layer(resource)

The data layer of the resource, or nil if it does not have one

data_layer_can?(resource, feature)

Whether or not the data layer supports a specific feature

data_layer_functions(resource)

Custom functions supported by the data layer of the resource

destroy(resource, changeset)
destroy_query(query, changeset, opts)
distinct(query, distinct, resource)
distinct_sort(query, sort, resource)
filter(query, filter, resource)
functions(resource)
in_transaction?(resource)
limit(query, limit, resource)
lock(query, lock_type, resource)
offset(query, offset, resource)
prefer_lateral_join_for_many_to_many?(data_layer)

Whether or not lateral joins should be used for many to many relationships by default

resource_to_query(resource, domain)
return_query(query, resource)
rollback(resource, term)

Rolls back the current transaction

run_aggregate_query(query, aggregates, resource)
run_aggregate_query_with_lateral_join(query, aggregates, root_data, destination_resource, path)
run_query(query, central_resource)
run_query_with_lateral_join(query, root_data, destination_resource, path)
select(query, select, resource)
set_context(resource, query, map)
set_tenant(resource, query, term)
sort(query, sort, resource)
source(resource)
transaction(resource_or_resources, func, timeout \\ nil, reason \\ %{type: :custom, metadata: %{}})

Wraps the execution of the function in a transaction with the resource's data_layer

transform_query(query)
update(resource, changeset)
update_query(query, changeset, opts)
upsert(resource, changeset, keys, identity \\ nil)

# Types

Link to this type

# bulk_create_options()

View Source

    @type bulk_create_options() :: %{
      batch_size: pos_integer(),
      return_records?: boolean(),
      upsert?: boolean(),
      action_select: [atom()],
      upsert_keys: nil | [atom()],
      upsert_condition: Ash.Expr.t() | nil,
      identity: Ash.Resource.Identity.t() | nil,
      select: [atom()],
      upsert_fields:
        nil
        | [atom()]
        | :replace_all
        | {:replace, [atom()]}
        | {:replace_all_except, [atom()]},
      tenant: term()
    }

Link to this type

# bulk_update_options()

View Source

    @type bulk_update_options() :: %{
      return_records?: boolean(),
      action_select: [atom()],
      calculations: [{Ash.Query.Calculation.t(), Ash.Expr.t()}],
      select: [atom()],
      tenant: term()
    }

Link to this type

# data_layer_query()

View Source

    @type data_layer_query() :: struct()

Link to this type

# feature()

View Source

    @type feature() ::
      :transact
      | :multitenancy
      | {:atomic, :update}
      | {:atomic, :upsert}
      | {:lateral_join, [Ash.Resource.t()]}
      | {:join, Ash.Resource.t()}
      | {:aggregate, Ash.Query.Aggregate.kind()}
      | {:aggregate_relationship, Ash.Resource.Relationships.relationship()}
      | {:query_aggregate, Ash.Query.Aggregate.kind()}
      | :select
      | :expr_error
      | :expression_calculation_sort
      | :aggregate_filter
      | :aggregate_sort
      | :boolean_filter
      | :async_engine
      | :bulk_create
      | :update_query
      | :destroy_query
      | :create
      | :read
      | :update
      | :destroy
      | :limit
      | :offset
      | :transact
      | :filter
      | :composite_type
      | {:lock, lock_type()}
      | {:filter_expr, struct()}
      | {:filter_relationship, Ash.Resource.Relationships.relationship()}
      | :sort
      | {:sort, Ash.Type.t()}
      | :upsert
      | :composite_primary_key

Link to this type

# lateral_join_link()

View Source

    @type lateral_join_link() ::
      {Ash.Resource.t(), atom(), atom(), Ash.Resource.Relationships.relationship()}

Link to this type

# lock_type()

View Source

    @type lock_type() :: :for_update | term()

Link to this type

# t()

View Source

    @type t() :: module()

Link to this type

# transaction_reason()

View Source

    @type transaction_reason() ::
      %{
        :type => :create,
        :metadata => %{resource: Ash.Resource.t(), action: atom()},
        optional(:data_layer_context) => %{}
      }
      | %{
          :type => :update,
          :metadata => %{
            resource: Ash.Resource.t(),
            action: atom(),
            record: Ash.Resource.record(),
            actor: term()
          },
          optional(:data_layer_context) => %{}
        }
      | %{
          :type => :destroy,
          :metadata => %{
            resource: Ash.Resource.t(),
            action: atom(),
            record: Ash.Resource.record(),
            actor: term()
          },
          optional(:data_layer_context) => %{}
        }
      | %{
          :type => :read,
          :metadata => %{
            resource: Ash.Resource.t(),
            query: Ash.Query.t(),
            actor: term()
          },
          optional(:data_layer_context) => %{}
        }
      | %{
          :type => :flow_transaction,
          :metadata => %{
            resource: Ash.Resource.t(),
            input: Ash.ActionInput.t(),
            action: atom(),
            actor: term()
          },
          optional(:data_layer_context) => %{}
        }
      | %{
          :type => :generic,
          :metadata => %{
            step_name: atom() | [term()],
            flow: module(),
            actor: term()
          },
          optional(:data_layer_context) => %{}
        }
      | %{type: :custom, metadata: map()}
      | %{type: atom(), metadata: map()}

# Callbacks

Link to this callback

# add_aggregate(data_layer_query, t, t)

View Source (optional)

    @callback add_aggregate(
      data_layer_query(),
      Ash.Query.Aggregate.t(),
      Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# add_aggregates(data_layer_query, list, t)

View Source (optional)

    @callback add_aggregates(
      data_layer_query(),
      [Ash.Query.Aggregate.t()],
      Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# add_calculation(data_layer_query, t, expression, t)

View Source (optional)

    @callback add_calculation(
      data_layer_query(),
      Ash.Query.Calculation.t(),
      expression :: any(),
      Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# add_calculations(data_layer_query, list, t)

View Source (optional)

    @callback add_calculations(
      data_layer_query(),
      [{Ash.Query.Calculation.t(), expression :: any()}],
      Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# bulk_create(t, t, options)

View Source (optional)

    @callback bulk_create(
      Ash.Resource.t(),
      Enumerable.t(Ash.Changeset.t()),
      options :: bulk_create_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this callback

# calculate(t, list, context)

View Source (optional)

    @callback calculate(Ash.Resource.t(), [Ash.Expr.t()], context :: map()) ::
      {:ok, term()} | {:error, term()}

Link to this callback

# can?(arg1, feature)

View Source

    @callback can?(Ash.Resource.t() | Spark.Dsl.t(), feature()) :: boolean()

Link to this callback

# create(t, t)

View Source (optional)

    @callback create(Ash.Resource.t(), Ash.Changeset.t()) ::
      {:ok, Ash.Resource.record()}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this callback

# destroy(t, t)

View Source (optional)

    @callback destroy(Ash.Resource.t(), Ash.Changeset.t()) :: :ok | {:error, term()}

Link to this callback

# destroy_query(data_layer_query, t, t, opts)

View Source (optional)

    @callback destroy_query(
      data_layer_query(),
      Ash.Changeset.t(),
      Ash.Resource.t(),
      opts :: bulk_update_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this callback

# distinct(data_layer_query, list, resource)

View Source (optional)

    @callback distinct(data_layer_query(), [atom()], resource :: Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# distinct_sort(data_layer_query, t, resource)

View Source (optional)

    @callback distinct_sort(data_layer_query(), Ash.Sort.t(), resource :: Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# filter(data_layer_query, t, resource)

View Source (optional)

    @callback filter(data_layer_query(), Ash.Filter.t(), resource :: Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# functions(t)

View Source (optional)

    @callback functions(Ash.Resource.t()) :: [module()]

Link to this callback

# in_transaction?(t)

View Source (optional)

    @callback in_transaction?(Ash.Resource.t()) :: boolean()

Link to this callback

# limit(data_layer_query, limit, resource)

View Source (optional)

    @callback limit(
      data_layer_query(),
      limit :: non_neg_integer(),
      resource :: Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# lock(data_layer_query, lock_type, resource)

View Source (optional)

    @callback lock(data_layer_query(), lock_type(), resource :: Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# offset(data_layer_query, offset, resource)

View Source (optional)

    @callback offset(
      data_layer_query(),
      offset :: non_neg_integer(),
      resource :: Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# prefer_lateral_join_for_many_to_many?()

View Source (optional)

    @callback prefer_lateral_join_for_many_to_many?() :: boolean()

Link to this callback

# resource_to_query(t, t)

View Source

    @callback resource_to_query(Ash.Resource.t(), Ash.Domain.t()) :: data_layer_query()

Link to this callback

# return_query(data_layer_query, t)

View Source (optional)

    @callback return_query(data_layer_query(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# rollback(t, term)

View Source (optional)

    @callback rollback(Ash.Resource.t(), term()) :: no_return()

Link to this callback

# run_aggregate_query(data_layer_query, list, t)

View Source (optional)

    @callback run_aggregate_query(
      data_layer_query(),
      [Ash.Query.Aggregate.t()],
      Ash.Resource.t()
    ) :: {:ok, map()} | {:error, term()}

Link to this callback

# run_aggregate_query_with_lateral_join(data_layer_query, list, list, destination_resource, list)

View Source (optional)

    @callback run_aggregate_query_with_lateral_join(
      data_layer_query(),
      [Ash.Query.Aggregate.t()],
      [Ash.Resource.record()],
      destination_resource :: Ash.Resource.t(),
      [lateral_join_link()]
    ) :: {:ok, [Ash.Resource.t()]} | {:error, term()}

Link to this callback

# run_query(data_layer_query, t)

View Source (optional)

    @callback run_query(data_layer_query(), Ash.Resource.t()) ::
      {:ok, [Ash.Resource.record()]}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this callback

# run_query_with_lateral_join(data_layer_query, list, source_resource, list)

View Source (optional)

    @callback run_query_with_lateral_join(
      data_layer_query(),
      [Ash.Resource.record()],
      source_resource :: Ash.Resource.t(),
      [lateral_join_link()]
    ) :: {:ok, [Ash.Resource.record()]} | {:error, term()}

Link to this callback

# select(data_layer_query, select, resource)

View Source (optional)

    @callback select(
      data_layer_query(),
      select :: [atom()],
      resource :: Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# set_context(t, data_layer_query, map)

View Source (optional)

    @callback set_context(Ash.Resource.t(), data_layer_query(), map()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# set_tenant(t, data_layer_query, term)

View Source (optional)

    @callback set_tenant(Ash.Resource.t(), data_layer_query(), term()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# sort(data_layer_query, t, resource)

View Source (optional)

    @callback sort(data_layer_query(), Ash.Sort.t(), resource :: Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this callback

# source(t)

View Source (optional)

    @callback source(Ash.Resource.t()) :: String.t()

Link to this callback

# transaction(t, function, arg3, reason)

View Source (optional)

    @callback transaction(
      Ash.Resource.t(),
      (-> term()),
      nil | pos_integer(),
      reason :: transaction_reason()
    ) :: {:ok, term()} | {:error, term()}

Link to this callback

# transform_query(t)

View Source (optional)

    @callback transform_query(Ash.Query.t()) :: Ash.Query.t()

Link to this callback

# update(t, t)

View Source (optional)

    @callback update(Ash.Resource.t(), Ash.Changeset.t()) ::
      {:ok, Ash.Resource.record()}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this callback

# update_query(data_layer_query, t, t, opts)

View Source (optional)

    @callback update_query(
      data_layer_query(),
      Ash.Changeset.t(),
      Ash.Resource.t(),
      opts :: bulk_update_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this callback

# upsert(t, t, list)

View Source (optional)

    @callback upsert(Ash.Resource.t(), Ash.Changeset.t(), [atom()]) ::
      {:ok, Ash.Resource.record()}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this callback

# upsert(t, t, list, arg4)

View Source (optional)

    @callback upsert(
      Ash.Resource.t(),
      Ash.Changeset.t(),
      [atom()],
      Ash.Resource.Identity.t() | nil
    ) ::
      {:ok,
       Ash.Resource.record()
       | {:upsert_skipped, Ash.Query.t(),
          (-> {:ok, Ash.Resource.record()}
              | {:error, term()}
              | {:error, :no_rollback, term()})}}
      | {:error, term()}
      | {:error, :no_rollback, term()}

# Functions

Link to this function

# add_aggregates(query, aggregates, resource)

View Source

    @spec add_aggregates(data_layer_query(), [Ash.Query.Aggregate.t()], Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# add_calculations(query, calculations, resource)

View Source

    @spec add_calculations(
      data_layer_query(),
      [{Ash.Query.Calculation.t(), expression :: term()}],
      Ash.Resource.t()
    ) :: {:ok, data_layer_query()} | {:error, term()}

Link to this function

# bulk_create(resource, changesets, options)

View Source

    @spec bulk_create(
      Ash.Resource.t(),
      Enumerable.t(Ash.Changeset.t()),
      options :: bulk_create_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this function

# calculate(resource, exprs, context)

View Source

    @spec calculate(Ash.Resource.t(), [Ash.Expr.t()], context :: map()) ::
      {:ok, [term()]} | {:error, Ash.Error.t()}

Link to this function

# can?(feature, resource)

View Source

    @spec can?(feature(), Ash.Resource.t() | Spark.Dsl.t()) :: boolean()

Link to this function

# create(resource, changeset)

View Source

    @spec create(Ash.Resource.t(), Ash.Changeset.t()) ::
      {:ok, Ash.Resource.record()}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this function

# data_layer(resource)

View Source

    @spec data_layer(Ash.Resource.t() | Spark.Dsl.t()) :: t() | nil

The data layer of the resource, or nil if it does not have one

Link to this function

# data_layer_can?(resource, feature)

View Source

    @spec data_layer_can?(Ash.Resource.t() | Spark.Dsl.t(), feature()) :: boolean()

Whether or not the data layer supports a specific feature

Link to this function

# data_layer_functions(resource)

View Source

    @spec data_layer_functions(Ash.Resource.t()) :: map()

Custom functions supported by the data layer of the resource

Link to this function

# destroy(resource, changeset)

View Source

    @spec destroy(Ash.Resource.t(), Ash.Changeset.t()) ::
      :ok | {:error, term()} | {:error, :no_rollback, term()}

Link to this function

# destroy_query(query, changeset, opts)

View Source

    @spec destroy_query(
      data_layer_query(),
      Ash.Changeset.t(),
      opts :: bulk_update_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this function

# distinct(query, distinct, resource)

View Source

    @spec distinct(data_layer_query(), Ash.Sort.t(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# distinct_sort(query, sort, resource)

View Source

    @spec distinct_sort(data_layer_query(), Ash.Sort.t(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# filter(query, filter, resource)

View Source

    @spec filter(data_layer_query(), Ash.Filter.t(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# functions(resource)

View Source
Link to this function

# in_transaction?(resource)

View Source
Link to this function

# limit(query, limit, resource)

View Source

    @spec limit(data_layer_query(), limit :: non_neg_integer(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# lock(query, lock_type, resource)

View Source

    @spec lock(
      data_layer_query(),
      lock_type :: lock_type() | nil,
      resource :: Ash.Resource.t()
    ) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# offset(query, offset, resource)

View Source

    @spec offset(data_layer_query(), offset :: non_neg_integer(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# prefer_lateral_join_for_many_to_many?(data_layer)

View Source

    @spec prefer_lateral_join_for_many_to_many?(t()) :: boolean()

Whether or not lateral joins should be used for many to many relationships by default

Link to this function

# resource_to_query(resource, domain)

View Source

    @spec resource_to_query(Ash.Resource.t(), Ash.Domain.t()) :: data_layer_query()

Link to this function

# return_query(query, resource)

View Source

    @spec return_query(data_layer_query(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# rollback(resource, term)

View Source

    @spec rollback(Ash.Resource.t() | [Ash.Resource.t()], term()) :: no_return()

Rolls back the current transaction

Link to this function

# run_aggregate_query(query, aggregates, resource)

View Source

    @spec run_aggregate_query(
      data_layer_query(),
      [Ash.Query.Aggregate.t()],
      Ash.Resource.t()
    ) :: {:ok, map()} | {:error, term()}

Link to this function

# run_aggregate_query_with_lateral_join(query, aggregates, root_data, destination_resource, path)

View Source
Link to this function

# run_query(query, central_resource)

View Source

    @spec run_query(data_layer_query(), central_resource :: Ash.Resource.t()) ::
      {:ok, [Ash.Resource.record()]}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this function

# run_query_with_lateral_join(query, root_data, destination_resource, path)

View Source
Link to this function

# select(query, select, resource)

View Source

    @spec select(data_layer_query(), select :: [atom()], Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# set_context(resource, query, map)

View Source

    @spec set_context(Ash.Resource.t(), data_layer_query(), map()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# set_tenant(resource, query, term)

View Source

    @spec set_tenant(Ash.Resource.t(), data_layer_query(), String.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# sort(query, sort, resource)

View Source

    @spec sort(data_layer_query(), Ash.Sort.t(), Ash.Resource.t()) ::
      {:ok, data_layer_query()} | {:error, term()}

Link to this function

# source(resource)

View Source

    @spec source(Ash.Resource.t()) :: String.t()

Link to this function

# transaction(resource_or_resources, func, timeout \\ nil, reason \\ %{type: :custom, metadata: %{}})

View Source

    @spec transaction(
      Ash.Resource.t() | [Ash.Resource.t()],
      (-> term()),
      nil | pos_integer(),
      reason :: transaction_reason()
    ) :: term()

Wraps the execution of the function in a transaction with the resource's data_layer

Link to this function

# transform_query(query)

View Source
Link to this function

# update(resource, changeset)

View Source

    @spec update(Ash.Resource.t(), Ash.Changeset.t()) ::
      {:ok, Ash.Resource.record()}
      | {:error, term()}
      | {:error, :no_rollback, term()}

Link to this function

# update_query(query, changeset, opts)

View Source

    @spec update_query(
      data_layer_query(),
      Ash.Changeset.t(),
      opts :: bulk_update_options()
    ) ::
      :ok
      | {:ok, Enumerable.t(Ash.Resource.record())}
      | {:error, Ash.Error.t()}
      | {:error, :no_rollback, Ash.Error.t()}

Link to this function

# upsert(resource, changeset, keys, identity \\ nil)

View Source

    @spec upsert(
      Ash.Resource.t(),
      Ash.Changeset.t(),
      [atom()],
      identity :: Ash.Resource.Identity.t() | nil
    ) ::
      {:ok,
       Ash.Resource.record()
       | {:upsert_skipped, Ash.Query.t(),
          (-> {:ok, Ash.Resource.record()}
              | {:error, term()}
              | {:error, :no_rollback, term()})}}
      | {:error, term()}
      | {:error, :no_rollback, term()}