Skip to content

Commit b4271f2

Browse files
authored
Merge pull request #35 from ccamel/copilot/rename-callbacks-for-consistency
refactor: rename event store callbacks to align with ES domain terminology
2 parents 33f79a2 + 74a5dc4 commit b4271f2

10 files changed

Lines changed: 127 additions & 112 deletions

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,13 @@ The event store is a core component in this experiment, designed as a customizab
120120
% Shuts down the event store.
121121
-callback stop() -> {ok} | {error, term()}.
122122

123-
% Persists a list of events for a given stream.
124-
-callback persist_events(StreamId, Events) -> ok | {error, term()}
123+
% Appends a list of events for a given stream.
124+
-callback append(StreamId, Events) -> ok | {error, term()}
125125
when StreamId :: stream_id(),
126126
Events :: [event()].
127127

128-
% Retrieves events from a stream and folds them using a provided function
129-
-callback retrieve_and_fold_events(StreamId, Options, FoldFun, InitialAcc) -> {ok, Acc} | {error, term()}
128+
% Folds events from a stream using a provided function
129+
-callback fold(StreamId, Options, FoldFun, InitialAcc) -> {ok, Acc} | {error, term()}
130130
when StreamId :: stream_id(),
131131
Options :: fold_events_opts(),
132132
FoldFun :: fold_events_fun(),
@@ -144,11 +144,11 @@ The event store supports snapshotting to optimize aggregate rehydration. Instead
144144
**Snapshot Callbacks:**
145145

146146
```erlang
147-
% Save a snapshot of aggregate state
148-
-callback save_snapshot(Snapshot) -> ok when Snapshot :: snapshot().
147+
% Store a snapshot of aggregate state
148+
-callback store(Snapshot) -> ok when Snapshot :: snapshot().
149149

150-
% Retrieve the latest snapshot for a stream
151-
-callback retrieve_latest_snapshot(StreamId) -> {ok, Snapshot} | {error, not_found}.
150+
% Load the latest snapshot for a stream
151+
-callback load_latest(StreamId) -> {ok, Snapshot} | {error, not_found}.
152152
```
153153

154154
The snapshot record contains all necessary fields (domain, stream_id, sequence, timestamp, state), making the API consistent with event persistence where events are passed as complete records.

apps/event_sourcing_contract/src/event_sourcing_event_store_behaviour.erl

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ be replayed for state reconstruction.
88

99
Callbacks:
1010
- `start/0`, `stop/0` — manage the backend's lifecycle
11-
- `persist_events/2` — append events to a stream, ensuring monotonic sequence numbers
12-
- `retrieve_and_fold_events/4` — replay events in order and fold them with a user function
11+
- `append/2` — append events to a stream, ensuring monotonic sequence numbers
12+
- `fold/4` — replay events in order and fold them with a user function
1313

1414
Implementations must guarantee:
1515
- **ordering**: events for a given stream are stored and replayed in strictly increasing
@@ -46,7 +46,9 @@ Returns `ok` on success. May throw an exception if cleanup fails
4646
-doc """
4747
Append events to an event stream.
4848

49-
This callback appends events to the specified streams.
49+
This callback appends events to the specified stream, ensuring monotonic ordering
50+
by sequence number. Each event is durably persisted and becomes part of the immutable
51+
event log for the stream.
5052

5153
- StreamId is an atom identifying the event stream (e.g., order-123).
5254
- Events is the list of events to append to the stream. The events provided are unique and all
@@ -55,7 +57,7 @@ belong to the same stream.
5557
Returns `ok` on success. May throw an exception if persistence fails (e.g., badarg if the
5658
stream ID is incorrect, duplicate events if the sequence number is not unique).
5759
""".
58-
-callback persist_events(StreamId, Events) -> ok when
60+
-callback append(StreamId, Events) -> ok when
5961
StreamId :: stream_id(),
6062
Events :: [event()].
6163
-doc """
@@ -71,11 +73,11 @@ rebuild application state by replaying events.
7173
- `{to, Sequence | infinity}`: End at this sequence (default: infinity).
7274
- `{limit, Limit}`: Maximum number of events to retrieve (default: infinity).
7375
- FoldFun is a function `fun((Event, AccIn) -> AccOut)` to process each event.
74-
- InitialAcc is The initial accumulator value (e.g., an empty state).
76+
- InitialAcc is the initial accumulator value (e.g., an empty state).
7577

76-
Returns `{ok, Acc}` where `Acc` is the result of folding all events.
78+
Returns the final accumulator after folding all events.
7779
""".
78-
-callback retrieve_and_fold_events(StreamId, Options, Fun, Acc0) -> Acc1 when
80+
-callback fold(StreamId, Options, Fun, Acc0) -> Acc1 when
7981
StreamId :: stream_id(),
8082
Options :: fold_events_opts(),
8183
Fun :: fun((Event :: event(), AccIn) -> AccOut),

