Packages
one_piece_commanded
0.15.1
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/value_object.ex
defmodule OnePiece.Commanded.ValueObject do
@moduledoc """
Defines "Value Object" modules.
"""
alias Ecto.Changeset
@doc """
Converts the module into an `Ecto.Schema`.
It derives from `Jason.Encoder` and also adds some factory functions to create
structs.
## Usage
defmodule MyValueObject do
use OnePiece.Commanded.ValueObject
embedded_schema do
field :title, :string
# ...
end
end
{:ok, my_value} = MyValueObject.new(%{title: "Hello, World!"})
"""
@spec __using__(opts :: []) :: any()
defmacro __using__(_opts \\ []) do
quote do
alias OnePiece.Commanded.ValueObject
use Ecto.Schema
@derive Jason.Encoder
@primary_key false
@before_compile OnePiece.Commanded.ValueObject
@doc """
Creates a `t:t/0`.
"""
@spec new(attrs :: map()) :: {:ok, %__MODULE__{}}
def new(attrs) do
ValueObject.__new__(__MODULE__, attrs)
end
@doc """
Creates a `t:t/0`.
"""
@spec new!(attrs :: map()) :: %__MODULE__{}
def new!(attrs) do
ValueObject.__new__!(__MODULE__, attrs)
end
@doc """
Returns an `t:Ecto.Changeset.t/0` for a given `t:t/0` command.
"""
@spec changeset(message :: %__MODULE__{}, attrs :: map()) :: Ecto.Changeset.t()
def changeset(message, attrs) do
ValueObject.__changeset__(message, attrs)
end
defoverridable new: 1, new!: 1, changeset: 2
end
end
defmacro __before_compile__(env) do
enforced_keys = get_enforced_keys(env)
quote unquote: false, bind_quoted: [enforced_keys: enforced_keys] do
def __enforced_keys__ do
unquote(enforced_keys)
end
for the_key <- enforced_keys do
def __enforced_keys__?(unquote(the_key)) do
true
end
end
def __enforced_keys__?(_) do
false
end
end
end
defp get_enforced_keys(env) do
enforce_keys = Module.get_attribute(env.module, :enforce_keys) || []
enforce_keys ++ get_primary_key_name(env)
end
defp get_primary_key_name(env) do
case Module.get_attribute(env.module, :primary_key) do
{field_name, _, _} -> [field_name]
_ -> []
end
end
def __new__(struct_module, attrs) do
struct_module
|> apply_changeset(attrs)
|> Changeset.apply_action(:new)
end
def __new__!(struct_module, attrs) do
struct_module
|> apply_changeset(attrs)
|> Changeset.apply_action!(:new)
end
def __changeset__(%struct_module{} = message, attrs) do
embeds = struct_module.__schema__(:embeds)
allowed = struct_module.__schema__(:fields) -- embeds
changeset =
message
|> Changeset.cast(attrs, allowed)
|> Changeset.validate_required(struct_module.__enforced_keys__() -- embeds)
Enum.reduce(embeds, changeset, fn field, changeset ->
Changeset.cast_embed(changeset, field, required: struct_module.__enforced_keys__?(field))
end)
end
defp apply_changeset(struct_module, attrs) do
struct(struct_module)
|> struct_module.changeset(attrs)
end
end