packages feed

cqrs 0.6.0 → 0.7.0

raw patch · 8 files changed

+69/−39 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.CQRS.EventStore.Backend: type RawEvent = PersistedEvent ByteString
+ Data.CQRS.GUID: fromByteString :: ByteString -> GUID
+ Data.CQRS.GUID: toByteString :: GUID -> ByteString
+ Data.CQRS.PersistedEvent: PersistedEvent :: !GUID -> e -> !Int -> !Int -> PersistedEvent e
+ Data.CQRS.PersistedEvent: data PersistedEvent e
+ Data.CQRS.PersistedEvent: peAggregateGUID :: PersistedEvent e -> !GUID
+ Data.CQRS.PersistedEvent: peEvent :: PersistedEvent e -> e
+ Data.CQRS.PersistedEvent: peGlobalVer :: PersistedEvent e -> !Int
+ Data.CQRS.PersistedEvent: peSequenceNumber :: PersistedEvent e -> !Int
- Data.CQRS.EventStore: enumerateEventStore :: Serialize e => EventStore e -> Int -> Enumerator (Int, (GUID, Int, e)) IO a
+ Data.CQRS.EventStore: enumerateEventStore :: Serialize e => EventStore e -> Int -> Enumerator (PersistedEvent e) IO a
- Data.CQRS.EventStore.Backend: EventStoreBackend :: (GUID -> Int -> [(ByteString, Int)] -> IO ()) -> (GUID -> Int -> IO (Int, [ByteString])) -> (forall a. Int -> Enumerator (Int, (GUID, Int, ByteString)) IO a) -> (GUID -> (Int, ByteString) -> IO ()) -> (GUID -> IO (Maybe (Int, ByteString))) -> IO Int -> (forall a. IO a -> IO a) -> IO () -> EventStoreBackend
+ Data.CQRS.EventStore.Backend: EventStoreBackend :: (GUID -> Int -> [RawEvent] -> IO ()) -> (GUID -> Int -> IO [RawEvent]) -> (forall a. Int -> Enumerator RawEvent IO a) -> (GUID -> (Int, ByteString) -> IO ()) -> (GUID -> IO (Maybe (Int, ByteString))) -> IO Int -> (forall a. IO a -> IO a) -> IO () -> EventStoreBackend
- Data.CQRS.EventStore.Backend: esbEnumerateAllEvents :: EventStoreBackend -> forall a. Int -> Enumerator (Int, (GUID, Int, ByteString)) IO a
+ Data.CQRS.EventStore.Backend: esbEnumerateAllEvents :: EventStoreBackend -> forall a. Int -> Enumerator RawEvent IO a
- Data.CQRS.EventStore.Backend: esbRetrieveEvents :: EventStoreBackend -> GUID -> Int -> IO (Int, [ByteString])
+ Data.CQRS.EventStore.Backend: esbRetrieveEvents :: EventStoreBackend -> GUID -> Int -> IO [RawEvent]
- Data.CQRS.EventStore.Backend: esbStoreEvents :: EventStoreBackend -> GUID -> Int -> [(ByteString, Int)] -> IO ()
+ Data.CQRS.EventStore.Backend: esbStoreEvents :: EventStoreBackend -> GUID -> Int -> [RawEvent] -> IO ()

Files

