Current section
Files
Jump to
Current section
Files
lib/ecto/fsm/schema.ex
defmodule Ecto.FSM.Schema do
@moduledoc """
Provides `status/{1,2}` macro for adding status field in an `Ecto.Schema`.
"""
defmacro __using__(_opts) do
quote do
use Ecto.Schema
import Ecto.FSM.Schema
@before_compile Ecto.FSM.Schema
end
end
defmacro __before_compile__(env) do
states_schema = env.module
states_handler =
states_schema
|> Module.get_attribute(:states_handler)
|> case do
nil ->
raise """
Schema #{env.module} is missing a status field.
You can add one with `Ecto.FSM.Schema.status/{1,2}`.
"""
m ->
m
end
states_field = Module.get_attribute(states_schema, :states_field)
quote do
alias Ecto.Changeset
def state_name(s) do
s
|> Changeset.change()
|> Changeset.get_field(unquote(states_field))
end
def set_state_name(s, name) do
s
|> Changeset.change()
|> Changeset.put_change(unquote(states_field), name)
end
defimpl Ecto.FSM.Machine.State do
def handlers(_), do: [unquote(states_handler)]
def state_name(s), do: unquote(states_schema).state_name(s)
def set_state_name(s, name), do: unquote(states_schema).set_state_name(s, name)
end
defimpl Ecto.FSM.Schema.State do
def field(_), do: unquote(states_field)
end
end
end
@doc """
Generates `status` field from an `Ecto.FSM` module.
## Options
* `:name` - the name of the field for status
* `:type` - module name for the enumeration type (use `EctoEnum`)
* `:default` - default value for status field
"""
defmacro status(handler, opts \\ []) do
opts =
[name: :status, type: Module.concat(__CALLER__.module, "Status"), default: nil]
|> Keyword.merge(opts)
states_field = Keyword.fetch!(opts, :name)
states_type = Keyword.fetch!(opts, :type)
states_default = Keyword.fetch!(opts, :default)
states_type_name =
states_type
|> Module.split()
|> Enum.map(&Macro.underscore/1)
|> Enum.join("_")
quote do
@states_field unquote(states_field)
@states_handler unquote(handler)
require unquote(handler)
require EctoEnum
states_names = @states_handler.states_names()
EctoEnum.defenum(unquote(states_type), unquote(states_type_name), states_names)
field_opts =
case unquote(states_default) do
nil -> []
default -> [default: default]
end
Ecto.Schema.__field__(__MODULE__, @states_field, unquote(states_type), field_opts)
end
end
end