Ash.Type behaviour (ash v1.44.4) View Source

Describes how to convert data to Ecto.Type and eventually into the database.

This behaviour is a superset of the Ecto.Type behavior, that also contains API level information, like what kinds of filters are allowed.

Built in types

Composite Types

Currently, the only composite type supported is a list type, specified via: {:array, Type}. The constraints available are:

  • :items - Constraints for the elements of the list. See the contained type's docs for more.

  • :min_length - A minimum length for the items

  • :max_length - A maximum length for the items

  • :nil_items? - Whether or not the list can contain nil items The default value is true.

Defining Custom Types

Generally you add use Ash.Type to your module (it is possible to add @behaviour Ash.Type and define everything yourself, but this is more work and error-prone).

Overriding the {:array, type} behavior. By definining the *_array versions of cast_input, cast_stored, dump_to_native and apply_constraints, you can override how your type behaves as a collection. This is how the features of embedded resources are implemented. No need to implement them unless you wish to override the default behavior.

Simple example of a float custom type

defmodule GenTracker.AshFloat do
  use Ash.Type

  @impl Ash.Type
  def storage_type, do: :float

  @impl Ash.Type
  def cast_input(value, _) do
    Ecto.Type.cast(:float, value)
  end

  @impl Ash.Type
  def cast_stored(value, _) do
    Ecto.Type.load(:float, value)
  end

  @impl Ash.Type
  def dump_to_native(value, _) do
    Ecto.Type.dump(:float, value)
  end
end

All the Ash built-in types are implemented with use Ash.Type so they are good examples to look at to create your own Ash.Type

Link to this section Summary

Functions

Confirms if a casted value matches the provided constraints.

Returns true if the value is a builtin type or adopts the Ash.Type behaviour

Casts input (e.g. unknown) data to an instance of the type, or errors

Casts a value from the data store to an instance of the type, or errors

Casts a value from the Elixir type to a value that can be embedded in another data structure.

Casts a value from the Elixir type to a value that the data store can persist

Returns the ecto compatible type for an Ash.Type.

Determines if two values of a given type are equal.

Process the old casted values alongside the new casted values.

Process the old casted values alongside the new uncasted values.

Returns the underlying storage type (the underlying type of the ecto type of the ash type)

Link to this section Types

Specs

constraint_error() :: String.t() | {String.t(), Keyword.t()}

Specs

constraints() :: Keyword.t()

Specs

t() :: atom() | {:array, atom()}

Link to this section Functions

Link to this function

apply_constraints(type, term, constraints)

View Source

Specs

apply_constraints(t(), term(), constraints()) ::
  {:ok, term()} | {:error, String.t()}

Confirms if a casted value matches the provided constraints.

Specs

ash_type?(term()) :: boolean()

Returns true if the value is a builtin type or adopts the Ash.Type behaviour

Link to this function

cast_input(type, term, constraints \\ [])

View Source

Specs

cast_input(t(), term(), constraints() | nil) ::
  {:ok, term()} | {:error, Keyword.t()} | :error

Casts input (e.g. unknown) data to an instance of the type, or errors

Maps to Ecto.Type.cast/2

Link to this function

cast_stored(type, term, constraints \\ [])

View Source

Specs

cast_stored(t(), term(), constraints() | nil) ::
  {:ok, term()} | {:error, keyword()} | :error

Casts a value from the data store to an instance of the type, or errors

Maps to Ecto.Type.load/2

Specs

constraints(t()) :: constraints()
Link to this function

constraints(source, type, constraints)

View Source

Specs

constraints(Ash.Changeset.t() | Ash.Query.t(), t(), Keyword.t()) :: Keyword.t()
Link to this function

describe(type, constraints)

View Source
Link to this function

dump_to_embedded(type, term, constraints \\ [])

View Source

Specs

dump_to_embedded(t(), term(), constraints() | nil) ::
  {:ok, term()} | {:error, keyword()} | :error

Casts a value from the Elixir type to a value that can be embedded in another data structure.

Embedded resources expect to be stored in JSON, so this allows things like UUIDs to be stored as strings in embedded resources instead of binary.

Link to this function

dump_to_native(type, term, constraints \\ [])

View Source

Specs

dump_to_native(t(), term(), constraints() | nil) ::
  {:ok, term()} | {:error, keyword()} | :error

