module Persistent.Event.Source
  ( handleCmdWithAuthor
  , applyEventsSince
  , module X
  )
where

import Persistent.Event.Source.Projection as X
import Persistent.Event.Source.Aggregate as X
import Persistent.Event.Source.EventStore as X
import Database.Persist.Monad(MonadSqlQuery)
import Database.Persist.Class.PersistEntity
import Control.Monad.IO.Unlift
import Control.Monad.Logger
import Data.Foldable

-- TODO: handle potential concurrency problems, catch errors from invalid commands
-- | Executes command and applies events, as well as storing them, aka `transact` or `actAndApply`
handleCmdWithAuthor :: ( Aggregate a, EventStore a, MonadUnliftIO m, MonadSqlQuery m, MonadLogger m) =>
  Maybe (Actor a) -> Command a -> m [Entity (Event a)]
handleCmdWithAuthor :: forall a (m :: * -> *).
(Aggregate a, EventStore a, MonadUnliftIO m, MonadSqlQuery m,
 MonadLogger m) =>
Maybe (Actor a) -> Command a -> m [Entity (Event a)]
handleCmdWithAuthor Maybe (Actor a)
mAuthorId Command a
cmd = do
  [Event a]
events <- Maybe (Actor a) -> Command a -> m [Event a]
forall a (m :: * -> *).
(Aggregate a, MonadSqlQuery m, MonadIO m) =>
Maybe (Actor a) -> Command a -> m [Event a]
act Maybe (Actor a)
mAuthorId Command a
cmd
  (Event a -> m ()) -> [Event a] -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ Event a -> m ()
forall a (m :: * -> *).
(Projection a, MonadUnliftIO m, MonadLogger m, MonadSqlQuery m) =>
Event a -> m ()
apply [Event a]
events
  [Key (Event a)]
eventIds <- [Event a] -> m [Key (Event a)]
forall a (m :: * -> *).
(EventStore a, MonadIO m, MonadSqlQuery m) =>
[Event a] -> m [Key (Event a)]
storeMany [Event a]
events
  [Key (Event a)] -> m ()
forall a (m :: * -> *).
(EventStore a, MonadIO m, MonadSqlQuery m) =>
[Key (Event a)] -> m ()
markEventsApplied [Key (Event a)]
eventIds
  [Entity (Event a)] -> m [Entity (Event a)]
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Entity (Event a)] -> m [Entity (Event a)])
-> [Entity (Event a)] -> m [Entity (Event a)]
forall a b. (a -> b) -> a -> b
$ (Key (Event a) -> Event a -> Entity (Event a))
-> [Key (Event a)] -> [Event a] -> [Entity (Event a)]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Key (Event a) -> Event a -> Entity (Event a)
forall record. Key record -> record -> Entity record
Entity [Key (Event a)]
eventIds [Event a]
events

applyEventsSince :: (EventStore a, MonadUnliftIO m, MonadSqlQuery m, MonadLogger m) => Maybe (Key (Event a)) -> m ()
applyEventsSince :: forall a (m :: * -> *).
(EventStore a, MonadUnliftIO m, MonadSqlQuery m, MonadLogger m) =>
Maybe (Key (Event a)) -> m ()
applyEventsSince Maybe (Key (Event a))
lastEventId = do
  [Entity (Event a)]
events <- Maybe (Key (Event a)) -> m [Entity (Event a)]
forall a (m :: * -> *).
(EventStore a, MonadIO m, MonadSqlQuery m) =>
Maybe (Key (Event a)) -> m [Entity (Event a)]
loadUnappliedEvents Maybe (Key (Event a))
lastEventId
  (Entity (Event a) -> m ()) -> [Entity (Event a)] -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (Event a -> m ()
forall a (m :: * -> *).
(Projection a, MonadUnliftIO m, MonadLogger m, MonadSqlQuery m) =>
Event a -> m ()
apply (Event a -> m ())
-> (Entity (Event a) -> Event a) -> Entity (Event a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Entity (Event a) -> Event a
forall record. Entity record -> record
entityVal) [Entity (Event a)]
events
  [Key (Event a)] -> m ()
forall a (m :: * -> *).
(EventStore a, MonadIO m, MonadSqlQuery m) =>
[Key (Event a)] -> m ()
markEventsApplied ([Key (Event a)] -> m ()) -> [Key (Event a)] -> m ()
forall a b. (a -> b) -> a -> b
$ Entity (Event a) -> Key (Event a)
forall record. Entity record -> Key record
entityKey (Entity (Event a) -> Key (Event a))
-> [Entity (Event a)] -> [Key (Event a)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Entity (Event a)]
events