lib/incident/aggregate_state.ex

defmodule Incident.AggregateState do
  @moduledoc """
  Defines an Aggregate State macro that receives the aggregate module and an initial state.
  """

  defmacro __using__(opts) do
    aggregate = Keyword.get(opts, :aggregate)
    initial_state = Keyword.get(opts, :initial_state)

    quote do
      import Incident.AggregateState

      alias Incident.EventStore

      @doc """
      Reads all the persisted events for a specific aggregate and apply them, returning the current aggregate state.
      """
      @spec get(String.t()) :: any
      def get(aggregate_id) do
        aggregate_id
        |> EventStore.get()
        |> Enum.reduce(unquote(initial_state), fn event, state ->
          unquote(aggregate).apply(event, state)
        end)
      end
    end
  end
end