Packages
one_piece_commanded
0.21.3
0.26.0
0.25.2
0.25.1
0.25.0
0.24.0
0.23.0
0.22.0
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.0
0.5.0
0.4.1
0.4.0
0.3.0
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Extend Commanded package
Current section
Files
Jump to
Current section
Files
lib/one_piece/commanded/enum.ex
defmodule OnePiece.Commanded.Enum do
@moduledoc """
Defines an Enum type module.
"""
@doc """
Converts the module into a struct with an `:value` enum field.
## Using
- `Ecto.Schema`
- `Ecto.Type`
## Derives
- `Jason.Encoder`
## Usage
defmodule BankAccountType do
use OnePiece.Commanded.Enum, values: [:business, :personal]
end
{:ok, type} = BankAccountType.new(:business)
You can use it in your `Ecto.Schema` like this:
defmodule BankAccount do
use Ecto.Schema
embedded_schema do
field :type, BankAccountType
end
end
"""
defmacro __using__(opts) do
values = Keyword.fetch!(opts, :values)
type_ast = Enum.reduce(values, &{:|, [], [&1, &2]})
value_functions_ast =
for value <- values do
quote do
def unquote(value)(), do: %__MODULE__{value: unquote(value)}
end
end
load_functions_ast =
for value <- values do
quote do
@impl Ecto.Type
def load(unquote(Atom.to_string(value))) do
{:ok, %__MODULE__{value: unquote(value)}}
end
end
end
dump_functions_ast =
for value <- values do
value_string = Atom.to_string(value)
quote do
@impl Ecto.Type
def dump(%__MODULE__{value: unquote(value)}) do
{:ok, unquote(value_string)}
end
end
end
cast_as_function_ast =
for value <- values do
value_string = Atom.to_string(value)
quote do
@impl Ecto.Type
def cast(unquote(value_string)) do
{:ok, %__MODULE__{value: unquote(value)}}
end
end
end
quote generated: true do
alias OnePiece.Commanded.ValueObject
alias Ecto.Changeset
use Ecto.Schema
use Ecto.Type
@primary_key false
@enforce_keys [:value]
embedded_schema do
field :value, Ecto.Enum, values: unquote(values)
end
@type value :: unquote(type_ast)
@type t :: %__MODULE__{value: value()}
@doc """
Creates a `t:t/0`.
"""
@spec new(attrs :: %{required(:value) => value()}) :: {:ok, %__MODULE__{}} | {:error, Ecto.Changeset.t()}
def new(attrs) when is_map(attrs) do
ValueObject.__new__(__MODULE__, attrs)
end
@spec new(value :: value()) :: {:ok, %__MODULE__{}} | {:error, Ecto.Changeset.t()}
def new(value) do
ValueObject.__new__(__MODULE__, %{value: value})
end
@doc """
Creates a `t:t/0`.
"""
@spec new!(attrs :: %{required(:value) => value()}) :: %__MODULE__{}
def new!(attrs) when is_map(attrs) do
ValueObject.__new__!(__MODULE__, attrs)
end
@spec new!(value :: value()) :: %__MODULE__{}
def new!(value) do
ValueObject.__new__!(__MODULE__, %{value: value})
end
@doc """
Returns an `t:Ecto.Changeset.t/0` for a given `t:t/0` value object.
"""
@spec changeset(message :: %__MODULE__{}, attrs :: %{required(:value) => value()}) :: Ecto.Changeset.t()
def changeset(message, attrs) do
message
|> Changeset.cast(attrs, [:value])
|> Changeset.validate_required([:value])
end
@spec values() :: [unquote(type_ast)]
def values, do: unquote(values)
unquote_splicing(value_functions_ast)
@impl Ecto.Type
def type, do: :string
@impl Ecto.Type
def cast(value) when is_struct(value, __MODULE__) do
{:ok, value}
end
@impl Ecto.Type
def cast(%{value: value}) do
cast(value)
end
unquote_splicing(cast_as_function_ast)
@impl Ecto.Type
def cast(value) when value in unquote(values) do
{:ok, %__MODULE__{value: value}}
end
@impl Ecto.Type
def cast(_), do: :error
unquote_splicing(load_functions_ast)
@impl Ecto.Type
def load(_), do: :error
unquote_splicing(dump_functions_ast)
@impl Ecto.Type
def dump(_), do: :error
@impl Ecto.Type
def equal?(%__MODULE__{value: value1}, %__MODULE__{value: value1}) do
true
end
@impl Ecto.Type
def equal?(_term1, _term2), do: false
defimpl Jason.Encoder do
def encode(v, opts) do
Jason.Encode.value(v.value, opts)
end
end
end
end
end