Search documentation of ash

# Ash.Type.Enum behaviour (ash v3.4.71)

View Source

A type for abstracting enums into a single type.

For example, your existing attribute might look like:

    attribute :status, :atom, constraints: [one_of: [:open, :closed]]

But as that starts to spread around your system, you may find that you want to centralize that logic. To do that, use this module to define an Ash type easily:

    defmodule MyApp.TicketStatus do
      use Ash.Type.Enum, values: [:open, :closed]
    end

Then, you can rewrite your original attribute as follows:

    attribute :status, MyApp.TicketStatus

Valid values are:

- The atom itself, e.g `:open`
- A string that matches the atom, e.g `"open"`
- A string that matches the atom after being downcased, e.g `"OPEN"` or `"oPeN"`
- A string that matches the stringified, downcased atom, after itself being downcased. This allows for enum values like `:Open`, `:SomeState` and `:Some_State`

## Custom input values

If you need to accept inputs beyond those described above while still mapping them to one of the enum values, you can override the `match/1` callback.

For example, if you want to map both the `:half_empty` and `:half_full` states to the same enum value, you could implement it as follows:

    defmodule MyApp.GlassState do
      use Ash.Type.Enum, values: [:empty, :half_full, :full]

      def match(:half_empty), do: {:ok, :half_full}
      def match("half_empty"), do: {:ok, :half_full}
      def match(value), do: super(value)
    end

In the provided example, if no additional value is matched, `super(value)` is called, invoking the default implementation of `match/1`. This approach is typically suitable if you only aim to extend default matching rather than completely reimplementing it.

### Caveats

Additional input values are not exposed in derived interfaces. For example, `HALF_EMPTY` will not be present as a possible enum value when using `ash_graphql`.

Moreover, only explicitly matched values are mapped to the enum value. For instance, `"HaLf_emPty"` would not be accepted by the code provided earlier. If case normalization is needed for additional values, it must be explicitly implemented.

## Value descriptions

It's possible to associate a description with a value by passing a `{value, description}` tuple inside the values list, which becomes a keyword list:

    defmodule MyApp.TicketStatus do
      use Ash.Type.Enum,
        values: [
          open: "An open ticket",
          closed: "A closed ticket"
        ]
    end

This can be used by extensions to provide detailed descriptions of enum values.

The description of a value can be retrieved with `description/1`:

    MyApp.TicketStatus.description(:open)
    iex> "An open ticket"

# Summary

## Callbacks

description(arg1)

The description of the value, if existing

match(term)

finds the valid value that matches a given input term

match?(term)

true if a given term matches a value

values()

The list of valid values (not all input types that match them)

# Callbacks

# description(arg1)

    @callback description(atom() | String.t()) :: String.t() | nil

The description of the value, if existing

# match(term)

    @callback match(term()) :: {:ok, atom()} | :error

finds the valid value that matches a given input term

# match?(term)

    @callback match?(term()) :: boolean()

true if a given term matches a value

# values()

    @callback values() :: [atom() | String.t()]

The list of valid values (not all input types that match them)