defmodule OnePiece.Commanded.Command do
@moduledoc """
Defines "Command" modules.
"""
@typedoc """
A struct that represents a command.
"""
@type t :: struct()
@typedoc """
The aggregate identifier key of the event.
If it's a tuple, the type must be a module that implements the `OnePiece.Commanded.ValueObject` module or [`Ecto` built-in types](https://hexdocs.pm/ecto/Ecto.Schema.html#module-types-and-casting)
"""
@type aggregate_identifier_opt ::
atom() | {key_name :: atom(), type :: atom()} | {key_name :: atom(), type :: module()}
@doc """
Converts the module into an `t:t/0`.
### Options
- `:aggregate_identifier` - The aggregate identifier key.
- `:identity_prefix` (optional) - The prefix to be used for the identity.
## Aggregate Identifier
The `aggregate_identifier` is used to identify the aggregate that the command is associated with. It uses the
`@primary_key` attribute to define the column and type.
> #### Schema Field Registration {: .info}
> `aggregate_identifier` is automatically registered as a field in the `embedded_schema`.
> Do not define the field in the `embedded_schema` yourself again.
## Using
- `OnePiece.Commanded.ValueObject`
## Usage
defmodule MyCommand do
use OnePiece.Commanded.Command, aggregate_identifier: :id
embedded_schema do
# ...
end
end
You can also define a custom type as the aggregate identifier:
defmodule IdentityRoleId do
use OnePiece.Commanded.ValueObject
embedded_schema do
field :identity_id, :string
field :role_id, :string
end
end
defmodule AssignRole do
use OnePiece.Commanded.Command,
aggregate_identifier: {:id, IdentityRoleId}
embedded_schema do
# ...
end
end
"""
@spec __using__(opts :: [aggregate_identifier: aggregate_identifier_opt(), identity_prefix: String.t() | nil]) ::
any()
defmacro __using__(opts \\ []) do
unless Keyword.has_key?(opts, :aggregate_identifier) do
raise ArgumentError, "missing :aggregate_identifier key"
end
identity_prefix = Keyword.get(opts, :identity_prefix)
{aggregate_identifier, aggregate_identifier_type} =
opts
|> Keyword.fetch!(:aggregate_identifier)
|> OnePiece.Commanded.Helpers.get_primary_key()
quote generated: true do
use OnePiece.Commanded.ValueObject
@typedoc """
The key used to identify the aggregate.
"""
@type aggregate_identifier_key :: unquote(aggregate_identifier)
@primary_key {unquote(aggregate_identifier), unquote(aggregate_identifier_type), autogenerate: false}
@doc """
Returns the aggregate identifier key.
"""
@spec aggregate_identifier :: aggregate_identifier_key()
def aggregate_identifier do
unquote(aggregate_identifier)
end
@doc """
Returns `#{inspect(unquote(identity_prefix))}` as the identity prefix.
"""
@spec identity_prefix :: String.t() | nil
def identity_prefix do
unquote(identity_prefix)
end
end
end
end