-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Provides an eventsourcing high level API. -- -- A high-level eventsourcing library. @package eventsource-api @version 1.3.1 module EventSource.Types -- | Opaque data type used to store raw data. data Data Data :: ByteString -> Data DataAsJson :: Value -> Data -- | Sometimes, having to implement a FromJSON instance isn't -- flexible enough. JsonParsing allow to pass parameters when -- parsing from a JSON value while remaining composable. newtype JsonParsing a JsonParsing :: (Value -> Parser a) -> JsonParsing a -- | Returns Data content as a ByteString. dataAsBytes :: Data -> ByteString -- | Creates a Data object from a raw ByteString. dataFromBytes :: ByteString -> Data -- | Creates a Data object from a JSON object. dataFromJson :: ToJSON a => a -> Data -- | Returns Data content as any value that implements -- FromJSON type-class. dataAsJson :: FromJSON a => Data -> Either Text a -- | Uses a JsonParsing comuputation to extract a value. dataAsParsing :: Data -> JsonParsing a -> Either Text a -- | Like dataAsParsing but doesn't require you to use -- JsonParsing. dataAsParse :: Data -> (Value -> Parser a) -> Either Text a -- | Used to store a set a properties. One example is to be used as -- Event metadata. newtype Properties Properties :: (Map Text Text) -> Properties -- | Retrieves a value associated with the given key. property :: MonadPlus m => Text -> Properties -> m Text -- | Builds a Properties with a single pair of key-value. singleton :: Text -> Text -> Properties -- | Adds a pair of key-value into given Properties. setProperty :: Text -> Text -> Properties -> Properties -- | Returns all associated key-value pairs as a list. properties :: Properties -> [(Text, Text)] -- | Used to identify an event. newtype EventId EventId :: UUID -> EventId -- | Generates a fresh EventId. freshEventId :: MonadBase IO m => m EventId -- | Represents a stream name. newtype StreamName StreamName :: Text -> StreamName -- | Used to identity the type of an Event. newtype EventType EventType :: Text -> EventType -- | Sets EventType for an Event. setEventType :: EventType -> State Event () -- | Sets Eventid for an Event. setEventId :: EventId -> State Event () -- | Sets a payload for an Event. setEventPayload :: Data -> State Event () -- | Sets metadata for an Event. setEventMetadata :: Properties -> State Event () -- | Encapsulates an event which is about to be saved. data Event Event :: EventType -> EventId -> Data -> Maybe Properties -> Event [eventType] :: Event -> EventType [eventId] :: Event -> EventId [eventPayload] :: Event -> Data [eventMetadata] :: Event -> Maybe Properties -- | Represents an event index in a stream. newtype EventNumber EventNumber :: Int64 -> EventNumber -- | Represents an event that's saved into the event store. data SavedEvent SavedEvent :: EventNumber -> Event -> Maybe Event -> SavedEvent [eventNumber] :: SavedEvent -> EventNumber [savedEvent] :: SavedEvent -> Event [linkEvent] :: SavedEvent -> Maybe Event -- | Deserializes a SavedEvent. savedEventAs :: DecodeEvent a => SavedEvent -> Either Text a -- | Represents batch of events read from a store. data Slice Slice :: [SavedEvent] -> Bool -> EventNumber -> Slice [sliceEvents] :: Slice -> [SavedEvent] [sliceEndOfStream] :: Slice -> Bool [sliceNextEventNumber] :: Slice -> EventNumber -- | Deserializes a Slice's events. sliceEventsAs :: DecodeEvent a => Slice -> Either Text [a] -- | Encodes a data object into an Event. encodeEvent get -- passed an EventId in a case where a fresh id is needed. class EncodeEvent a encodeEvent :: EncodeEvent a => a -> State Event () -- | Decodes an Event into a data object. class DecodeEvent a decodeEvent :: DecodeEvent a => Event -> Either Text a newtype DecodeEventException DecodeEventException :: Text -> DecodeEventException -- | The purpose of ExpectedVersion is to make sure a certain stream -- state is at an expected point in order to carry out a write. data ExpectedVersion AnyVersion :: ExpectedVersion NoStream :: ExpectedVersion StreamExists :: ExpectedVersion ExactVersion :: EventNumber -> ExpectedVersion -- | Statuses you can get on every read attempt. data ReadStatus a ReadSuccess :: a -> ReadStatus a ReadFailure :: ReadFailure -> ReadStatus a -- | Returns True is ReadStatus is a ReadSuccess. isReadSuccess :: ReadStatus a -> Bool -- | Returns False is ReadStatus is a ReadFailure. isReadFailure :: ReadStatus a -> Bool -- | Represents the different kind of failure you can get when reading. data ReadFailure StreamNotFound :: StreamName -> ReadFailure ReadError :: (Maybe Text) -> ReadFailure AccessDenied :: StreamName -> ReadFailure instance GHC.Show.Show a => GHC.Show.Show (EventSource.Types.ReadStatus a) instance GHC.Show.Show EventSource.Types.ReadFailure instance GHC.Classes.Eq EventSource.Types.ExpectedVersion instance GHC.Show.Show EventSource.Types.ExpectedVersion instance GHC.Show.Show EventSource.Types.DecodeEventException instance GHC.Show.Show EventSource.Types.Slice instance GHC.Show.Show EventSource.Types.SavedEvent instance Data.Aeson.Types.ToJSON.ToJSON EventSource.Types.EventNumber instance Data.Aeson.Types.FromJSON.FromJSON EventSource.Types.EventNumber instance GHC.Show.Show EventSource.Types.EventNumber instance GHC.Enum.Enum EventSource.Types.EventNumber instance GHC.Num.Num EventSource.Types.EventNumber instance GHC.Classes.Ord EventSource.Types.EventNumber instance GHC.Classes.Eq EventSource.Types.EventNumber instance GHC.Show.Show EventSource.Types.Event instance Data.Aeson.Types.FromJSON.FromJSON EventSource.Types.EventType instance Data.Aeson.Types.ToJSON.ToJSON EventSource.Types.EventType instance GHC.Classes.Eq EventSource.Types.EventType instance Data.Aeson.Types.FromJSON.FromJSON EventSource.Types.StreamName instance Data.Aeson.Types.ToJSON.ToJSON EventSource.Types.StreamName instance GHC.Classes.Ord EventSource.Types.StreamName instance GHC.Classes.Eq EventSource.Types.StreamName instance GHC.Classes.Ord EventSource.Types.EventId instance GHC.Classes.Eq EventSource.Types.EventId instance GHC.Base.Monoid EventSource.Types.Properties instance Data.Semigroup.Semigroup EventSource.Types.Properties instance GHC.Base.Functor EventSource.Types.ReadStatus instance Data.Foldable.Foldable EventSource.Types.ReadStatus instance Data.Traversable.Traversable EventSource.Types.ReadStatus instance GHC.Exception.Exception EventSource.Types.DecodeEventException instance EventSource.Types.DecodeEvent EventSource.Types.Event instance EventSource.Types.EncodeEvent EventSource.Types.Event instance GHC.Show.Show EventSource.Types.EventType instance Data.String.IsString EventSource.Types.EventType instance GHC.Show.Show EventSource.Types.StreamName instance Data.String.IsString EventSource.Types.StreamName instance Data.Aeson.Types.ToJSON.ToJSON EventSource.Types.EventId instance Data.Aeson.Types.FromJSON.FromJSON EventSource.Types.EventId instance GHC.Show.Show EventSource.Types.EventId instance GHC.Show.Show EventSource.Types.Properties instance Data.Aeson.Types.ToJSON.ToJSON EventSource.Types.Properties instance Data.Aeson.Types.FromJSON.FromJSON EventSource.Types.Properties instance GHC.Base.Functor EventSource.Types.JsonParsing instance GHC.Base.Applicative EventSource.Types.JsonParsing instance GHC.Base.Monad EventSource.Types.JsonParsing instance GHC.Show.Show EventSource.Types.Data module EventSource.Store -- | Represents batch information needed to read a stream. data Batch Batch :: EventNumber -> Int32 -> Batch [batchFrom] :: Batch -> EventNumber [batchSize] :: Batch -> Int32 -- | A subscription allows to be notified on every change occuring on a -- stream. data Subscription Subscription :: SubscriptionId -> (forall m. MonadBase IO m => m (Either SomeException SavedEvent)) -> Subscription [subscriptionId] :: Subscription -> SubscriptionId [nextEvent] :: Subscription -> forall m. MonadBase IO m => m (Either SomeException SavedEvent) -- | Represents a subscription id. data SubscriptionId data ExpectedVersionException ExpectedVersionException :: ExpectedVersion -> ExpectedVersion -> ExpectedVersionException [versionExceptionExpected] :: ExpectedVersionException -> ExpectedVersion [versionExceptionActual] :: ExpectedVersionException -> ExpectedVersion -- | Main event store abstraction. It exposes essential features expected -- from an event store. class Store store -- | Appends a batch of events at the end of a stream. appendEvents :: (Store store, EncodeEvent a, MonadBase IO m) => store -> StreamName -> ExpectedVersion -> [a] -> m (Async EventNumber) -- | Appends a batch of events at the end of a stream. readBatch :: (Store store, MonadBase IO m) => store -> StreamName -> Batch -> m (Async (ReadStatus Slice)) -- | Subscribes to given stream. subscribe :: (Store store, MonadBase IO m) => store -> StreamName -> m Subscription -- | Encapsulates to an abstract store. toStore :: Store store => store -> SomeStore -- | Utility type to pass any store that implements Store typeclass. data SomeStore SomeStore :: store -> SomeStore -- | Allows to easily iterate over a stream's events. data StreamIterator iteratorNext :: StreamIterator -> forall m. MonadBase IO m => m (Maybe SavedEvent) -- | Reads the next available event from the StreamIterator and try -- to deserialize it at the same time. iteratorNextEvent :: (DecodeEvent a, MonadBase IO m, MonadPlus m) => StreamIterator -> m (Maybe a) -- | Reads all events from the StreamIterator until reaching end of -- stream. iteratorReadAll :: MonadBase IO m => StreamIterator -> m [SavedEvent] -- | Like iteratorReadAll but try to deserialize the events at the -- same time. iteratorReadAllEvents :: (DecodeEvent a, MonadBase IO m, MonadPlus m) => StreamIterator -> m [a] -- | Returns a StreamIterator for the given stream name. The -- returned StreamIterator IS NOT THREADSAFE. streamIterator :: (Store store, MonadBase IO m) => store -> StreamName -> m (ReadStatus StreamIterator) -- | Returns a fresh subscription id. freshSubscriptionId :: MonadBase IO m => m SubscriptionId -- | Starts a Batch from a given point. The batch size is set to -- default, which is 500. startFrom :: EventNumber -> Batch -- | Waits for the next event and deserializes it on the go. nextEventAs :: (DecodeEvent a, MonadBase IO m) => Subscription -> m (Either SomeException a) -- | Folds over every event coming from the subscription until the end of -- the universe, unless an Exception raises from the subscription. -- SomeException is used because we let the underlying -- subscription model exposed its own Exception. If the callback -- that handles incoming events throws an exception, it will not be catch -- by the error callback. foldSub :: (DecodeEvent a, MonadBase IO m) => Subscription -> (a -> m ()) -> (SomeException -> m ()) -> m () -- | Asynchronous version of foldSub. foldSubAsync :: (MonadBaseControl IO m, DecodeEvent a) => Subscription -> (a -> m ()) -> (SomeException -> m ()) -> m (Async (StM m ())) -- | Appends a single event at the end of a stream. appendEvent :: (EncodeEvent a, MonadBase IO m, Store store) => store -> StreamName -> ExpectedVersion -> a -> m (Async EventNumber) -- | Iterates over all events of stream given a starting point and a batch -- size. forEvents :: (MonadBase IO m, DecodeEvent a, Store store) => store -> StreamName -> (a -> m ()) -> ExceptT ForEventFailure m () -- | Iterates over all events of stream given a starting point and a batch -- size. It also passes the EventNumber at each recursion step. forEventsWithNumber :: (MonadBase IO m, DecodeEvent a, Store store) => store -> StreamName -> (EventNumber -> a -> m ()) -> ExceptT ForEventFailure m () -- | Like forEvents but expose signature similar to foldM -- and also passes the EventNumber at each recursion step. foldEventsWithNumberM :: (MonadBase IO m, DecodeEvent a, Store store) => store -> StreamName -> (EventNumber -> s -> a -> m s) -> s -> ExceptT ForEventFailure m s -- | Like forEvents but expose signature similar to foldM. foldEventsM :: (MonadBase IO m, DecodeEvent a, Store store) => store -> StreamName -> (s -> a -> m s) -> s -> ExceptT ForEventFailure m s -- | Like foldEventsM but expose signature similar to foldl. foldEvents :: (MonadBase IO m, DecodeEvent a, Store store) => store -> StreamName -> (s -> a -> s) -> s -> ExceptT ForEventFailure m s -- | Like forEvents but provides access to SavedEvent instead -- of decoded event. forSavedEvents :: (MonadBase IO m, Store store) => store -> StreamName -> (SavedEvent -> m ()) -> ExceptT ForEventFailure m () -- | Like forSavedEvents but expose signature similar to -- foldM. foldSavedEventsM :: (MonadBase IO m, Store store) => store -> StreamName -> (s -> SavedEvent -> m s) -> s -> ExceptT ForEventFailure m s -- | Like foldSavedEventsM but expose signature similar to -- foldl. foldSavedEvents :: (MonadBase IO m, Store store) => store -> StreamName -> (s -> SavedEvent -> s) -> s -> ExceptT ForEventFailure m s -- | Similar to foldSub but provides access to the SavedEvent -- instead of decoded event. foldSubSaved :: MonadBase IO m => Subscription -> (SavedEvent -> m ()) -> (SomeException -> m ()) -> m () -- | Asynchronous version of foldSubSaved. foldSubSavedAsync :: MonadBaseControl IO m => Subscription -> (SavedEvent -> m ()) -> (SomeException -> m ()) -> m (Async (StM m ())) -- | Represents failures that can occurs when using forEvents. data ForEventFailure ForEventReadFailure :: ReadFailure -> ForEventFailure ForEventDecodeFailure :: Text -> ForEventFailure -- | Throws an exception in case ExceptT was a Left. unhandled :: (MonadBase IO m, Exception e) => ExceptT e m a -> m a instance GHC.Show.Show EventSource.Store.ForEventFailure instance GHC.Show.Show EventSource.Store.ExpectedVersionException instance GHC.Show.Show EventSource.Store.SubscriptionId instance GHC.Classes.Ord EventSource.Store.SubscriptionId instance GHC.Classes.Eq EventSource.Store.SubscriptionId instance GHC.Show.Show EventSource.Store.StreamIterator instance GHC.Exception.Exception EventSource.Store.ForEventFailure instance EventSource.Store.Store EventSource.Store.SomeStore instance GHC.Exception.Exception EventSource.Store.ExpectedVersionException module EventSource -- | Implementation of an aggregate abstraction. Link: -- https://en.wikipedia.org/wiki/Domain-driven_design. module EventSource.Aggregate -- | Maps an id to a StreamName. class StreamId a toStreamName :: StreamId a => a -> StreamName -- | Represents a stream aggregate. An aggregate can rebuild its internal -- state by replaying all the stream's events that aggregate is -- responsible for. class Aggregate a where { type family Id a :: *; type family Evt a :: *; type family M a :: * -> *; } -- | Given current aggregate state, updates it according to the event the -- aggregate receives. apply :: Aggregate a => a -> Evt a -> M a a -- | Represents an aggregate that support validation. An aggregate that -- supports validation can receive command and decide if it was valid or -- not. When the validation is successful, The aggregate emits an event -- that will be persisted and pass to apply function. class Aggregate a => Validate a where { type family Cmd a :: *; type family Err a :: *; } -- | Validates a command. If the command validation succeeds, it will emits -- an event. Otherwise, it will returns an error. validate :: Validate a => a -> Cmd a -> M a (Decision a) -- | When validating a command, tells if the command was valid. If the -- command is valid, it returns an event. Otherwise, it returns an error. type Decision a = Either (Err a) (Evt a) -- | A stream aggregate. An aggregate updates its internal based on the -- event it receives. You can read its current state by using -- snapshot. If it supports validation, through Validated -- typeclass, it can receive command and emits an event if the command -- was successful. Otherwise, it will yield an error. When receiving -- valid command, an aggregate will persist the resulting event. An -- aggregate is only responsible of its own stream. data Agg a -- | Returns an aggregate id. aggId :: Agg a -> Id a -- | Executes an action on an aggregate. runAgg :: MonadBase IO (M a) => Agg a -> Action a r -> (r -> M a ()) -> M a () -- | Creates a new aggregate given an eventstore handle, an id and an -- initial state. newAgg :: (Aggregate a, MonadBaseControl IO (M a)) => SomeStore -> Id a -> a -> M a (Agg a) -- | Creates an aggregate and replays its entire stream to rebuild its -- internal state. loadAgg :: (Aggregate a, StreamId (Id a), DecodeEvent (Evt a), MonadBaseControl IO (M a)) => SomeStore -> Id a -> a -> M a (Either ForEventFailure (Agg a)) -- | Like loadAgg but call loadAgg in case of -- ForEventFailure error. loadOrCreateAgg :: (Aggregate a, StreamId (Id a), DecodeEvent (Evt a), MonadBaseControl IO (M a)) => SomeStore -> Id a -> a -> M a (Agg a) -- | Submits a command to the aggregate. If the command was valid, it -- returns an event otherwise an error. In case of a valid command, the -- aggregate persist the resulting event to the eventstore. The aggregate -- will also update its internal state accordingly. submitCmd :: (Validate a, MonadBase IO (M a), StreamId (Id a), EncodeEvent (Evt a)) => Agg a -> Cmd a -> M a (Decision a) -- | Submits an event. The aggregate will update its internal state -- accondingly. submitEvt :: (Aggregate a, MonadBase IO (M a)) => Agg a -> Evt a -> M a () -- | Returns current aggregate state. snapshot :: MonadBase IO (M a) => Agg a -> M a a -- | Uses usually by Root aggregates which usually have unusual workflow -- and make great use of a CPS-ed computation. -- http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1 route :: MonadBase IO (M a) => Agg a -> (SomeStore -> a -> (a -> r -> M a ()) -> M a ()) -> M a r -- | Closes internal aggregate state. closeAgg :: Agg a -> M a () -- | Executes an action. execute :: MonadBase IO (M a) => Agg a -> Action a r -> M a r -- | Internal aggregate action. An action is executed by an aggregate. An -- action embodies fundamental operations like submitting event, -- validating command or returning the current snapshot of an aggregate. -- Action are CPS-ed encoded so the execution model can be flexible. An -- action can perform synchronously or asynchronously. newtype Action' e s m a Action' :: (e -> s -> (s -> a -> m ()) -> m ()) -> Action' e s m a [runAction] :: Action' e s m a -> e -> s -> (s -> a -> m ()) -> m () -- | An action configured to aggregate internal types. type Action a r = Action' (AggEnv a) (AggState a) (M a) r -- | Returns an action environment. askEnv :: Action' e s m e -- | Returns an action current state. getState :: Action' e s m s -- | Set an action state. putState :: s -> Action' e s m () -- | Aggregate internal environment. data AggEnv a AggEnv :: SomeStore -> Id a -> AggEnv a -- | Handle to an eventstore. [aggEnvStore] :: AggEnv a -> SomeStore -- | Identification of the aggregate. [aggEnvId] :: AggEnv a -> Id a -- | Aggregate internal state. data AggState a AggState :: !ExpectedVersion -> !a -> AggState a -- | Expected version of the next write. This isn't expose to user and it's -- updated automatically. [aggStateVersion] :: AggState a -> !ExpectedVersion -- | Aggregate current state. [aggState] :: AggState a -> !a -- | Persists an event to the eventstore. persist :: (StreamId id, EncodeEvent event, MonadBase IO m) => SomeStore -> id -> ExpectedVersion -> event -> m EventNumber instance GHC.Base.Functor (EventSource.Aggregate.Action' e s m) instance GHC.Base.Applicative (EventSource.Aggregate.Action' e s m) instance GHC.Base.Monad (EventSource.Aggregate.Action' e s m) instance Control.Monad.Trans.Class.MonadTrans (EventSource.Aggregate.Action' e s) module EventSource.Aggregate.Simple -- | A stream aggregate. An aggregate updates its internal based on the -- event it receives. You can read its current state by using -- snapshot. If it supports validation, through Validated -- typeclass, it can receive command and emits an event if the command -- was successful. Otherwise, it will yield an error. When receiving -- valid command, an aggregate will persist the resulting event. An -- aggregate is only responsible of its own stream. type AggIO id command event state = Agg (Simple id command event state) -- | Represents a stream aggregate. An aggregate can rebuild its internal -- state by replaying all the stream's events that aggregate is -- responsible for. class AggregateIO event state | event -> state -- | Given current aggregate state, updates it according to the event the -- aggregate receives. applyIO :: AggregateIO event state => state -> event -> IO state -- | Represents an aggregate that support validation. An aggregate that -- supports validation can receive command and decide if it was valid or -- not. When the validation is successful, The aggregate emits an event -- that will be persisted and pass to apply function. class AggregateIO event state => ValidateIO command event state | command -> state, command -> event -- | Validates a command. If the command validation succeeds, it will emits -- an event. Otherwise, it will returns an error. validateIO :: ValidateIO command event state => state -> command -> IO (Either SomeException event) -- | Simple aggregate abstraction. data Simple id command event state -- | Creates a new aggregate given an eventstore handle, an id and an -- initial state. newAgg :: AggregateIO event state => SomeStore -> id -> state -> IO (AggIO id command event state) -- | Creates an aggregate and replays its entire stream to rebuild its -- internal state. loadAgg :: (AggregateIO event state, StreamId id, DecodeEvent event) => SomeStore -> id -> state -> IO (Either ForEventFailure (AggIO id command event state)) -- | Like loadAgg but call loadAgg in case of -- ForEventFailure error. loadOrCreateAgg :: (AggregateIO event state, StreamId id, DecodeEvent event) => SomeStore -> id -> state -> IO (AggIO id command event state) -- | Submits a command to the aggregate. If the command was valid, it -- returns an event otherwise an error. In case of a valid command, the -- aggregate persist the resulting event to the eventstore. The aggregate -- will also update its internal state accordingly. submitCmd :: (ValidateIO command event state, StreamId id, EncodeEvent event) => AggIO id command event state -> command -> IO (Either SomeException event) -- | Submits an event. The aggregate will update its internal state -- accondingly. submitEvt :: AggregateIO event state => AggIO id command event state -> event -> IO () -- | Closes internal aggregate state. closeAgg :: AggIO id command event state -> IO () -- | Returns current aggregate state. snapshot :: AggIO id command event state -> IO state -- | Uses usually by Root aggregates which usually have unusual workflow -- and make great use of a CPS-ed computation. -- http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1 route :: AggIO id command event state -> (SomeStore -> state -> (state -> r -> IO ()) -> IO ()) -> IO r instance EventSource.Aggregate.Simple.ValidateIO command event state => EventSource.Aggregate.Validate (EventSource.Aggregate.Simple.Simple id command event state) instance EventSource.Aggregate.Simple.AggregateIO event state => EventSource.Aggregate.Aggregate (EventSource.Aggregate.Simple.Simple id command event state)