EctoEnumerize

Hex.pm version

EctoEnumerize allows to define custom enums (keyword lists) to be used in your Ecto schemes.

It differs from EctoEnum because EctoEnumerize does not use the PostgreSQL native Enum type, instead it stores the value as an integer and therefore it should work on any database.

When using native Enum types, you would need to tell PostgreSQL all the possible values of your Enum and in order to add new values you would need to alter the table definition. At the moment PostgreSQL does not support dropping a value from an existing enum.

Check this thread on stackoverflow for more info.

Usage

First, we add ecto_enumerize to mix.exs:

def deps do
[
{:ecto_enumerize, "~> 0.1.0"}
]
end

Run mix deps.get to install ecto_enumerize.

Now we can define our enum as follow:

defmodule Order do
use Ecto.Schema
import EctoEnumerize
defenum Status, pending: 0, shipped: 1, delivered: 2
schema "orders" do
field :status, Status, default: :pending
end
def changeset(order, attrs) do
cast(order, attrs, [:status])
end
end

In the above example, the :status will behave like an enum and will allow you to pass an integer, atom or string to it. This applies to saving the model, invoking Ecto.Changeset.cast/4, or performing a query on the status field. Let's do a few examples:

iex> order = Repo.insert!(%Order{status: :delivered})
iex> Repo.get(Order, order.id).status
:delivered
iex> # any of these values will produce the same result
iex> s = Enum.random([:delivered, "delivered", 2])
iex> from(o in Order, where: o.status == ^s) |> Repo.aggregate(:count, :id)
1

Passing an invalid value to a Ecto.Changeset.cast/3 will add an error to changeset.errors field.

iex> cs = Order.changeset(order, %{status: :unknown})
iex> cs.errors
[status: {"is invalid", [type: Order.Status, validation: :cast]}]

Migrations

In your migrations:

def change do
create table(:orders) do
add :status, :integer
end
end