-
-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathCore.hs
More file actions
82 lines (72 loc) · 2.69 KB
/
Copy pathCore.hs
File metadata and controls
82 lines (72 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
module Service.EntityFetcher.Core (
EntityFetcher (..),
Error (..),
new,
) where
import Core
import Service.Event (EntityName, Event (..), StreamId)
import Service.EventStore.Core (EventStore)
import Service.EventStore.Core qualified as EventStore
import Stream qualified
import Task qualified
-- | Errors that can occur during entity operations
data Error
= EventStoreError EventStore.Error
| ReductionError Text
deriving (Eq, Show)
-- | An entity fetcher is responsible for fetching an entity's current state
-- by reading all events from the event store and applying a reduction function.
--
-- The fetcher takes an initial state and a reduce function that applies events
-- to update the state.
data EntityFetcher state event = EntityFetcher
{ -- | Fetch an entity's current state by entity name and stream ID.
-- Reads all events from the event store and applies the reduction function
-- to compute the current state.
fetch :: EntityName -> StreamId -> Task Error state
}
-- | Create a new entity fetcher with the given event store, initial state, and reduce function.
--
-- The reduce function takes an event and the current state, and returns the new state
-- after applying the event.
--
-- Example:
--
-- @
-- fetcher <- EntityFetcher.new eventStore initialState applyEvent
-- state <- fetcher.fetch entityName streamId
-- @
new ::
forall state event.
EventStore event ->
state ->
(event -> state -> state) ->
Task Error (EntityFetcher state event)
new eventStore initialState reduceFunction = do
let fetchImpl entityName streamId = do
-- Read all events for this entity stream
streamMessages <-
eventStore.readAllStreamEvents entityName streamId
|> Task.mapError EventStoreError
-- Consume the stream, applying the reduction function to each event
-- This processes events one-by-one without loading everything into memory
finalState <-
streamMessages
|> Stream.consume
( \state message -> do
case message of
-- Only process actual events, ignore other message types
EventStore.StreamEvent event -> do
let eventData = event.event
let newState = reduceFunction eventData state
Task.yield newState
-- For all other message types, keep state unchanged
_ -> Task.yield state
)
initialState
|> Task.mapError (\errorText -> EventStoreError (EventStore.StorageFailure errorText))
Task.yield finalState
Task.yield
EntityFetcher
{ fetch = fetchImpl
}