evoq_command behaviour (evoq v1.30.1)

View Source

Command behavior for evoq.

Commands represent intentions to change state. They are: - Imperative (present tense): open_account, deposit_money - Targeted at a specific aggregate - Validated before dispatch - Domain artifacts: atom keys, Erlang terms, stay inside bounded context

Required Callbacks

- command_type() -> atom() - new(Params) -> {ok, Command} | {error, Reason} - to_map(Command) -> map()

Optional Callbacks

- validate(Command) -> ok | {error, Reason} - from_map(Map) -> {ok, Command} | {error, Reason}

Summary

Functions

Give the command the identity it needs to be dispatched.

Get the aggregate ID.

Get the aggregate type.

Get the command ID.

Get the idempotency key (may be undefined).

Get the command metadata.

Get the command payload.

Get the command type.

Set a caller-provided idempotency key for deduplication.

Validate a command using its module's validate/1 callback.

Callbacks

command_type/0

-callback command_type() -> atom().

from_map/1

(optional)
-callback from_map(Map :: map()) -> {ok, Command :: term()} | {error, Reason :: term()}.

new/1

-callback new(Params :: map()) -> {ok, Command :: term()} | {error, Reason :: term()}.

to_map/1

-callback to_map(Command :: term()) -> map().

validate/1

(optional)
-callback validate(Command :: term()) -> ok | {ok, Command :: term()} | {error, Reason :: term()}.

Functions

ensure_id(Evoq_command)

-spec ensure_id(#evoq_command{command_id :: binary() | undefined,
                              command_type :: atom() | undefined,
                              aggregate_type :: atom() | undefined,
                              aggregate_id :: binary() | undefined,
                              payload :: map(),
                              metadata :: map(),
                              causation_id :: binary() | undefined,
                              correlation_id :: binary() | undefined,
                              idempotency_key :: binary() | undefined}) ->
                   #evoq_command{command_id :: binary() | undefined,
                                 command_type :: atom() | undefined,
                                 aggregate_type :: atom() | undefined,
                                 aggregate_id :: binary() | undefined,
                                 payload :: map(),
                                 metadata :: map(),
                                 causation_id :: binary() | undefined,
                                 correlation_id :: binary() | undefined,
                                 idempotency_key :: binary() | undefined}.

Give the command the identity it needs to be dispatched.

A command with no command_id gets one; a command with no correlation_id gets one too, and that is the only place a correlation is minted. Called by the command router on every dispatch, so by the time an aggregate appends the events a command produced, the command has a conversation to stamp them with. A command that already carries a correlation - a process manager copying its triggering event's, or an application choosing its own - keeps it.

get_aggregate_id(Evoq_command)

-spec get_aggregate_id(#evoq_command{command_id :: binary() | undefined,
                                     command_type :: atom() | undefined,
                                     aggregate_type :: atom() | undefined,
                                     aggregate_id :: binary() | undefined,
                                     payload :: map(),
                                     metadata :: map(),
                                     causation_id :: binary() | undefined,
                                     correlation_id :: binary() | undefined,
                                     idempotency_key :: binary() | undefined}) ->
                          binary().

Get the aggregate ID.

get_aggregate_type(Evoq_command)

-spec get_aggregate_type(#evoq_command{command_id :: binary() | undefined,
                                       command_type :: atom() | undefined,
                                       aggregate_type :: atom() | undefined,
                                       aggregate_id :: binary() | undefined,
                                       payload :: map(),
                                       metadata :: map(),
                                       causation_id :: binary() | undefined,
                                       correlation_id :: binary() | undefined,
                                       idempotency_key :: binary() | undefined}) ->
                            atom().

Get the aggregate type.

get_id(Evoq_command)

-spec get_id(#evoq_command{command_id :: binary() | undefined,
                           command_type :: atom() | undefined,
                           aggregate_type :: atom() | undefined,
                           aggregate_id :: binary() | undefined,
                           payload :: map(),
                           metadata :: map(),
                           causation_id :: binary() | undefined,
                           correlation_id :: binary() | undefined,
                           idempotency_key :: binary() | undefined}) ->
                binary().

Get the command ID.

get_idempotency_key(Evoq_command)

-spec get_idempotency_key(#evoq_command{command_id :: binary() | undefined,
                                        command_type :: atom() | undefined,
                                        aggregate_type :: atom() | undefined,
                                        aggregate_id :: binary() | undefined,
                                        payload :: map(),
                                        metadata :: map(),
                                        causation_id :: binary() | undefined,
                                        correlation_id :: binary() | undefined,
                                        idempotency_key :: binary() | undefined}) ->
                             binary() | undefined.

Get the idempotency key (may be undefined).

get_metadata(Evoq_command)

-spec get_metadata(#evoq_command{command_id :: binary() | undefined,
                                 command_type :: atom() | undefined,
                                 aggregate_type :: atom() | undefined,
                                 aggregate_id :: binary() | undefined,
                                 payload :: map(),
                                 metadata :: map(),
                                 causation_id :: binary() | undefined,
                                 correlation_id :: binary() | undefined,
                                 idempotency_key :: binary() | undefined}) ->
                      map().

Get the command metadata.

get_payload(Evoq_command)