apps/event_sourcing_contract/src/event_sourcing_snapshot_store_behaviour.erl

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ representations of the state after applying a set of events.
77

88
Callbacks:
99
- `start/0`, `stop/0` — manage backend initialization and shutdown
10-
- `save_snapshot/1` — persist a snapshot of the aggregate state
11-
- `retrieve_latest_snapshot/1` — fetch the most recent snapshot for a given stream
10+
- `store/1` — persist a snapshot of the aggregate state
11+
- `load_latest/1` — fetch the most recent snapshot for a given stream
1212

1313
Design principles:
1414
- Snapshots are **optional optimizations**; events remain the source of truth.
@@ -23,37 +23,38 @@ systems (e.g., S3).
2323
-include("event_sourcing.hrl").
2424

2525
-doc """
26-
Save a snapshot for a stream.
26+
Store a snapshot for a stream.
2727

28-
This callback saves a snapshot of the aggregate state at a specific point in time.
29-
The snapshot represents the aggregate state after all events up to and including
30-
the given sequence number have been applied.
28+
This callback persists a snapshot of the aggregate state at a specific point in time,
29+
representing the state after applying all events up to and including the recorded
30+
sequence number. Snapshots are optimization aids; events remain the source of truth.
3131

32-
The snapshot record already contains all necessary information including domain,
33-
stream_id, sequence, timestamp, and state. This is consistent with how events
34-
are handled - they are passed as complete records rather than decomposed fields.
32+
The snapshot record contains all necessary information: domain, stream_id, sequence,
33+
timestamp, and state. This design is consistent with event persistence, where complete
34+
records are passed rather than decomposed fields.
3535

3636
- Snapshot is the complete snapshot record to persist.
3737

3838
Returns `ok` on success, or `{warning, Reason}` if persistence fails. Returning a
3939
warning is preferred over throwing an exception, as snapshot failures should not
40-
crash aggregates (events are the source of truth).
40+
crash aggregates.
4141
""".
42-
-callback save_snapshot(Snapshot) -> ok | {warning, Reason} when
42+
-callback store(Snapshot) -> ok | {warning, Reason} when
4343
Snapshot :: snapshot(),
4444
Reason :: term().
4545

4646
-doc """
47-
Retrieve the latest snapshot for a stream.
47+
Load the latest snapshot for a stream.
4848

4949
This callback retrieves the most recent snapshot for the given stream, if one exists.
50-
The snapshot can be used to restore aggregate state without replaying all events.
50+
The snapshot enables fast state reconstruction by avoiding full event replay from
51+
the beginning of the stream.
5152

5253
- StreamId is the unique identifier for the stream.
5354

5455
Returns `{ok, Snapshot}` if a snapshot exists, or `{error, not_found}` if no snapshot
5556
has been saved for this stream.
5657
""".
57-
-callback retrieve_latest_snapshot(StreamId) -> {ok, Snapshot} | {error, not_found} when
58+
-callback load_latest(StreamId) -> {ok, Snapshot} | {error, not_found} when
5859
StreamId :: stream_id(),
5960
Snapshot :: snapshot().