Casts a value from the Elixir type to a value that the data store can persist

Maps to Ecto.Type.dump/2

Specs

ecto_type(t()) :: Ecto.Type.t()

Returns the ecto compatible type for an Ash.Type.

If you use Ash.Type, this is created for you. For builtin types this may return a corresponding ecto builtin type (atom)

Link to this function

equal?(type, left, right)

View Source

Specs

equal?(t(), term(), term()) :: boolean()

Determines if two values of a given type are equal.

Maps to Ecto.Type.equal?/3

Specs

get_type(atom() | module()) :: atom() | module() | {:array, atom() | module()}
Link to this function

handle_change(type, old_value, new_value, constraints)

View Source

Process the old casted values alongside the new casted values.

This is leveraged by embedded types to know if something is being updated or destroyed. This is not called on creates.

Link to this function

prepare_change(type, old_value, new_value, constraints)

View Source

Process the old casted values alongside the new uncasted values.

This is leveraged by embedded types to know if something is being updated or destroyed. This is not called on creates.

Specs

storage_type(t()) :: Ecto.Type.t()

Returns the underlying storage type (the underlying type of the ecto type of the ash type)

Link to this section Callbacks

Link to this callback

apply_constraints(term, constraints)

View Source

Specs

apply_constraints(term(), constraints()) ::
  {:ok, new_value :: term()}
  | :ok
  | {:error, constraint_error() | [constraint_error()]}
Link to this callback

apply_constraints_array(list, constraints)

View Source (optional)

Specs

apply_constraints_array([term()], constraints()) ::
  {:ok, new_values :: [term()]}
  | :ok
  | {:error, constraint_error() | [constraint_error()]}
Link to this callback

array_constraints()

View Source (optional)

Specs

array_constraints() :: constraints()
Link to this callback

cast_input(term, constraints)

View Source

Specs

cast_input(term(), constraints()) ::
  {:ok, term()} | {:error, Keyword.t()} | :error
Link to this callback

cast_input_array(list, constraints)

View Source (optional)

Specs

cast_input_array([term()], constraints()) ::
  {:ok, [term()]} | {:error, Keyword.t()} | :error
Link to this callback

cast_stored(term, constraints)

View Source

Specs

cast_stored(term(), constraints()) :: {:ok, term()} | :error
Link to this callback

cast_stored_array(list, constraints)

View Source (optional)

Specs

cast_stored_array([term()], constraints()) :: {:ok, [term()]} | :error

Specs

constraints() :: constraints()

Specs

describe(constraints()) :: String.t() | nil
Link to this callback

dump_to_embedded(term, constraints)

View Source (optional)

Specs

dump_to_embedded(term(), constraints()) :: {:ok, term()} | :error
Link to this callback

dump_to_embedded_array(list, constraints)

View Source (optional)

Specs

dump_to_embedded_array([term()], constraints()) :: {:ok, term()} | :error
Link to this callback

dump_to_native(term, constraints)

View Source

Specs

dump_to_native(term(), constraints()) :: {:ok, term()} | :error
Link to this callback

dump_to_native_array(list, constraints)

View Source (optional)

Specs

dump_to_native_array([term()], constraints()) :: {:ok, term()} | :error

Specs

ecto_type() :: Ecto.Type.t()

Specs

equal?(term(), term()) :: boolean()
Link to this callback

handle_change(old_term, new_term, constraints)

View Source

Specs

handle_change(old_term :: term(), new_term :: term(), constraints()) ::
  {:ok, term()} | {:error, term()}
Link to this callback

handle_change_array(old_term, new_term, constraints)

View Source (optional)

Specs

handle_change_array(old_term :: [term()], new_term :: [term()], constraints()) ::
  {:ok, term()} | {:error, term()}
Link to this callback

prepare_change(old_term, new_uncasted_term, constraints)

View Source

Specs

prepare_change(old_term :: term(), new_uncasted_term :: term(), constraints()) ::
  {:ok, term()} | {:error, term()}
Link to this callback

prepare_change_array(old_term, new_uncasted_term, constraints)

View Source (optional)

Specs

prepare_change_array(
  old_term :: [term()],
  new_uncasted_term :: [term()],
  constraints()
) :: {:ok, term()} | {:error, term()}

Specs

storage_type() :: Ecto.Type.t()