Abaks: Use Cases
After introducing Commands as our Entites/Core Domain, we then have to introduce next layer: Use Cases.
For reference, it is the place where application-specific wiring.
They aim to be really simple, most of them will just wrap Event sourcing mechanics:
addEntry periodId entry =
  runCommand (Entities.addEntry entry) periodId.getPeriodId $
    return . bimap (.getExplainedError) (const ())
While some of them will inject some value (or connect various sources):
createPeriod name from to balance = do
  periodId <- Entities.PeriodId . AggregateId . UUID.toText <$> embedFinal UUID.nextRandom
  runCommand (Entities.startPeriod periodId name from to balance) periodId.getPeriodId $
    return . bimap (.getExplainedError) (const periodId)
In the meantime, we have created a supporting function:
runCommand handler aggregateId f =
  withEvents aggregateId $ \initialEvents ->
    let result = applyCommand handler initialEvents
     in (,) (either mempty id result) <$> f result
And a dedicated effect:
data EventSourceEffect (eventType :: Type) (m :: Type -> Type) (a :: Type) where
  WithEvents :: AggregateId -> (Events eventType -> m (Events eventType, a)) -> EventSourceEffect eventType m a
We also provide two implementations:
- A pure in-memory, State-based
- A file-based, backed by a MVar, relying onAeson(which obviously won't scale, or even be maintainable, but good enough for the moment)
All based on a simple type: Map.Map AggregateId (Events eventType)