packages feed

cqrs-types (empty) → 0.9.0

raw patch · 9 files changed

+253/−0 lines, 9 filesdep +basedep +base16-bytestringdep +base64-bytestringsetup-changed

Dependencies added: base, base16-bytestring, base64-bytestring, bytestring, conduit, deepseq, derive, random

Files

+ LICENSE view
@@ -0,0 +1,19 @@+Copyright (c) 2012 Bardur Arantsson++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.lhs view
@@ -0,0 +1,4 @@+#! /usr/bin/env runhaskell++> import Distribution.Simple+> main = defaultMain
+ cqrs-types.cabal view
@@ -0,0 +1,37 @@+Name:                cqrs-types+Version:             0.9.0+Synopsis:            Command-Query Responsibility Segregation. Modules for the basic types.+Description:         Haskell implementation of the CQRS architectural pattern.+License:             MIT+License-file:        LICENSE+Category:            Data+Cabal-version:       >=1.10+Build-type:          Simple+Author:              Bardur Arantsson+Maintainer:          Bardur Arantsson <bardur@scientician.net>++Library+  Build-Depends:       base == 4.*+                     , base16-bytestring >= 0.1.1.3 && < 0.2+                     , base64-bytestring >= 1 && < 2+                     , bytestring >= 0.9.0.1+                     , conduit >= 1.0 && < 2+                     , deepseq >= 1.3 && < 2+                     , derive >= 2.5.11 && < 2.6+                     , random >= 1.0 && < 1.1+  Default-language:    Haskell2010+  Default-Extensions:+                       DeriveDataTypeable+                       DeriveFunctor+                       FunctionalDependencies+                       MultiParamTypeClasses+                       Rank2Types+                       TemplateHaskell+  ghc-options:         -Wall+  hs-source-dirs:      src+  Exposed-modules:     Data.CQRS.Aggregate+                       Data.CQRS.Eventable+                       Data.CQRS.EventStore.Backend+                       Data.CQRS.GUID+                       Data.CQRS.PersistedEvent+                       Data.CQRS.Serializable
+ src/Data/CQRS/Aggregate.hs view
@@ -0,0 +1,10 @@+-- | Aggregate type class.+module Data.CQRS.Aggregate+       ( Aggregate+       ) where++import Data.CQRS.Serializable++-- | Type class for aggregates.+class Serializable a => Aggregate a where+    -- No functions at the current time.
+ src/Data/CQRS/EventStore/Backend.hs view
@@ -0,0 +1,56 @@+-- | Event store backend. You only need to import this+-- module if you're planning on implementing a custom+-- event store backend.+module Data.CQRS.EventStore.Backend+       ( EventStoreBackend(..)+       , RawEvent+       , RawSnapshot(..)+       ) where++import Data.ByteString (ByteString)+import Data.Conduit (ResourceT, Source)+import Data.CQRS.GUID+import Data.CQRS.PersistedEvent (PersistedEvent)++-- | Raw event type. The data associated with an event is not+-- translated in any way.+type RawEvent = PersistedEvent ByteString++-- | Raw snapshot.+data RawSnapshot =+  RawSnapshot { rsVersion :: Int+              , rsSnapshotData :: ByteString+              }+  deriving (Eq,Ord,Show)++-- | Event stores are the backend used for reading and storing all the+-- information about recorded events.+class EventStoreBackend esb where+    -- | Store a sequence of events for aggregate identified by GUID+    -- into the event store, starting at the provided version number.+    -- If the version number does not match the expected value, a+    -- failure occurs.+    esbStoreEvents :: esb -> 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.+    esbRetrieveEvents :: esb -> GUID -> Int -> Source (ResourceT IO) RawEvent+    -- | Enumerate all events. There is no guarantee on the ordering+    -- of events /except/ that events for any specific aggregate root+    -- are returned in order of version number.+    esbEnumerateAllEvents :: esb -> Source (ResourceT IO) RawEvent+    -- | 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+    -- this function may do nothing.+    esbWriteSnapshot :: esb -> GUID -> RawSnapshot -> IO ()+    -- | Get latest snapshot of an aggregate identified by GUID.+    -- Returns the version number of the snapshot in addition to the+    -- data. An event store which does not support snapshots is+    -- permitted to return 'Nothing' in all cases.+    esbGetLatestSnapshot :: esb -> GUID -> IO (Maybe RawSnapshot)+    -- | Run transaction against the event store. The transaction is+    -- expected to commit if the supplied IO action runs to completion+    -- (i.e. doesn't throw an exception) and to rollback otherwise.+    esbWithTransaction :: forall a . esb -> IO a -> IO a
+ src/Data/CQRS/Eventable.hs view
@@ -0,0 +1,9 @@+-- | Eventable type class.+module Data.CQRS.Eventable+       ( Eventable(..)+       ) where++-- | Type class for applying events to aggregates.+class Eventable a e | a -> e where+  -- | Apply an event to the aggregate and return the updated aggregate.+  applyEvent :: Maybe a -> e -> Maybe a
+ src/Data/CQRS/GUID.hs view
@@ -0,0 +1,81 @@+-- | Globally Unique IDentifiers.+module Data.CQRS.GUID+       ( GUID+       , fromByteString+       , base64Decode+       , base64Encode+       , hexDecode+       , hexEncode+       , newGUID+       , toByteString+       ) where++import           Control.DeepSeq (NFData(..))+import           Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Base16 as B16+import qualified Data.ByteString.Base64 as B64+import           Data.ByteString.Char8 ()+import           Data.Data (Data)+import           Data.DeriveTH (derive, makeNFData)+import           Data.Typeable (Typeable)+import           Data.Word (Word8)+import           System.Random (randomRIO)++import           Data.CQRS.Serializable++-- | A Globally Unique IDentifier.+newtype GUID = GUID ByteString+              deriving (Typeable, Eq, Ord, Data)++-- | Get a random byte.+randomWord8 :: IO Word8+randomWord8 = fmap fromInteger $ randomRIO (0,255)++-- | Create a new random GUID.+newGUID :: IO GUID+newGUID = do+  uuid <- sequence $ replicate 16 randomWord8+  return $ GUID $ B.pack uuid++-- | Serialize instance.+instance Serializable GUID where+    serialize = toByteString+    deserialize = Just . GUID++-- | Hex encode a GUID.+hexEncode :: GUID -> ByteString+hexEncode (GUID s) = B16.encode s++-- | Base64 encode a GUID.+base64Encode :: GUID -> ByteString+base64Encode (GUID s) = B64.encode s++-- | Showing a GUID.+instance Show GUID where+    show = show . base64Encode++-- | Decode a GUID from hex representation.+hexDecode :: ByteString -> Maybe GUID+hexDecode s =+  case B16.decode s of+    (a,b) | B.length b == 0 -> Just $ GUID a+    _                       -> Nothing++-- | Decode a GUID from base64 representation.+base64Decode :: ByteString -> Maybe GUID+base64Decode s =+  case B64.decode s of+    Right a -> Just $ GUID a+    Left _  -> Nothing++-- | Convert from ByteString.+fromByteString :: ByteString -> GUID+fromByteString = GUID++-- | Convert to ByteString.+toByteString :: GUID -> ByteString+toByteString (GUID g) = g++-- Instances+$(derive makeNFData ''GUID)
+ src/Data/CQRS/PersistedEvent.hs view
@@ -0,0 +1,17 @@+module Data.CQRS.PersistedEvent+       ( PersistedEvent(..)+       ) where++import Control.DeepSeq (NFData(..))+import Data.CQRS.GUID (GUID)+import Data.DeriveTH (derive, makeNFData)++-- | Persisted Event.+data PersistedEvent e =+  PersistedEvent { peAggregateGUID :: !GUID -- ^ GUID of the aggregate.+                 , peEvent :: !e            -- ^ Event.+                 , peSequenceNumber :: !Int -- ^ Sequence number within the aggregate.+                 }+  deriving (Show, Eq, Ord, Functor)++$(derive makeNFData ''PersistedEvent)
+ src/Data/CQRS/Serializable.hs view
@@ -0,0 +1,20 @@+-- | Serialization support. This is mainly used for compatibility+-- with whatever serialization library you want to use.++module Data.CQRS.Serializable+    ( Serializable(..)+    ) where++import Data.ByteString (ByteString)++-- | Serialization support for values of type 'a'.+class Serializable a where+    -- | Serialize a value. The serialized representation+    -- should contain some metadata (a UUID for example)+    -- which can be used to check reliably whether the encoded+    -- representation is semantically valid upon decoding.+    serialize :: a -> ByteString+    -- | De-serialize a value from a byte string. Should return+    -- 'Nothing' if decoding is not possible due to a now-invalid+    -- representation.+    deserialize :: ByteString -> Maybe a