apps/event_sourcing_core/src/event_sourcing_core_aggregate.erl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ init({Aggregate, StoreContext, Id, Opts}) ->
130130

131131
%% Try to load the latest snapshot
132132
{StateFromSnapshot, SequenceFromSnapshot} =
133-
case event_sourcing_core_store:retrieve_latest_snapshot(StoreContext, Id) of
133+
case event_sourcing_core_store:load_latest(StoreContext, Id) of
134134
{ok, Snapshot} ->
135135
SnapshotState = event_sourcing_core_store:snapshot_state(Snapshot),
136136
SnapshotSeq = event_sourcing_core_store:snapshot_sequence(Snapshot),
@@ -150,7 +150,7 @@ init({Aggregate, StoreContext, Id, Opts}) ->
150150
}
151151
end,
152152
{State1, Sequence1} =
153-
event_sourcing_core_store:retrieve_and_fold_events(
153+
event_sourcing_core_store:fold(
154154
StoreContext,
155155
Id,
156156
#{from => SequenceFromSnapshot + 1},
@@ -354,7 +354,7 @@ persist_events(PayloadEvents, {Aggregate, StoreContext, Id, Sequence0, SequenceN
354354
end,
355355
Events
356356
),
357-
event_sourcing_core_store:persist_events(StoreContext, Id, Events).
357+
event_sourcing_core_store:append(StoreContext, Id, Events).
358358

359359
-doc """
360360
Saves a snapshot if the snapshot interval is configured and the current
@@ -379,7 +379,7 @@ maybe_save_snapshot(
379379
Timestamp = NowFun(),
380380
logger:info("Saving snapshot for ~p at sequence ~p", [Id, Sequence]),
381381
Snapshot = event_sourcing_core_store:new_snapshot(Aggregate, Id, Sequence, Timestamp, AggState),
382-
case event_sourcing_core_store:save_snapshot(StoreContext, Snapshot) of
382+
case event_sourcing_core_store:store(StoreContext, Snapshot) of
383383
ok ->
384384
ok;
385385
{warning, Reason} ->

apps/event_sourcing_core/src/event_sourcing_core_store.erl

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ Both modules may be the same if one backend implements both roles.
1717
-export([
1818
start/1,
1919
stop/1,
20-
persist_events/3,
21-
retrieve_and_fold_events/5,
20+
append/3,
21+
fold/5,
2222
retrieve_events/3,
23-
save_snapshot/2,
24-
retrieve_latest_snapshot/2,
23+
store/2,
24+
load_latest/2,
2525
new_snapshot/5,
2626
snapshot_stream_id/1,
2727
snapshot_domain/1,
@@ -82,13 +82,17 @@ stop({EventModule, SnapshotModule}) ->
8282
end.
8383

8484
-doc """
85-
Persists a list of events to the event store using the specified store module.
85+
Appends a list of events to the event store using the specified store module.
86+
87+
This is the primary mechanism for persisting domain events. All events in the list
88+
must target the same stream and have unique identifiers. The store backend ensures
89+
atomic persistence and maintains sequence ordering.
8690
""".
87-
-spec persist_events(StoreContext, StreamId, Events) -> ok when
91+
-spec append(StoreContext, StreamId, Events) -> ok when
8892
StoreContext :: store_context(),
8993
StreamId :: stream_id(),
9094
Events :: [event()].
91-
persist_events({EventModule, _}, StreamId, Events) when is_list(Events) ->
95+
append({EventModule, _}, StreamId, Events) when is_list(Events) ->
9296
%% Validate that all events target the same StreamId
9397
ok = lists:foreach(
9498
fun(Event) ->
@@ -111,12 +115,15 @@ persist_events({EventModule, _}, StreamId, Events) when is_list(Events) ->
111115
erlang:error(duplicate_event)
112116
end,
113117

114-
EventModule:persist_events(StreamId, Events).
118+
EventModule:append(StreamId, Events).
115119

116120
-doc """
117-
Retrieves and folds events from the event store using the specified persistence module.
121+
Folds events from the event store into an accumulator using the specified persistence module.
122+
123+
This is the core operation for event replay and state reconstruction. The backend
124+
retrieves events matching the given criteria and applies the fold function in sequence order.
118125
""".
119-
-spec retrieve_and_fold_events(StoreContext, StreamId, Options, Fun, Acc0) -> Acc1 when
126+
-spec fold(StoreContext, StreamId, Options, Fun, Acc0) -> Acc1 when
120127
StoreContext :: store_context(),
121128
StreamId :: stream_id(),
122129
Options :: fold_events_opts(),
@@ -125,19 +132,21 @@ Retrieves and folds events from the event store using the specified persistence
125132
Acc1 :: term(),
126133
AccIn :: term(),
127134
AccOut :: term().
128-
retrieve_and_fold_events({EventModule, _}, StreamId, Options, Fun, InitialResult) ->
129-
EventModule:retrieve_and_fold_events(StreamId, Options, Fun, InitialResult).
135+
fold({EventModule, _}, StreamId, Options, Fun, InitialResult) ->
136+
EventModule:fold(StreamId, Options, Fun, InitialResult).
130137

131138
-doc """
132139
Retrieves events for a given stream using the specified store module and options.
140+
141+
This is a convenience wrapper around fold/5 that collects all events into a list.
133142
""".
134143
-spec retrieve_events(StoreContext, StreamId, Options) -> Result when
135144
StoreContext :: store_context(),
136145
StreamId :: stream_id(),
137146
Options :: fold_events_opts(),
138147
Result :: [event()].
139148
retrieve_events(StoreContext, StreamId, Options) ->
140-
retrieve_and_fold_events(
149+
fold(
141150
StoreContext,
142151
StreamId,
143152
Options,
@@ -304,36 +313,39 @@ new_snapshot(Domain, StreamId, Sequence, Timestamp, State) ->
304313
}.
305314

306315
-doc """
307-
Saves a snapshot using the specified store module.
316+
Stores a snapshot using the specified store module.
308317

309-
This function delegates snapshot saving to the store module implementation.
310-
The snapshot captures the aggregate state at a specific point in time, allowing
311-
for faster aggregate rehydration by avoiding full event replay.
318+
This function delegates snapshot storage to the backend implementation. The snapshot
319+
captures aggregate state at a specific sequence number, enabling faster rehydration
320+
by avoiding full event replay from the stream's beginning.
312321

313322
The snapshot record contains all necessary fields (domain, stream_id, sequence,
314-
timestamp, state), making the API consistent with event persistence where events
315-
are passed as complete records.
323+
timestamp, state), consistent with event persistence where complete records are
324+
passed rather than individual fields.
316325

317-
Returns `ok` on success, or `{warning, Reason}` if persistence fails.
326+
Returns `ok` on success, or `{warning, Reason}` if persistence fails. Warnings are
327+
preferred over exceptions since snapshots are optimizations, not requirements.
318328
""".
319-
-spec save_snapshot(StoreContext, Snapshot) -> ok | {warning, Reason} when
329+
-spec store(StoreContext, Snapshot) -> ok | {warning, Reason} when
320330
StoreContext :: store_context(),
321331
Snapshot :: snapshot(),
322332
Reason :: term().
323-
save_snapshot({_, SnapshotModule}, Snapshot) ->
324-
SnapshotModule:save_snapshot(Snapshot).
333+
store({_, SnapshotModule}, Snapshot) ->
334+
SnapshotModule:store(Snapshot).
325335

326336
-doc """
327-
Retrieves the latest snapshot for a stream using the specified store module.
337+
Loads the latest snapshot for a stream using the specified store module.
328338

329-
Returns `{ok, Snapshot}` if found, `{error, not_found}` otherwise.
339+
Returns `{ok, Snapshot}` if found, `{error, not_found}` otherwise. This enables
340+
fast aggregate rehydration by restoring state from the snapshot and replaying only
341+
events that occurred after the snapshot's sequence number.
330342
""".
331-
-spec retrieve_latest_snapshot(StoreContext, StreamId) -> {ok, Snapshot} | {error, not_found} when
343+
-spec load_latest(StoreContext, StreamId) -> {ok, Snapshot} | {error, not_found} when
332344
StoreContext :: store_context(),
333345
StreamId :: stream_id(),
334346
Snapshot :: snapshot().
335-
retrieve_latest_snapshot({_, SnapshotModule}, StreamId) ->
336-
SnapshotModule:retrieve_latest_snapshot(StreamId).
347+
load_latest({_, SnapshotModule}, StreamId) ->
348+
SnapshotModule:load_latest(StreamId).
337349

338350
-doc """
339351
Returns the stream identifier of the snapshot.

apps/event_sourcing_core/test/event_sourcing_core_aggregate_tests.erl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ aggregate_snapshot_creation() ->
116116
?assertState(Pid, Id, #{balance := 125}, 3),
117117

118118
%% Snapshot should be saved at sequence 3 (3 % 3 == 0)
119-
{ok, Snapshot} = event_sourcing_core_store:retrieve_latest_snapshot(
119+
{ok, Snapshot} = event_sourcing_core_store:load_latest(
120120
?ETS_STORE_CONTEXT,
121121
Id
122122
),
@@ -130,7 +130,7 @@ aggregate_snapshot_creation() ->
130130
?assertState(Pid, Id, #{balance := 250}, 6),
131131

132132
%% Snapshot should now be at sequence 6 (6 % 3 == 0)
133-
{ok, Snapshot2} = event_sourcing_core_store:retrieve_latest_snapshot(
133+
{ok, Snapshot2} = event_sourcing_core_store:load_latest(
134134
?ETS_STORE_CONTEXT,
135135
Id
136136
),
@@ -156,7 +156,7 @@ aggregate_snapshot_rehydration() ->
156156
?assertState(Pid1, Id, #{balance := 300}, 2),
157157

158158
%% Snapshot should exist at sequence 2
159-
{ok, _Snapshot} = event_sourcing_core_store:retrieve_latest_snapshot(
159+
{ok, _Snapshot} = event_sourcing_core_store:load_latest(
160160
?ETS_STORE_CONTEXT,
161161
Id
162162
),

apps/event_sourcing_core/test/event_sourcing_core_store_snapshot_stub.erl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
-include_lib("event_sourcing_contract/include/event_sourcing.hrl").
44

5-
-export([start/0, stop/0, save_snapshot/1, retrieve_latest_snapshot/1]).
5+
-export([start/0, stop/0, store/1, load_latest/1]).
66

77
-define(TABLE, ?MODULE).
88

@@ -26,14 +26,14 @@ stop() ->
2626
ok
2727
end.
2828

29-
-spec save_snapshot(snapshot()) -> ok.
30-
save_snapshot(Snapshot) ->
29+
-spec store(snapshot()) -> ok.
30+
store(Snapshot) ->
3131
StreamId = event_sourcing_core_store:snapshot_stream_id(Snapshot),
3232
ets:insert(?TABLE, {StreamId, Snapshot}),
3333
ok.
3434

35-
-spec retrieve_latest_snapshot(stream_id()) -> {ok, snapshot()} | {error, not_found}.
36-
retrieve_latest_snapshot(StreamId) ->
35+
-spec load_latest(stream_id()) -> {ok, snapshot()} | {error, not_found}.
36+
load_latest(StreamId) ->
3737
case ets:lookup(?TABLE, StreamId) of
3838
[{_, Snapshot}] ->
3939
{ok, Snapshot};

0 commit comments

Comments
 (0)