Current section
Files
Jump to
Current section
Files
src/evoq_state.erl
%% @doc State behaviour for evoq aggregates.
%%
%% The state module is the "default read model" — it owns the aggregate's
%% state record, knows how to create initial state, apply events to update
%% state, and serialize/deserialize state for feedback and snapshots.
%%
%% Every aggregate MUST have a corresponding state module. The aggregate
%% declares it via the state_module/0 callback, and delegates state
%% operations to it:
%%
%% %% In the aggregate:
%% state_module() -> venture_state.
%% init(AggregateId) -> {ok, venture_state:new(AggregateId)}.
%% apply(State, Event) -> venture_state:apply_event(State, Event).
%%
%% This separation keeps the aggregate focused on command validation and
%% business rules, while the state module owns the data shape, field
%% access, event folding, and serialization.
%%
%% == Required Callbacks ==
%%
%% - new(AggregateId) -> State
%% - apply_event(State, Event) -> State
%% - to_map(State) -> map()
%%
%% == Optional Callbacks ==
%%
%% - from_map(Map) -> {ok, State} | {error, Reason}
%%
%% @author rgfaber
-module(evoq_state).
%% Required callbacks
%% Create initial (empty) state for a new aggregate.
-callback new(AggregateId :: binary()) -> State :: term().
%% Apply a single event to update state. Must be pure and deterministic.
%% Called for each event produced by execute/2 and during replay.
-callback apply_event(State :: term(), Event :: map()) -> State :: term().
%% Serialize state to a map. Used for session-level consistency feedback,
%% snapshot serialization, and programmatic state inspection.
-callback to_map(State :: term()) -> map().
%% Optional callbacks
%% Deserialize state from a map. Used for snapshot loading and
%% state reconstruction from external sources.
-callback from_map(Map :: map()) -> {ok, State :: term()} | {error, Reason :: term()}.
-optional_callbacks([from_map/1]).