cqrs.cabal view
@@ -1,5 +1,5 @@ Name:                cqrs-Version:             0.6.0+Version:             0.7.0 Synopsis:            Command-Query Responsibility Segregation Description:         Haskell implementation of the CQRS architectural pattern. License:             MIT@@ -16,8 +16,8 @@                , bytestring >= 0.9.0.1                , cereal >= 0.3.3 && < 0.4                , containers >= 0.4-               , enumerator >= 0.4.15 && < 0.5                , data-default >= 0.3 && < 0.4+               , enumerator >= 0.4.15 && < 0.5                , random >= 1.0 && < 1.1                , transformers >= 0.2.2 && < 0.3   Extensions:          DeriveDataTypeable@@ -37,7 +37,9 @@                        Data.CQRS.EventStore                        Data.CQRS.EventStore.Backend                        Data.CQRS.GUID+                       Data.CQRS.PersistedEvent                        Data.CQRS.Serialize                        Data.CQRS.Transaction   Other-modules:       Data.CQRS.Internal.AggregateRef                        Data.CQRS.Internal.EventStore+                       Data.CQRS.Internal.PersistedEvent
src/Data/CQRS/EventStore/Backend.hs view
@@ -3,12 +3,18 @@ -- event store backend. module Data.CQRS.EventStore.Backend        ( EventStoreBackend(..)+       , RawEvent        ) where  import Data.ByteString (ByteString) import Data.CQRS.GUID+import Data.CQRS.PersistedEvent (PersistedEvent) import Data.Enumerator (Enumerator) +-- | Raw event type. The data associated with an event is not+-- translated in any way.+type RawEvent = PersistedEvent ByteString+ -- | Event stores are the backend used for reading and storing all the -- information about recorded events. data EventStoreBackend =@@ -17,15 +23,14 @@     -- into the event store, starting at the provided version number.     -- If the version number does not match the expected value, a     -- failure occurs.-    esbStoreEvents :: GUID -> Int -> [(ByteString,Int)] -> IO (),+    esbStoreEvents :: GUID -> Int -> [RawEvent] -> IO (),     -- | Retrieve the sequence of events associated with the aggregate     -- identified by the given GUID. Only events at or after the given     -- version number are retrieved. The events are returned in-    -- increasing order of version number. The version number of the-    -- last event is returned as well.-    esbRetrieveEvents :: GUID -> Int -> IO (Int,[ByteString]),+    -- increasing order of version number.+    esbRetrieveEvents :: GUID -> Int -> IO [RawEvent],     -- | Enumerate all events later than given logical timestamp.-    esbEnumerateAllEvents :: forall a. Int -> Enumerator (Int, (GUID, Int, ByteString)) IO a,+    esbEnumerateAllEvents :: forall a. Int -> Enumerator RawEvent IO a,     -- | Write snapshot for aggregate identified by GUID and     -- the given version number. The version number is NOT checked     -- for validity. If the event store does not support snapshots
src/Data/CQRS/GUID.hs view
@@ -1,9 +1,11 @@ -- | Globally Unique IDentifiers. module Data.CQRS.GUID        ( GUID+       , fromByteString        , hexDecode        , hexEncode        , newGUID+       , toByteString        ) where  import           Control.Monad (liftM)@@ -37,8 +39,8 @@  -- | Serialize instance. instance Serialize GUID where-    put (GUID s) = put s-    get = liftM GUID get+    put = put . toByteString+    get = liftM fromByteString get  -- | Hex encode a GUID. hexEncode :: GUID -> ByteString@@ -50,3 +52,11 @@   case B16.decode s of     (a,b) | B.length b == 0 -> Just $ GUID a     _                       -> Nothing++-- | Convert from ByteString.+fromByteString :: ByteString -> GUID+fromByteString = GUID++-- | Convert to ByteString.+toByteString :: GUID -> ByteString+toByteString (GUID g) = g
src/Data/CQRS/Internal/AggregateRef.hs view
@@ -12,8 +12,9 @@  import           Control.Monad (liftM) import           Control.Monad.IO.Class (MonadIO, liftIO)-import           Data.CQRS.GUID (GUID) import           Data.CQRS.Eventable (Eventable(..))+import           Data.CQRS.GUID (GUID)+import           Data.CQRS.PersistedEvent (PersistedEvent(..)) import           Data.Foldable (toList) import           Data.IORef (IORef, modifyIORef, newIORef, readIORef) import           Data.Sequence (Seq, (|>))@@ -23,7 +24,7 @@ -- | Aggregate root reference. data AggregateRef a e =   AggregateRef { arValue :: IORef a-               , arEvents :: IORef (Seq (e, Int))+               , arEvents :: IORef (Seq (PersistedEvent e))                , arGUID :: GUID                , arStartVersion :: Int                , arSnapshotVersion :: Int@@ -43,10 +44,11 @@   -- Apply event to aggregate state.   modifyIORef (arValue aggregateRef) $ applyEvent event   -- Add event to aggregate.-  modifyIORef (arEvents aggregateRef) $ \events -> events |> (event,gv)+  modifyIORef (arEvents aggregateRef) $ \events ->+    events |> (PersistedEvent (arGUID aggregateRef) event (arStartVersion aggregateRef + 1 + S.length events) gv)  -- | Read aggregate events.-readEvents :: (MonadIO m) => AggregateRef a e -> m [(e,Int)]+readEvents :: (MonadIO m) => AggregateRef a e -> m [PersistedEvent e] readEvents = liftM toList . liftIO . readIORef . arEvents  -- | Read aggregate state.
src/Data/CQRS/Internal/EventStore.hs view
@@ -1,7 +1,6 @@ -- | Event store functions. module Data.CQRS.Internal.EventStore        ( EventStore-       , enumerateAllEvents        , enumerateEventStore        , getLatestSnapshot        , getLatestVersion@@ -17,21 +16,12 @@ import           Data.ByteString (ByteString) import           Data.CQRS.EventStore.Backend (EventStoreBackend(..)) import           Data.CQRS.GUID+import           Data.CQRS.Internal.PersistedEvent (PersistedEvent(..), mapPersistedEvent) import           Data.CQRS.Serialize (decode') import           Data.Enumerator (Enumerator, ($=)) import qualified Data.Enumerator.List as EL import           Data.Serialize (Serialize, encode) --- Utilities.-map1st :: (a -> c) -> (a, b) -> (c, b)-map1st f (a,b) = (f a, b)--map2nd :: (b -> c) -> (a,b) -> (a,c)-map2nd f (a,b) = (a, f b)--map3rd :: (c -> d) -> (a,b,c) -> (a,b,d)-map3rd f (a,b,c) = (a,b,f c)- -- Provide a type alias. data EventStore e = EventStore { esBackend :: EventStoreBackend                                }@@ -42,22 +32,18 @@  -- | Enumerate all the events from an event store that occur at or later -- than a given logical timestamp.-enumerateEventStore :: forall a e . (Serialize e) => EventStore e -> Int -> Enumerator (Int, (GUID, Int, e)) IO a+enumerateEventStore :: forall a e . (Serialize e) => EventStore e -> Int -> Enumerator (PersistedEvent e) IO a enumerateEventStore es minVersion =-  esbEnumerateAllEvents (esBackend es) minVersion $= EL.map (\(gv,(g,ev,ed)) -> (gv,(g,ev,decode' ed :: e)))+  esbEnumerateAllEvents (esBackend es) minVersion $= EL.map (mapPersistedEvent decode')  withTransaction :: EventStore e -> IO a -> IO a withTransaction (EventStore esb) = esbWithTransaction esb -storeEvents :: Serialize e => EventStore e -> GUID -> Int -> [(e,Int)] -> IO ()-storeEvents (EventStore esb) guid v0 evs = esbStoreEvents esb guid v0 (map (map1st encode) evs)--retrieveEvents :: Serialize e => EventStore e -> GUID -> Int -> IO (Int,[e])-retrieveEvents (EventStore esb) guid v0 = liftM (map2nd $ map decode') $ esbRetrieveEvents esb guid v0+storeEvents :: Serialize e => EventStore e -> GUID -> Int -> [PersistedEvent e] -> IO ()+storeEvents (EventStore esb) guid v0 evs = esbStoreEvents esb guid v0 $ (map $ mapPersistedEvent encode) evs -enumerateAllEvents :: forall a e. Serialize e => EventStore e -> Int -> Enumerator (Int, (GUID, Int, e)) IO a-enumerateAllEvents (EventStore esb) v0 =-  esbEnumerateAllEvents esb v0 $= EL.map (map2nd $ map3rd decode')+retrieveEvents :: Serialize e => EventStore e -> GUID -> Int -> IO [PersistedEvent e]+retrieveEvents (EventStore esb) guid v0 = liftM (map $ mapPersistedEvent decode') $ esbRetrieveEvents esb guid v0  writeSnapshot ::   EventStore e -> GUID -> (Int, ByteString) -> IO () writeSnapshot (EventStore esb) = esbWriteSnapshot esb
+ src/Data/CQRS/Internal/PersistedEvent.hs view
@@ -0,0 +1,18 @@+module Data.CQRS.Internal.PersistedEvent+       ( PersistedEvent(..)+       , mapPersistedEvent+       ) where++import Data.CQRS.GUID (GUID)++-- | Persisted Event.+data PersistedEvent e =+  PersistedEvent { peAggregateGUID :: !GUID -- ^ GUID of the aggregate.+                 , peEvent :: e             -- ^ Event.+                 , peSequenceNumber :: !Int -- ^ Sequence number within the aggregate.+                 , peGlobalVer :: !Int      -- ^ Global sequence number.+                 }++-- Transform the event data.+mapPersistedEvent :: (e -> e') -> PersistedEvent e -> PersistedEvent e'+mapPersistedEvent f (PersistedEvent g e v gv) = PersistedEvent g (f e) v gv
+ src/Data/CQRS/PersistedEvent.hs view
@@ -0,0 +1,5 @@+module Data.CQRS.PersistedEvent+       ( PersistedEvent(..)+       ) where++import Data.CQRS.Internal.PersistedEvent
src/Data/CQRS/Transaction.hs view
@@ -11,12 +11,13 @@ import           Control.Monad.Trans.Class (MonadTrans(..), lift) import           Control.Monad.Trans.State (StateT, get, gets, modify, runStateT) import           Data.CQRS.Aggregate (Aggregate(..))-import           Data.CQRS.Internal.AggregateRef (AggregateRef, mkAggregateRef)-import qualified Data.CQRS.Internal.AggregateRef as AR import           Data.CQRS.Eventable (Eventable(..)) import           Data.CQRS.EventStore (EventStore)-import qualified Data.CQRS.Internal.EventStore as ES import           Data.CQRS.GUID (GUID)+import           Data.CQRS.Internal.AggregateRef (AggregateRef, mkAggregateRef)+import qualified Data.CQRS.Internal.AggregateRef as AR+import qualified Data.CQRS.Internal.EventStore as ES+import           Data.CQRS.PersistedEvent (PersistedEvent(..)) import           Data.Default (Default(..)) import           Data.List (find) import           Data.Serialize (Serialize)@@ -102,9 +103,10 @@   -- Get latest snapshot (if any).   (v0,a0) <- getLatestSnapshot guid   -- Get events.-  (latestVersion, events) <- lift $ ES.retrieveEvents es guid v0+  events <- lift $ ES.retrieveEvents es guid v0+  let latestVersion = maximum $ (:) v0 (map peSequenceNumber events)   -- Build the aggregate state from all the events.-  let a = foldr applyEvent a0 events+  let a = foldr (applyEvent . peEvent) a0 events   -- Make the aggregate itself   (a' :: AggregateRef a e) <- lift $ mkAggregateRef a guid latestVersion v0   -- Add to set of aggregates to commit later.