-spec get_payload(#evoq_command{command_id :: binary() | undefined,
                                command_type :: atom() | undefined,
                                aggregate_type :: atom() | undefined,
                                aggregate_id :: binary() | undefined,
                                payload :: map(),
                                metadata :: map(),
                                causation_id :: binary() | undefined,
                                correlation_id :: binary() | undefined,
                                idempotency_key :: binary() | undefined}) ->
                     map().

Get the command payload.

get_type(Evoq_command)

-spec get_type(#evoq_command{command_id :: binary() | undefined,
                             command_type :: atom() | undefined,
                             aggregate_type :: atom() | undefined,
                             aggregate_id :: binary() | undefined,
                             payload :: map(),
                             metadata :: map(),
                             causation_id :: binary() | undefined,
                             correlation_id :: binary() | undefined,
                             idempotency_key :: binary() | undefined}) ->
                  atom().

Get the command type.

new(CommandType, AggregateType, AggregateId, Payload)

-spec new(atom(), atom(), binary(), map()) ->
             #evoq_command{command_id :: binary() | undefined,
                           command_type :: atom() | undefined,
                           aggregate_type :: atom() | undefined,
                           aggregate_id :: binary() | undefined,
                           payload :: map(),
                           metadata :: map(),
                           causation_id :: binary() | undefined,
                           correlation_id :: binary() | undefined,
                           idempotency_key :: binary() | undefined}.

Create a new command.

new(CommandType, AggregateType, AggregateId, Payload, Metadata)

-spec new(atom(), atom(), binary(), map(), map()) ->
             #evoq_command{command_id :: binary() | undefined,
                           command_type :: atom() | undefined,
                           aggregate_type :: atom() | undefined,
                           aggregate_id :: binary() | undefined,
                           payload :: map(),
                           metadata :: map(),
                           causation_id :: binary() | undefined,
                           correlation_id :: binary() | undefined,
                           idempotency_key :: binary() | undefined}.

Create a new command with metadata.

correlation_id is left undefined on purpose: it is minted at dispatch when the command does not carry one (see ensure_id/1). That is what makes "this command joins the conversation of the event that caused it" a decision the caller can take, by setting the id before dispatching, rather than something the constructor has already decided.

set_causation_id(CausationId, Evoq_command)

-spec set_causation_id(binary(),
                       #evoq_command{command_id :: binary() | undefined,
                                     command_type :: atom() | undefined,
                                     aggregate_type :: atom() | undefined,
                                     aggregate_id :: binary() | undefined,
                                     payload :: map(),
                                     metadata :: map(),
                                     causation_id :: binary() | undefined,
                                     correlation_id :: binary() | undefined,
                                     idempotency_key :: binary() | undefined}) ->
                          #evoq_command{command_id :: binary() | undefined,
                                        command_type :: atom() | undefined,
                                        aggregate_type :: atom() | undefined,
                                        aggregate_id :: binary() | undefined,
                                        payload :: map(),
                                        metadata :: map(),
                                        causation_id :: binary() | undefined,
                                        correlation_id :: binary() | undefined,
                                        idempotency_key :: binary() | undefined}.

Set the causation ID.

set_correlation_id(CorrelationId, Evoq_command)

-spec set_correlation_id(binary(),
                         #evoq_command{command_id :: binary() | undefined,
                                       command_type :: atom() | undefined,
                                       aggregate_type :: atom() | undefined,
                                       aggregate_id :: binary() | undefined,
                                       payload :: map(),
                                       metadata :: map(),
                                       causation_id :: binary() | undefined,
                                       correlation_id :: binary() | undefined,
                                       idempotency_key :: binary() | undefined}) ->
                            #evoq_command{command_id :: binary() | undefined,
                                          command_type :: atom() | undefined,
                                          aggregate_type :: atom() | undefined,
                                          aggregate_id :: binary() | undefined,
                                          payload :: map(),
                                          metadata :: map(),
                                          causation_id :: binary() | undefined,
                                          correlation_id :: binary() | undefined,
                                          idempotency_key :: binary() | undefined}.

Set the correlation ID.

set_idempotency_key(Key, Evoq_command)

-spec set_idempotency_key(binary(),
                          #evoq_command{command_id :: binary() | undefined,
                                        command_type :: atom() | undefined,
                                        aggregate_type :: atom() | undefined,
                                        aggregate_id :: binary() | undefined,
                                        payload :: map(),
                                        metadata :: map(),
                                        causation_id :: binary() | undefined,
                                        correlation_id :: binary() | undefined,
                                        idempotency_key :: binary() | undefined}) ->
                             #evoq_command{command_id :: binary() | undefined,
                                           command_type :: atom() | undefined,
                                           aggregate_type :: atom() | undefined,
                                           aggregate_id :: binary() | undefined,
                                           payload :: map(),
                                           metadata :: map(),
                                           causation_id :: binary() | undefined,
                                           correlation_id :: binary() | undefined,
                                           idempotency_key :: binary() | undefined}.

Set a caller-provided idempotency key for deduplication.

validate(Evoq_command)

-spec validate(#evoq_command{command_id :: binary() | undefined,
                             command_type :: atom() | undefined,
                             aggregate_type :: atom() | undefined,
                             aggregate_id :: binary() | undefined,
                             payload :: map(),
                             metadata :: map(),
                             causation_id :: binary() | undefined,
                             correlation_id :: binary() | undefined,
                             idempotency_key :: binary() | undefined}) ->
                  ok | {error, term()}.

Validate a command using its module's validate/1 callback.