All checks were successful
Build and Publish / build-release (push) Successful in 1m24s
156 lines
4.4 KiB
Elixir
156 lines
4.4 KiB
Elixir
defmodule WorkloadService.Aggregates.Task do
|
|
@moduledoc """
|
|
Behaviour and __using__ macro for task aggregates.
|
|
Each task type can override validation and add specific behavior.
|
|
|
|
Usage:
|
|
defmodule WorkloadService.Aggregates.QuoteTask do
|
|
use WorkloadService.Aggregates.Task,
|
|
task_type: "quote"
|
|
end
|
|
|
|
## With custom submission type
|
|
|
|
defmodule QuoteTaskWithCustomSubmission do
|
|
defmodule CustomSubmission do
|
|
@type t :: %{...custom_fields: term()}
|
|
end
|
|
|
|
use WorkloadService.Aggregates.Task,
|
|
task_type: "quote",
|
|
submission_type: CustomSubmission.t()
|
|
end
|
|
"""
|
|
|
|
@callback validate_submission(map()) :: :ok | {:error, term()}
|
|
|
|
defmacro __using__(opts) do
|
|
task_type = Keyword.fetch!(opts, :task_type)
|
|
commands_module = Keyword.get(opts, :commands, WorkloadService.Commands.Task)
|
|
submission_type = Keyword.get(opts, :submission_type, quote(do: map()))
|
|
|
|
quote do
|
|
@type t :: %__MODULE__{
|
|
id: WorkloadService.Aggregates.TaskId.t() | nil,
|
|
application_id: WorkloadService.Aggregates.ApplicationId.t() | nil,
|
|
task_info: map() | nil,
|
|
submission: unquote(submission_type) | nil,
|
|
attachments: [String.t()],
|
|
status: String.t() | nil
|
|
}
|
|
|
|
@behaviour Commanded.Aggregates.Aggregate
|
|
@task_type unquote(task_type)
|
|
|
|
alias unquote(commands_module).CreateTask
|
|
alias unquote(commands_module).SubmitResponse
|
|
alias unquote(commands_module).ApproveSubmission
|
|
alias unquote(commands_module).CompleteTask
|
|
|
|
alias Commanded.Aggregates.Aggregate
|
|
|
|
@derive Jason.Encoder
|
|
defstruct [
|
|
:id,
|
|
:application_id,
|
|
:task_info,
|
|
:submission,
|
|
:attachments,
|
|
:status
|
|
]
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{status: nil}, %CreateTask{} = cmd) do
|
|
%WorkloadService.Events.TaskCreated{
|
|
id: cmd.id,
|
|
application_id: cmd.application_id,
|
|
task_info: cmd.task_info,
|
|
attachments: cmd.attachments || []
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{}, %CreateTask{}) do
|
|
{:error, :task_already_exists}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{status: status}, %SubmitResponse{} = cmd)
|
|
when status in [nil, "created", "draft", "approved"] do
|
|
with :ok <- validate_submission(cmd.submission) do
|
|
%WorkloadService.Events.SubmissionUpdated{
|
|
id: cmd.id,
|
|
submission: cmd.submission,
|
|
attachments: cmd.attachments
|
|
}
|
|
end
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{id: id, status: "draft"}, %ApproveSubmission{}) do
|
|
%WorkloadService.Events.SubmissionApproved{
|
|
id: id
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{status: status}, %ApproveSubmission{}) do
|
|
{:error, {:invalid_state, "cannot approve in state: #{status}"}}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{status: "approved", id: id}, %CompleteTask{} = cmd) do
|
|
%WorkloadService.Events.TaskCompleted{
|
|
id: id,
|
|
completed_by: cmd.completed_by
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def execute(%__MODULE__{status: status}, %CompleteTask{}) do
|
|
{:error, {:invalid_state, "cannot complete in state: #{status}"}}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def apply(%__MODULE__{} = agg, %WorkloadService.Events.TaskCreated{} = e) do
|
|
%{
|
|
agg
|
|
| id: e.id,
|
|
application_id: e.application_id,
|
|
task_info: e.task_info,
|
|
attachments: e.attachments,
|
|
status: "created"
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def apply(%__MODULE__{} = agg, %WorkloadService.Events.SubmissionUpdated{} = e) do
|
|
%{
|
|
agg
|
|
| submission: e.submission,
|
|
attachments: e.attachments || [],
|
|
status: "draft"
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def apply(%__MODULE__{} = agg, %WorkloadService.Events.SubmissionApproved{}) do
|
|
%{
|
|
agg
|
|
| status: "approved"
|
|
}
|
|
end
|
|
|
|
@impl Aggregate
|
|
def apply(%__MODULE__{} = agg, %WorkloadService.Events.TaskCompleted{}) do
|
|
%{
|
|
agg
|
|
| status: "completed"
|
|
}
|
|
end
|
|
|
|
defoverridable execute: 2, apply: 2
|
|
end
|
|
end
|
|
end
|