Files
workload-service/lib/workload_service/aggregates/task.ex
HaimKortovich 1e493840de
All checks were successful
Build and Publish / build-release (push) Successful in 1m23s
remove version
2026-04-17 11:52:55 -05:00

135 lines
3.7 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
"""
@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)
quote do
@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
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
new_status = if status == "approved", do: "draft", else: "draft"
%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"}, %CompleteTask{} = cmd) do
%WorkloadService.Events.TaskCompleted{
id: cmd.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