packages feed

eventstore 1.1.6 → 1.2.0

raw patch · 25 files changed

+620/−461 lines, 25 filesdep +safedep +streamingdep ~containersPVP ok

version bump matches the API change (PVP)

Dependencies added: safe, streaming

Dependency ranges changed: containers

API changes (from Hackage documentation)

- Database.EventStore: All :: StreamType
- Database.EventStore: AllStream :: StreamName
- Database.EventStore: RegularStream :: StreamType
- Database.EventStore: StreamName :: Text -> StreamName
- Database.EventStore: class Slice a where {
- Database.EventStore: data AllSlice
- Database.EventStore: data StreamName
- Database.EventStore: data StreamSlice
- Database.EventStore: data StreamType
- Database.EventStore: isSubscribedToAll :: Subscription s => s -> Bool
- Database.EventStore: readAllEventsBackward :: Connection -> Position -> Int32 -> Bool -> Maybe Credentials -> IO (Async AllSlice)
- Database.EventStore: readAllEventsForward :: Connection -> Position -> Int32 -> Bool -> Maybe Credentials -> IO (Async AllSlice)
- Database.EventStore: readStreamEventsBackward :: Connection -> StreamName -> Int64 -> Int32 -> Bool -> Maybe Credentials -> IO (Async (ReadResult 'RegularStream StreamSlice))
- Database.EventStore: readStreamEventsForward :: Connection -> StreamName -> Int64 -> Int32 -> Bool -> Maybe Credentials -> IO (Async (ReadResult 'RegularStream StreamSlice))
- Database.EventStore: sliceDirection :: Slice a => a -> ReadDirection
- Database.EventStore: sliceFrom :: Slice a => a -> Loc a
- Database.EventStore: subscribeToAll :: Connection -> Bool -> Maybe Credentials -> IO RegularSubscription
- Database.EventStore: subscribeToAllFrom :: Connection -> Bool -> Maybe Position -> Maybe Int32 -> Maybe Credentials -> IO CatchupSubscription
- Database.EventStore: toSlice :: Slice a => a -> SomeSlice
- Database.EventStore: }
+ Database.EventStore: NoResolveLink :: ResolveLink
+ Database.EventStore: ResolveLink :: ResolveLink
+ Database.EventStore: Slice :: ![ResolvedEvent] -> !Maybe t -> Slice t
+ Database.EventStore: SliceEndOfStream :: Slice t
+ Database.EventStore: [All] :: StreamId Position
+ Database.EventStore: [StreamName] :: Text -> StreamId EventNumber
+ Database.EventStore: class SubscriptionStream s t | t -> s
+ Database.EventStore: data EventNumber
+ Database.EventStore: data ResolveLink
+ Database.EventStore: data Slice t
+ Database.EventStore: data StreamId loc
+ Database.EventStore: emptySlice :: Slice t
+ Database.EventStore: eventNumber :: Natural -> EventNumber
+ Database.EventStore: eventNumberToInt64 :: EventNumber -> Int64
+ Database.EventStore: infixr 5 :|
+ Database.EventStore: isAllStream :: StreamId t -> Bool
+ Database.EventStore: rawEventNumber :: Int64 -> EventNumber
+ Database.EventStore: readEventsBackward :: Connection -> StreamId t -> t -> Int32 -> ResolveLink -> Maybe Credentials -> IO (Async (BatchResult t))
+ Database.EventStore: readEventsForward :: Connection -> StreamId t -> t -> Int32 -> ResolveLink -> Maybe Credentials -> IO (Async (BatchResult t))
+ Database.EventStore: streamEnd :: EventNumber
+ Database.EventStore: streamStart :: EventNumber
+ Database.EventStore: type AllSlice = Slice Position
+ Database.EventStore: type StreamName = StreamId EventNumber
+ Database.EventStore: type StreamSlice = Slice EventNumber
+ Database.EventStore.Streaming: AccessDenied :: !StreamId t -> ReadError t
+ Database.EventStore.Streaming: ReadError :: !Maybe Text -> ReadError t
+ Database.EventStore.Streaming: StreamDeleted :: !StreamName -> ReadError t
+ Database.EventStore.Streaming: data ReadError t
+ Database.EventStore.Streaming: instance (GHC.Show.Show t, Data.Typeable.Internal.Typeable t) => GHC.Exception.Type.Exception (Database.EventStore.Streaming.ReadError t)
+ Database.EventStore.Streaming: instance GHC.Show.Show (Database.EventStore.Streaming.ReadError t)
+ Database.EventStore.Streaming: readThroughBackward :: Connection -> StreamId t -> ResolveLink -> t -> Maybe Int32 -> Maybe Credentials -> Stream (Of ResolvedEvent) (ExceptT (ReadError t) IO) ()
+ Database.EventStore.Streaming: readThroughForward :: Connection -> StreamId t -> ResolveLink -> t -> Maybe Int32 -> Maybe Credentials -> Stream (Of ResolvedEvent) (ExceptT (ReadError t) IO) ()
+ Database.EventStore.Streaming: throwOnError :: (Show t, Typeable t) => Stream (Of a) (ExceptT (ReadError t) IO) () -> Stream (Of a) IO ()
- Database.EventStore: AccessDenied :: StreamName -> OperationError
+ Database.EventStore: AccessDenied :: StreamId t -> OperationError
- Database.EventStore: ClusterSettings :: !ByteString -> !Int -> !Int -> (Maybe (NonEmpty GossipSeed)) -> !TimeSpan -> !(Maybe DnsServer) -> ClusterSettings
+ Database.EventStore: ClusterSettings :: !ByteString -> !Int -> !Int -> Maybe (NonEmpty GossipSeed) -> !TimeSpan -> !Maybe DnsServer -> ClusterSettings
- Database.EventStore: Dns :: ByteString -> (Maybe DnsServer) -> Int -> ConnectionType
+ Database.EventStore: Dns :: ByteString -> Maybe DnsServer -> Int -> ConnectionType
- Database.EventStore: LogCallback :: LogStr -> IO () -> IO () -> LogType
+ Database.EventStore: LogCallback :: (LogStr -> IO ()) -> IO () -> LogType
- Database.EventStore: ReadEvent :: !Text -> !Int32 -> !ResolvedEvent -> ReadEvent
+ Database.EventStore: ReadEvent :: !Text -> !Int64 -> !ResolvedEvent -> ReadEvent
- Database.EventStore: ReadEventNotFound :: !Text -> !Int32 -> ReadEvent
+ Database.EventStore: ReadEventNotFound :: !Text -> !Int64 -> ReadEvent
- Database.EventStore: RecordedEvent :: !Text -> !UUID -> !Int64 -> !Text -> !ByteString -> !(Maybe ByteString) -> !Bool -> !(Maybe UTCTime) -> RecordedEvent
+ Database.EventStore: RecordedEvent :: !Text -> !UUID -> !Int64 -> !Text -> !ByteString -> !Maybe ByteString -> !Bool -> !Maybe UTCTime -> RecordedEvent
- Database.EventStore: ResolvedEvent :: !(Maybe RecordedEvent) -> !(Maybe RecordedEvent) -> !(Maybe Position) -> ResolvedEvent
+ Database.EventStore: ResolvedEvent :: !Maybe RecordedEvent -> !Maybe RecordedEvent -> !Maybe Position -> ResolvedEvent
- Database.EventStore: ServerError :: (Maybe Text) -> OperationError
+ Database.EventStore: ServerError :: Maybe Text -> OperationError
- Database.EventStore: StreamDeleted :: Text -> OperationError
+ Database.EventStore: StreamDeleted :: StreamName -> OperationError
- Database.EventStore: StreamMetadata :: !(Maybe Int32) -> !(Maybe TimeSpan) -> !(Maybe Int32) -> !(Maybe TimeSpan) -> !StreamACL -> !Object -> StreamMetadata
+ Database.EventStore: StreamMetadata :: !Maybe Int32 -> !Maybe TimeSpan -> !Maybe Int32 -> !Maybe TimeSpan -> !StreamACL -> !Object -> StreamMetadata
- Database.EventStore: StreamMetadataResult :: !Text -> !Int32 -> !StreamMetadata -> StreamMetadataResult
+ Database.EventStore: StreamMetadataResult :: !Text -> !Int64 -> !StreamMetadata -> StreamMetadataResult
- Database.EventStore: StreamNotFound :: Text -> OperationError
+ Database.EventStore: StreamNotFound :: StreamName -> OperationError
- Database.EventStore: SubNotAuthenticated :: (Maybe Text) -> SubDropReason
+ Database.EventStore: SubNotAuthenticated :: Maybe Text -> SubDropReason
- Database.EventStore: SubNotHandled :: !NotHandledReason -> !(Maybe MasterInfo) -> SubDropReason
+ Database.EventStore: SubNotHandled :: !NotHandledReason -> !Maybe MasterInfo -> SubDropReason
- Database.EventStore: SubServerError :: (Maybe Text) -> SubDropReason
+ Database.EventStore: SubServerError :: Maybe Text -> SubDropReason
- Database.EventStore: SubscriptionClosed :: (Maybe SubDropReason) -> SubscriptionClosed
+ Database.EventStore: SubscriptionClosed :: Maybe SubDropReason -> SubscriptionClosed
- Database.EventStore: [ReadAccessDenied] :: StreamName -> ReadResult t a
+ Database.EventStore: [ReadAccessDenied] :: StreamId t -> ReadResult t a
- Database.EventStore: [ReadNoStream] :: ReadResult 'RegularStream a
+ Database.EventStore: [ReadNoStream] :: ReadResult EventNumber a
- Database.EventStore: [ReadStreamDeleted] :: Text -> ReadResult 'RegularStream a
+ Database.EventStore: [ReadStreamDeleted] :: StreamName -> ReadResult EventNumber a
- Database.EventStore: [clusterDnsServer] :: ClusterSettings -> !(Maybe DnsServer)
+ Database.EventStore: [clusterDnsServer] :: ClusterSettings -> !Maybe DnsServer
- Database.EventStore: [clusterGossipSeeds] :: ClusterSettings -> (Maybe (NonEmpty GossipSeed))
+ Database.EventStore: [clusterGossipSeeds] :: ClusterSettings -> Maybe (NonEmpty GossipSeed)
- Database.EventStore: [readEventNumber] :: ReadEvent -> !Int32
+ Database.EventStore: [readEventNumber] :: ReadEvent -> !Int64
- Database.EventStore: [recordedEventCreated] :: RecordedEvent -> !(Maybe UTCTime)
+ Database.EventStore: [recordedEventCreated] :: RecordedEvent -> !Maybe UTCTime
- Database.EventStore: [recordedEventMetadata] :: RecordedEvent -> !(Maybe ByteString)
+ Database.EventStore: [recordedEventMetadata] :: RecordedEvent -> !Maybe ByteString
- Database.EventStore: [resolvedEventLink] :: ResolvedEvent -> !(Maybe RecordedEvent)
+ Database.EventStore: [resolvedEventLink] :: ResolvedEvent -> !Maybe RecordedEvent
- Database.EventStore: [resolvedEventPosition] :: ResolvedEvent -> !(Maybe Position)
+ Database.EventStore: [resolvedEventPosition] :: ResolvedEvent -> !Maybe Position
- Database.EventStore: [resolvedEventRecord] :: ResolvedEvent -> !(Maybe RecordedEvent)
+ Database.EventStore: [resolvedEventRecord] :: ResolvedEvent -> !Maybe RecordedEvent
- Database.EventStore: [streamMetaResultVersion] :: StreamMetadataResult -> !Int32
+ Database.EventStore: [streamMetaResultVersion] :: StreamMetadataResult -> !Int64
- Database.EventStore: [streamMetadataCacheControl] :: StreamMetadata -> !(Maybe TimeSpan)
+ Database.EventStore: [streamMetadataCacheControl] :: StreamMetadata -> !Maybe TimeSpan
- Database.EventStore: [streamMetadataMaxAge] :: StreamMetadata -> !(Maybe TimeSpan)
+ Database.EventStore: [streamMetadataMaxAge] :: StreamMetadata -> !Maybe TimeSpan
- Database.EventStore: [streamMetadataMaxCount] :: StreamMetadata -> !(Maybe Int32)
+ Database.EventStore: [streamMetadataMaxCount] :: StreamMetadata -> !Maybe Int32
- Database.EventStore: [streamMetadataTruncateBefore] :: StreamMetadata -> !(Maybe Int32)
+ Database.EventStore: [streamMetadataTruncateBefore] :: StreamMetadata -> !Maybe Int32
- Database.EventStore: data CatchupSubscription
+ Database.EventStore: data CatchupSubscription t
- Database.EventStore: data ReadResult :: StreamType -> * -> *
+ Database.EventStore: data ReadResult t a
- Database.EventStore: data RegularSubscription
+ Database.EventStore: data RegularSubscription t
- Database.EventStore: hasCaughtUp :: CatchupSubscription -> IO Bool
+ Database.EventStore: hasCaughtUp :: CatchupSubscription t -> IO Bool
- Database.EventStore: hasCaughtUpSTM :: CatchupSubscription -> STM Bool
+ Database.EventStore: hasCaughtUpSTM :: CatchupSubscription t -> STM Bool
- Database.EventStore: nonEmpty :: () => [a] -> Maybe NonEmpty a
+ Database.EventStore: nonEmpty :: () => [a] -> Maybe (NonEmpty a)
- Database.EventStore: readEvent :: Connection -> StreamName -> Int32 -> Bool -> Maybe Credentials -> IO (Async (ReadResult 'RegularStream ReadEvent))
+ Database.EventStore: readEvent :: Connection -> StreamName -> EventNumber -> ResolveLink -> Maybe Credentials -> IO (Async (ReadResult EventNumber ReadEvent))
- Database.EventStore: sliceEOS :: Slice a => a -> Bool
+ Database.EventStore: sliceEOS :: Slice t -> Bool
- Database.EventStore: sliceEvents :: Slice a => a -> [ResolvedEvent]
+ Database.EventStore: sliceEvents :: Slice t -> [ResolvedEvent]
- Database.EventStore: sliceNext :: Slice a => a -> Loc a
+ Database.EventStore: sliceNext :: Slice t -> Maybe t
- Database.EventStore: subscribe :: Connection -> StreamName -> Bool -> Maybe Credentials -> IO RegularSubscription
+ Database.EventStore: subscribe :: Connection -> StreamId t -> ResolveLink -> Maybe Credentials -> IO (RegularSubscription t)
- Database.EventStore: subscribeFrom :: Connection -> StreamName -> Bool -> Maybe Int64 -> Maybe Int32 -> Maybe Credentials -> IO CatchupSubscription
+ Database.EventStore: subscribeFrom :: Connection -> StreamId t -> ResolveLink -> Maybe t -> Maybe Int32 -> Maybe Credentials -> IO (CatchupSubscription t)
- Database.EventStore: subscriptionStream :: Subscription s => s -> StreamName
+ Database.EventStore: subscriptionStream :: SubscriptionStream s t => s -> StreamId t
- Database.EventStore: type family Loc a;
+ Database.EventStore: type family BatchResult t
- Database.EventStore: waitTillCatchup :: CatchupSubscription -> IO ()
+ Database.EventStore: waitTillCatchup :: CatchupSubscription t -> IO ()

Files

CHANGELOG.markdown view
@@ -1,3 +1,13 @@+1.2.0+-----+* Introduce a type-safe `EventNumber` setting.+* Introduce a type-safe `ResolveLink` setting.+* Support GHC 8.6 but drop GHC < 8.+* Refactor `Slice` api.+* Implement a stream-processing interface.+* typeful stream id representation.+* Uniform batch-read and subscription interface.+ 1.1.6 ----- * Update package metadata information.
Database/EventStore.hs view
@@ -51,15 +51,22 @@     , withJsonAndMetadata     , withBinary     , withBinaryAndMetadata+     -- * Event number+    , EventNumber+    , streamStart+    , streamEnd+    , eventNumber+    , rawEventNumber+    , eventNumberToInt64      -- * Common Operation types     , OperationMaxAttemptReached(..)      -- * Read Operations     , StreamMetadataResult(..)+    , BatchResult(..)+    , ResolveLink(..)     , readEvent-    , readAllEventsBackward-    , readAllEventsForward-    , readStreamEventsBackward-    , readStreamEventsForward+    , readEventsBackward+    , readEventsForward     , getStreamMetadata       -- * Write Operations     , StreamACL(..)@@ -110,6 +117,7 @@       -- * Subscription     , SubscriptionClosed(..)     , SubscriptionId+    , SubscriptionStream(..)     , Subscription     , SubDropReason(..)     , SubDetails@@ -120,19 +128,15 @@     , nextEventMaybeSTM     , getSubscriptionDetailsSTM     , unsubscribe-    , subscriptionStream       -- * Volatile Subscription     , RegularSubscription     , subscribe-    , subscribeToAll     , getSubscriptionId-    , isSubscribedToAll     , nextEvent     , nextEventMaybe       -- * Catch-up Subscription     , CatchupSubscription     , subscribeFrom-    , subscribeToAllFrom     , waitTillCatchup     , hasCaughtUp     , hasCaughtUpSTM@@ -155,19 +159,24 @@     , connectToPersistentSubscription      -- * Results     , Slice(..)+    , sliceEvents+    , sliceEOS+    , sliceNext+    , emptySlice     , AllSlice     , Op.DeleteResult(..)     , WriteResult(..)     , ReadResult(..)     , RecordedEvent(..)     , Op.ReadEvent(..)-    , StreamType(..)     , StreamSlice     , Position(..)     , ReadDirection(..)     , ResolvedEvent(..)     , OperationError(..)+    , StreamId(..)     , StreamName(..)+    , isAllStream     , isEventResolvedLink     , resolvedEventOriginal     , resolvedEventDataAsJson@@ -315,7 +324,7 @@            -> IO (Async WriteResult) sendEvents Connection{..} evt_stream exp_ver evts cred = do     p <- newPromise-    let op = Op.writeEvents _settings (streamNameRaw evt_stream) exp_ver cred evts+    let op = Op.writeEvents _settings (streamIdRaw evt_stream) exp_ver cred evts     publishWith _exec (SubmitOperation p op)     async (retrieve p) @@ -329,7 +338,7 @@              -> IO (Async Op.DeleteResult) deleteStream Connection{..} evt_stream exp_ver hard_del cred = do     p <- newPromise-    let op = Op.deleteStream _settings (streamNameRaw evt_stream) exp_ver hard_del cred+    let op = Op.deleteStream _settings (streamIdRaw evt_stream) exp_ver hard_del cred     publishWith _exec (SubmitOperation p op)     async (retrieve p) @@ -363,12 +372,12 @@                  -> IO (Async Transaction) startTransaction conn@Connection{..} evt_stream exp_ver cred = do     p <- newPromise-    let op = Op.transactionStart _settings (streamNameRaw evt_stream) exp_ver cred+    let op = Op.transactionStart _settings (streamIdRaw evt_stream) exp_ver cred     publishWith _exec (SubmitOperation p op)     async $ do         tid <- retrieve p         return Transaction-               { _tStream  = streamNameRaw evt_stream+               { _tStream  = streamIdRaw evt_stream                , _tTransId = TransactionId tid                , _tExpVer  = exp_ver                , _tConn    = conn@@ -409,152 +418,119 @@ -- | Reads a single event from given stream. readEvent :: Connection           -> StreamName-          -> Int32      -- ^ Event number-          -> Bool       -- ^ Resolve Link Tos+          -> EventNumber+          -> ResolveLink           -> Maybe Credentials-          -> IO (Async (ReadResult 'RegularStream Op.ReadEvent))-readEvent Connection{..} stream_id evt_num res_link_tos cred = do+          -> IO (Async (ReadResult EventNumber Op.ReadEvent))+readEvent Connection{..} stream_id evtNum resLinkTos cred = do     p <- newPromise-    let op = Op.readEvent _settings (streamNameRaw stream_id) evt_num res_link_tos cred+    let evt_num = eventNumberToInt64 evtNum+        res_link_tos = resolveLinkToBool resLinkTos+        op = Op.readEvent _settings (streamIdRaw stream_id) evt_num res_link_tos cred     publishWith _exec (SubmitOperation p op)     async (retrieve p)  ----------------------------------------------------------------------------------- | Reads events from a given stream forward.-readStreamEventsForward :: Connection-                        -> StreamName-                        -> Int64      -- ^ From event number-                        -> Int32      -- ^ Batch size-                        -> Bool       -- ^ Resolve Link Tos-                        -> Maybe Credentials-                        -> IO (Async (ReadResult 'RegularStream StreamSlice))-readStreamEventsForward mgr =-    readStreamEventsCommon mgr Forward------------------------------------------------------------------------------------- | Reads events from a given stream backward.-readStreamEventsBackward :: Connection-                         -> StreamName-                         -> Int64      -- ^ From event number-                         -> Int32      -- ^ Batch size-                         -> Bool       -- ^ Resolve Link Tos-                         -> Maybe Credentials-                         -> IO (Async (ReadResult 'RegularStream StreamSlice))-readStreamEventsBackward mgr =-    readStreamEventsCommon mgr Backward-----------------------------------------------------------------------------------readStreamEventsCommon :: Connection-                       -> ReadDirection-                       -> StreamName-                       -> Int64-                       -> Int32-                       -> Bool-                       -> Maybe Credentials-                       -> IO (Async (ReadResult 'RegularStream StreamSlice))-readStreamEventsCommon Connection{..} dir stream_id start cnt res_link_tos cred = do-    p <- newPromise-    let name = streamNameRaw stream_id-        op   = Op.readStreamEvents _settings dir name start cnt res_link_tos cred-    publishWith _exec (SubmitOperation p op)-    async (retrieve p)+-- | When batch-reading a stream, this type-level function maps the result you+--   will have whether you read a regular stream or $all stream. When reading+--   a regular stream, some read-error can occur like the stream got deleted.+--   However read-error cannot occur when reading $all stream (because $all+--   cannot get deleted).+type family BatchResult t where+    BatchResult EventNumber = ReadResult EventNumber StreamSlice+    BatchResult Position    = AllSlice  ----------------------------------------------------------------------------------- | Reads events from the $all stream forward.-readAllEventsForward :: Connection-                     -> Position-                     -> Int32      -- ^ Batch size-                     -> Bool       -- ^ Resolve Link Tos-                     -> Maybe Credentials-                     -> IO (Async AllSlice)-readAllEventsForward mgr =-    readAllEventsCommon mgr Forward+-- | Reads events from a stream forward.+readEventsForward :: Connection+                  -> StreamId t+                  -> t+                  -> Int32      -- ^ Batch size+                  -> ResolveLink+                  -> Maybe Credentials+                  -> IO (Async (BatchResult t))+readEventsForward conn = readEventsCommon conn Forward  ----------------------------------------------------------------------------------- | Reads events from the $all stream backward-readAllEventsBackward :: Connection-                      -> Position-                      -> Int32      -- ^ Batch size-                      -> Bool       -- ^ Resolve Link Tos-                      -> Maybe Credentials-                      -> IO (Async AllSlice)-readAllEventsBackward mgr =-    readAllEventsCommon mgr Backward+-- | Reads events from a stream backward.+readEventsBackward :: Connection+                   -> StreamId t+                   -> t+                   -> Int32      -- ^ Batch size+                   -> ResolveLink+                   -> Maybe Credentials+                   -> IO (Async (BatchResult t))+readEventsBackward conn = readEventsCommon conn Backward  ---------------------------------------------------------------------------------readAllEventsCommon :: Connection-                    -> ReadDirection-                    -> Position-                    -> Int32-                    -> Bool-                    -> Maybe Credentials-                    -> IO (Async AllSlice)-readAllEventsCommon Connection{..} dir pos max_c res_link_tos cred = do+readEventsCommon :: Connection+                 -> ReadDirection+                 -> StreamId t+                 -> t+                 -> Int32+                 -> ResolveLink+                 -> Maybe Credentials+                 -> IO (Async (BatchResult t))+readEventsCommon Connection{..} dir streamId start cnt resLinkTos cred = do     p <- newPromise-    let op = Op.readAllEvents _settings c_pos p_pos max_c res_link_tos dir cred+    let res_link_tos = resolveLinkToBool resLinkTos+        op =+            case streamId of+                StreamName{} ->+                    let name   = streamIdRaw streamId+                        evtNum = eventNumberToInt64 start in+                    Op.readStreamEvents _settings dir name evtNum cnt res_link_tos cred+                All ->+                    let Position c_pos p_pos = start in+                    Op.readAllEvents _settings c_pos p_pos cnt res_link_tos dir cred+     publishWith _exec (SubmitOperation p op)     async (retrieve p)-  where-    Position c_pos p_pos = pos  ----------------------------------------------------------------------------------- | Subcribes to given stream.+-- | Subscribes to a stream. subscribe :: Connection-          -> StreamName-          -> Bool       -- ^ Resolve Link Tos+          -> StreamId t+          -> ResolveLink           -> Maybe Credentials-          -> IO RegularSubscription-subscribe Connection{..} stream resLnkTos cred =+          -> IO (RegularSubscription t)+subscribe Connection{..} stream resLinkTos cred =     newRegularSubscription _exec stream resLnkTos cred------------------------------------------------------------------------------------- | Subcribes to $all stream.-subscribeToAll :: Connection-               -> Bool       -- ^ Resolve Link Tos-               -> Maybe Credentials-               -> IO RegularSubscription-subscribeToAll conn resLnkTos cred = subscribe conn AllStream resLnkTos cred+  where+    resLnkTos = resolveLinkToBool resLinkTos  ----------------------------------------------------------------------------------- | Subscribes to given stream. If last checkpoint is defined, this will+-- | Subscribes to a stream. If last checkpoint is defined, this will --   'readStreamEventsForward' from that event number, otherwise from the --   beginning. Once last stream event reached up, a subscription request will --   be sent using 'subscribe'. subscribeFrom :: Connection-              -> StreamName-              -> Bool        -- ^ Resolve Link Tos-              -> Maybe Int64 -- ^ Last checkpoint+              -> StreamId t+              -> ResolveLink+              -> Maybe t               -> Maybe Int32 -- ^ Batch size               -> Maybe Credentials-              -> IO CatchupSubscription-subscribeFrom conn streamId resLnkTos lastChkPt batch cred =-    subscribeFromCommon conn resLnkTos batch cred tpe-  where-    tpe = Op.RegularCatchup (streamNameRaw streamId) (fromMaybe 0 lastChkPt)------------------------------------------------------------------------------------- | Same as 'subscribeFrom' but applied to $all stream.-subscribeToAllFrom :: Connection-                   -> Bool           -- ^ Resolve Link Tos-                   -> Maybe Position -- ^ Last checkpoint-                   -> Maybe Int32    -- ^ Batch size-                   -> Maybe Credentials-                   -> IO CatchupSubscription-subscribeToAllFrom conn resLnkTos lastChkPt batch cred =-    subscribeFromCommon conn resLnkTos batch cred tpe+              -> IO (CatchupSubscription t)+subscribeFrom Connection{..} streamId resLinkTos lastChkPt batch cred =+    newCatchupSubscription _exec resLnkTos batch cred streamId $+        case streamId of+            StreamName{} -> fromMaybe streamStart lastChkPt+            All          -> fromMaybe positionStart lastChkPt   where-    Position cPos pPos = fromMaybe positionStart lastChkPt-    tpe = Op.AllCatchup (Position cPos pPos)+    resLnkTos = resolveLinkToBool resLinkTos  -------------------------------------------------------------------------------- subscribeFromCommon :: Connection-                    -> Bool+                    -> ResolveLink                     -> Maybe Int32                     -> Maybe Credentials-                    -> Op.CatchupState-                    -> IO CatchupSubscription-subscribeFromCommon Connection{..} resLnkTos batch cred tpe =-    newCatchupSubscription _exec resLnkTos batch cred tpe+                    -> StreamId t+                    -> t+                    -> IO (CatchupSubscription t)+subscribeFromCommon Connection{..} resLinkTos batch cred kind seed =+    newCatchupSubscription _exec resLnkTos batch cred kind seed+  where+    resLnkTos = resolveLinkToBool resLinkTos  -------------------------------------------------------------------------------- -- | Asynchronously sets the metadata for a stream.@@ -566,7 +542,7 @@                   -> IO (Async WriteResult) setStreamMetadata Connection{..} evt_stream exp_ver metadata cred = do     p <- newPromise-    let name = streamNameRaw evt_stream+    let name = streamIdRaw evt_stream         op = Op.setMetaStream _settings name exp_ver cred metadata     publishWith _exec (SubmitOperation p op)     async (retrieve p)@@ -579,7 +555,7 @@                   -> IO (Async StreamMetadataResult) getStreamMetadata Connection{..} evt_stream cred = do     p <- newPromise-    let op = Op.readMetaStream _settings (streamNameRaw evt_stream) cred+    let op = Op.readMetaStream _settings (streamIdRaw evt_stream) cred     publishWith _exec (SubmitOperation p op)     async (retrieve p) @@ -593,7 +569,7 @@                              -> IO (Async (Maybe PersistActionException)) createPersistentSubscription Connection{..} grp stream sett cred = do     p <- newPromise-    let op = Op.createPersist grp (streamNameRaw stream) sett cred+    let op = Op.createPersist grp (streamIdRaw stream) sett cred     publishWith _exec (SubmitOperation p op)     async (persistAsync p) @@ -607,7 +583,7 @@                              -> IO (Async (Maybe PersistActionException)) updatePersistentSubscription Connection{..} grp stream sett cred = do     p <- newPromise-    let op = Op.updatePersist grp (streamNameRaw stream) sett cred+    let op = Op.updatePersist grp (streamIdRaw stream) sett cred     publishWith _exec (SubmitOperation p op)     async (persistAsync p) @@ -620,7 +596,7 @@                              -> IO (Async (Maybe PersistActionException)) deletePersistentSubscription Connection{..} grp stream cred = do     p <- newPromise-    let op = Op.deletePersist grp (streamNameRaw stream) cred+    let op = Op.deletePersist grp (streamIdRaw stream) cred     publishWith _exec (SubmitOperation p op)     async (persistAsync p) 
Database/EventStore/Internal/Control.hs view
@@ -52,6 +52,9 @@   ) where  --------------------------------------------------------------------------------+#if __GLASGOW_HASKELL__ > 710+import Control.Monad.Fail+#endif import Data.Typeable #if __GLASGOW_HASKELL__ < 802 import Data.Typeable.Internal@@ -86,6 +89,9 @@   deriving ( Functor            , Applicative            , Monad+#if __GLASGOW_HASKELL__ > 710+           , MonadFail+#endif            , MonadThrow            , MonadCatch            , MonadIO
Database/EventStore/Internal/Operation.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE KindSignatures             #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE Rank2Types                 #-}+{-# LANGUAGE StandaloneDeriving         #-} -------------------------------------------------------------------------------- -- | -- Module : Database.EventStore.Internal.Operation@@ -74,22 +75,25 @@ -- | Operation exception that can occurs on an operation response. data OperationError     = WrongExpectedVersion Text ExpectedVersion -- ^ Stream and Expected Version-    | StreamDeleted Text                        -- ^ Stream+    | StreamDeleted StreamName                        -- ^ Stream     | InvalidTransaction-    | AccessDenied StreamName                   -- ^ Stream+    | forall t. AccessDenied (StreamId t)                   -- ^ Stream     | InvalidServerResponse Command Command     -- ^ Expected, Found     | ProtobufDecodingError String     | ServerError (Maybe Text)                  -- ^ Reason     | InvalidOperation Text-    | StreamNotFound Text+    | StreamNotFound StreamName     | NotAuthenticatedOp       -- ^ Invalid operation state. If happens, it's a driver bug.     | Aborted       -- ^ Occurs when the user asked to close the connection or if the       --   connection can't reconnect anymore.-    deriving (Show, Typeable)+    deriving Typeable  --------------------------------------------------------------------------------+deriving instance Show OperationError++-------------------------------------------------------------------------------- instance Exception OperationError  --------------------------------------------------------------------------------@@ -218,7 +222,7 @@  -------------------------------------------------------------------------------- -- | Raises 'StreamDeleted' exception.-streamDeleted :: Text -> Code o a+streamDeleted :: StreamName -> Code o a streamDeleted stream = failure (StreamDeleted stream)  --------------------------------------------------------------------------------@@ -228,7 +232,7 @@  -------------------------------------------------------------------------------- -- | Raises 'AccessDenied' exception.-accessDenied :: StreamName -> Code oconcat a+accessDenied :: StreamId t -> Code o a accessDenied = failure . AccessDenied  --------------------------------------------------------------------------------
Database/EventStore/Internal/Operation/Catchup.hs view
@@ -1,6 +1,7 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE GADTs             #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-} -------------------------------------------------------------------------------- -- | -- Module : Database.EventStore.Internal.Operation.Catchup@@ -13,11 +14,7 @@ -- -------------------------------------------------------------------------------- module Database.EventStore.Internal.Operation.Catchup-    ( CatchupState(..)-    , CatchupOpResult(..)-    , Checkpoint(..)-    , catchup-    ) where+    ( catchup ) where  -------------------------------------------------------------------------------- import Data.Int@@ -36,100 +33,75 @@ import Database.EventStore.Internal.Types  ----------------------------------------------------------------------------------- | Represents the next checkpoint to reach on a catchup subscription. Wheither---   it's a regular stream or the $all stream, it either point to an 'Int32' or---   a 'Position'.-data Checkpoint = CheckpointNumber Int32 | CheckpointPosition Position---------------------------------------------------------------------------------- defaultBatchSize :: Int32 defaultBatchSize = 500  -------------------------------------------------------------------------------- streamNotFound :: Text -> OperationError-streamNotFound stream = StreamNotFound stream+streamNotFound stream = StreamNotFound $ StreamName stream  ----------------------------------------------------------------------------------- | Catchup operation state.-data CatchupState-    = RegularCatchup Text Int64-      -- ^ Indicates the stream name and the next event number to start from.-    | AllCatchup Position-      -- ^ Indicates the commit and prepare position. Used when catching up from-      --   the $all stream.-    deriving Show+fetchStream :: Settings+            -> Text -- Stream name.+            -> Int32 -- Batch size.+            -> Bool -- Resolve link tos.+            -> Maybe Credentials+            -> EventNumber+            -> Code o (Slice EventNumber)+fetchStream setts stream batch tos cred (EventNumber n) = do+    outcome <-+        deconstruct $ fmap Left $+            readStreamEvents setts Forward stream n batch tos cred ----------------------------------------------------------------------------------fetch :: Settings-      -> Int32-      -> Bool-      -> CatchupState-      -> Maybe Credentials-      -> Code o SomeSlice-fetch setts batch tos state cred =-    case state of-        RegularCatchup stream n -> do-            outcome <- deconstruct $ fmap Left $-                           readStreamEvents setts Forward stream n batch tos cred-            fromReadResult stream outcome (return . toSlice)-        AllCatchup (Position com pre) ->-            deconstruct $ fmap (Left . toSlice) $-                readAllEvents setts com pre batch tos Forward cred+    fromReadResult stream outcome pure  ---------------------------------------------------------------------------------updateState :: CatchupState -> Location -> CatchupState-updateState (RegularCatchup stream _) (StreamEventNumber n) =-    RegularCatchup stream n-updateState (AllCatchup _) (StreamPosition p) = AllCatchup p-updateState x y = error $ "Unexpected input updateState: " <> show (x,y)+fetchAll :: Settings+         -> Int32 -- Batch size.+         -> Bool -- Resolve link tos.+         -> Maybe Credentials+         -> Position+         -> Code o (Slice Position)+fetchAll setts batch tos cred (Position com pre) =+    deconstruct $ fmap Left $+        readAllEvents setts com pre batch tos Forward cred  ---------------------------------------------------------------------------------sourceStream :: Settings-             -> Int32-             -> Bool-             -> CatchupState-             -> Maybe Credentials+sourceStream :: t+             -> (forall o. t -> Code o (Slice t))              -> Operation SubAction-sourceStream setts batch tos start cred = unfoldPlan start go+sourceStream seed iteratee = unfoldPlan seed go   where     go state = do-        s <- fetch setts batch tos state cred+        s <- iteratee state         traverse_ (yield . Submit) (sliceEvents s) -        when (sliceEOS s)-            stop--        return $ updateState state (sliceNext s)-----------------------------------------------------------------------------------catchupStreamName :: CatchupState -> Text-catchupStreamName (RegularCatchup stream _) = stream-catchupStreamName _ = ""-----------------------------------------------------------------------------------data CatchupOpResult =-    CatchupOpResult { catchupReadEvents :: ![ResolvedEvent]-                    , catchupEndOfStream :: !Bool-                    , catchupCheckpoint :: !Checkpoint-                    }+        case sliceNext s of+            Just newState -> pure newState+            Nothing       -> stop  ----------------------------------------------------------------------------------- | Stream catching up operation.-catchup :: Settings-        -> CatchupState-        -> Bool-        -> Maybe Int32+catchup :: forall t. Settings+        -> StreamId t+        -> t+        -> Bool        -- Resolve link tos.+        -> Maybe Int32 -- Batch size.         -> Maybe Credentials         -> Operation SubAction-catchup setts state tos batchSiz cred =-    sourceStream setts batch tos state cred <> volatile stream tos cred+catchup setts streamId from tos batchSiz cred =+    sourceStream from iteratee <> volatile streamId tos cred   where-    batch  = fromMaybe defaultBatchSize batchSiz-    stream = catchupStreamName state+    batch = fromMaybe defaultBatchSize batchSiz +    iteratee :: t -> Code o (Slice t)+    iteratee =+        case streamId of+            StreamName n -> fetchStream setts n batch tos cred+            All          -> fetchAll setts batch tos cred+ -------------------------------------------------------------------------------- fromReadResult :: Text-               -> ReadResult 'RegularStream a+               -> ReadResult EventNumber a                -> (a -> Code o x)                -> Code o x fromReadResult stream res k =
Database/EventStore/Internal/Operation/DeleteStream.hs view
@@ -61,6 +61,6 @@         OP_FORWARD_TIMEOUT        -> retry         OP_COMMIT_TIMEOUT         -> retry         OP_WRONG_EXPECTED_VERSION -> wrongVersion s v-        OP_STREAM_DELETED         -> streamDeleted s+        OP_STREAM_DELETED         -> streamDeleted $ StreamName s         OP_INVALID_TRANSACTION    -> invalidTransaction         OP_ACCESS_DENIED          -> accessDenied (StreamName s)
Database/EventStore/Internal/Operation/Read/Common.hs view
@@ -18,6 +18,7 @@ -------------------------------------------------------------------------------- import Control.Applicative import Data.Foldable+import Data.Maybe (isNothing) import Data.Monoid import Data.Traversable import Data.Int@@ -32,13 +33,13 @@  -------------------------------------------------------------------------------- -- | Enumeration detailing the possible outcomes of reading a stream.-data ReadResult       :: StreamType -> * -> * where+data ReadResult t a where     ReadSuccess       :: a -> ReadResult t a-    ReadNoStream      :: ReadResult 'RegularStream a-    ReadStreamDeleted :: Text -> ReadResult 'RegularStream a+    ReadNoStream      :: ReadResult EventNumber a+    ReadStreamDeleted :: StreamName -> ReadResult EventNumber a     ReadNotModified   :: ReadResult t a     ReadError         :: Maybe Text -> ReadResult t a-    ReadAccessDenied  :: StreamName -> ReadResult t a+    ReadAccessDenied  :: StreamId t -> ReadResult t a  -------------------------------------------------------------------------------- instance Eq a => Eq (ReadResult t a) where@@ -84,107 +85,43 @@  -------------------------------------------------------------------------------- -- | Gathers common slice operations.-class Slice a where-    type Loc a--    sliceEvents :: a -> [ResolvedEvent]-    -- ^ Gets slice's 'ResolvedEvent's.-    sliceDirection :: a -> ReadDirection-    -- ^ Gets slice's reading direction.-    sliceEOS :: a -> Bool-    -- ^ If the slice reaches the end of the stream.-    sliceFrom :: a -> Loc a-    -- ^ Gets the starting location of this slice.-    sliceNext :: a -> Loc a-    -- ^ Gets the next location of this slice.-    toSlice :: a -> SomeSlice-    -- ^ Returns a common view of a slice.+data Slice t+    = SliceEndOfStream+    | Slice ![ResolvedEvent] !(Maybe t)+    deriving Show  ----------------------------------------------------------------------------------- | Regular stream slice.-data StreamSlice =-    StreamSlice-    { sliceStream :: !Text-    , sliceLast   :: !Int64-    , _ssDir      :: !ReadDirection-    , _ssFrom     :: !Int64-    , _ssNext     :: !Int64-    , _ssEvents   :: ![ResolvedEvent]-    , _ssEOS      :: !Bool-    } deriving Show+-- | Empty slice.+emptySlice :: Slice t+emptySlice = SliceEndOfStream  ---------------------------------------------------------------------------------instance Slice StreamSlice where-    type Loc StreamSlice = Int64--    sliceEvents    = _ssEvents-    sliceDirection = _ssDir-    sliceEOS       = _ssEOS-    sliceFrom      = _ssFrom-    sliceNext      = _ssNext--    toSlice s =-        SomeSlice-        { __events = sliceEvents s-        , __eos    = sliceEOS s-        , __dir    = sliceDirection s-        , __from   = StreamEventNumber $ sliceFrom s-        , __next   = StreamEventNumber $ sliceNext s-        }+instance Functor Slice where+    fmap f SliceEndOfStream = SliceEndOfStream+    fmap f (Slice xs next)  = Slice xs (fmap f next)  ----------------------------------------------------------------------------------- | Represents a slice of the $all stream.-data AllSlice =-    AllSlice-    { _saFrom   :: !Position-    , _saNext   :: !Position-    , _saDir    :: !ReadDirection-    , _saEvents :: ![ResolvedEvent]-    , _saEOS    :: !Bool-    } deriving Show+-- | Gets slice's 'ResolvedEvents's.+sliceEvents :: Slice t -> [ResolvedEvent]+sliceEvents SliceEndOfStream = []+sliceEvents (Slice xs _)     = xs  ---------------------------------------------------------------------------------instance Slice AllSlice where-    type Loc AllSlice = Position--    sliceEvents    = _saEvents-    sliceDirection = _saDir-    sliceEOS       = _saEOS-    sliceFrom      = _saFrom-    sliceNext      = _saNext--    toSlice s =-        SomeSlice-        { __events = sliceEvents s-        , __eos    = sliceEOS s-        , __dir    = sliceDirection s-        , __from   = StreamPosition $ sliceFrom s-        , __next   = StreamPosition $ sliceNext s-        }+-- | If the slice has reached the end of the stream.+sliceEOS :: Slice t -> Bool+sliceEOS SliceEndOfStream = True+sliceEOS (Slice _ next)   = isNothing next  ---------------------------------------------------------------------------------data Location-    = StreamEventNumber !Int64-    | StreamPosition !Position-    deriving Show+-- | Gets the next location of this slice.+sliceNext :: Slice t -> Maybe t+sliceNext SliceEndOfStream = Nothing+sliceNext (Slice _ next)   = next  ---------------------------------------------------------------------------------data SomeSlice =-    SomeSlice-    { __events :: ![ResolvedEvent]-    , __eos    :: !Bool-    , __dir    :: !ReadDirection-    , __from   :: !Location-    , __next   :: !Location-    } deriving Show+-- | Regular stream slice.+type StreamSlice = Slice EventNumber  ---------------------------------------------------------------------------------instance Slice SomeSlice where-    type Loc SomeSlice = Location--    sliceEvents    = __events-    sliceDirection = __dir-    sliceEOS       = __eos-    sliceFrom      = __from-    sliceNext      = __next-    toSlice        = id+-- | Represents a slice of the $all stream.+type AllSlice = Slice Position
Database/EventStore/Internal/Operation/ReadAllEvents.hs view
@@ -57,10 +57,10 @@         es     = getField $ _Events resp         evts   = fmap newResolvedEventFromBuf es         eos    = null evts-        f_pos  = Position c_pos p_pos         n_pos  = Position nc_pos np_pos-        slice  = AllSlice f_pos n_pos dir evts eos+        slice  =+            if eos then SliceEndOfStream else Slice evts (Just n_pos)     case fromMaybe SUCCESS r of         ERROR         -> serverError err-        ACCESS_DENIED -> accessDenied AllStream+        ACCESS_DENIED -> accessDenied All         _             -> yield slice
Database/EventStore/Internal/Operation/ReadEvent.hs view
@@ -37,11 +37,11 @@ data ReadEvent     = ReadEventNotFound       { readEventStream :: !Text-      , readEventNumber :: !Int32+      , readEventNumber :: !Int64       }     | ReadEvent       { readEventStream   :: !Text-      , readEventNumber   :: !Int32+      , readEventNumber   :: !Int64       , readEventResolved :: !ResolvedEvent       } deriving Show @@ -49,10 +49,10 @@ -- | Read a specific event given event number operation. readEvent :: Settings           -> Text-          -> Int32+          -> Int64           -> Bool           -> Maybe Credentials-          -> Operation (ReadResult 'RegularStream ReadEvent)+          -> Operation (ReadResult EventNumber ReadEvent) readEvent Settings{..} s evtn tos cred = construct $ do     let msg = newRequest s evtn tos s_requireMaster     resp <- send readEventCmd readEventCompletedCmd cred msg@@ -64,7 +64,7 @@     case r of         NOT_FOUND      -> yield not_found         NO_STREAM      -> yield ReadNoStream-        STREAM_DELETED -> yield $ ReadStreamDeleted s+        STREAM_DELETED -> yield $ ReadStreamDeleted $ StreamName s         ERROR          -> yield (ReadError err)         ACCESS_DENIED  -> yield $ ReadAccessDenied $ StreamName s         SUCCESS        -> yield found
Database/EventStore/Internal/Operation/ReadEvent/Message.hs view
@@ -34,7 +34,7 @@ data Request     = Request       { _streamId       :: Required 1 (Value Text)-      , _eventNumber    :: Required 2 (Value Int32)+      , _eventNumber    :: Required 2 (Value Int64)       , _resolveLinkTos :: Required 3 (Value Bool)       , _requireMaster  :: Required 4 (Value Bool)       }@@ -45,7 +45,7 @@  -------------------------------------------------------------------------------- -- | 'Request' smart constructor.-newRequest :: Text -> Int32 -> Bool -> Bool -> Request+newRequest :: Text -> Int64 -> Bool -> Bool -> Request newRequest stream_id evt_num res_link_tos req_master =     Request     { _streamId       = putField stream_id
Database/EventStore/Internal/Operation/ReadStreamEvents.hs view
@@ -39,7 +39,7 @@                  -> Int32                  -> Bool                  -> Maybe Credentials-                 -> Operation (ReadResult 'RegularStream StreamSlice)+                 -> Operation (ReadResult EventNumber StreamSlice) readStreamEvents Settings{..} dir s st cnt tos cred = construct $ do     let req_cmd =             case dir of@@ -58,11 +58,13 @@         err   = getField $ _error resp         eos   = getField $ _endOfStream resp         nxt   = getField $ _nextNumber resp-        lst   = getField $ _lastNumber resp-        found = StreamSlice s lst dir st nxt evts eos+        found =+            if null evts && eos+            then SliceEndOfStream+            else Slice evts (if eos then Nothing else Just $ EventNumber nxt)     case r of         NO_STREAM      -> yield ReadNoStream-        STREAM_DELETED -> yield $ ReadStreamDeleted s+        STREAM_DELETED -> yield $ ReadStreamDeleted $ StreamName s         NOT_MODIFIED   -> yield ReadNotModified         ERROR          -> yield (ReadError err)         ACCESS_DENIED  -> yield $ ReadAccessDenied $ StreamName s
Database/EventStore/Internal/Operation/StreamMetadata.hs view
@@ -78,8 +78,8 @@ streamNotFound = InvalidOperation "Read metadata on an inexistant stream"  ---------------------------------------------------------------------------------onReadResult :: ReadResult 'RegularStream ReadEvent-             -> (Text -> Int32 -> ResolvedEvent -> Code o a)+onReadResult :: ReadResult EventNumber ReadEvent+             -> (Text -> Int64 -> ResolvedEvent -> Code o a)              -> Code o a onReadResult (ReadSuccess r) k =     case r of
Database/EventStore/Internal/Operation/Transaction.hs view
@@ -54,7 +54,7 @@         OP_FORWARD_TIMEOUT        -> retry         OP_COMMIT_TIMEOUT         -> retry         OP_WRONG_EXPECTED_VERSION -> wrongVersion stream exp_v-        OP_STREAM_DELETED         -> streamDeleted stream+        OP_STREAM_DELETED         -> streamDeleted $ StreamName stream         OP_INVALID_TRANSACTION    -> invalidTransaction         OP_ACCESS_DENIED          -> accessDenied $ StreamName stream         OP_SUCCESS                -> yield tid@@ -78,7 +78,7 @@         OP_FORWARD_TIMEOUT        -> retry         OP_COMMIT_TIMEOUT         -> retry         OP_WRONG_EXPECTED_VERSION -> wrongVersion stream exp_v-        OP_STREAM_DELETED         -> streamDeleted stream+        OP_STREAM_DELETED         -> streamDeleted $ StreamName stream         OP_INVALID_TRANSACTION    -> invalidTransaction         OP_ACCESS_DENIED          -> accessDenied $ StreamName stream         OP_SUCCESS                -> yield ()@@ -107,7 +107,7 @@         OP_FORWARD_TIMEOUT        -> retry         OP_COMMIT_TIMEOUT         -> retry         OP_WRONG_EXPECTED_VERSION -> wrongVersion stream exp_v-        OP_STREAM_DELETED         -> streamDeleted stream+        OP_STREAM_DELETED         -> streamDeleted $ StreamName stream         OP_INVALID_TRANSACTION    -> invalidTransaction         OP_ACCESS_DENIED          -> accessDenied $ StreamName stream         OP_SUCCESS                -> yield res
Database/EventStore/Internal/Operation/Volatile.hs view
@@ -20,13 +20,16 @@ import Database.EventStore.Internal.Operation import Database.EventStore.Internal.Prelude import Database.EventStore.Internal.Settings+import Database.EventStore.Internal.Stream import Database.EventStore.Internal.Subscription.Message import Database.EventStore.Internal.Subscription.Types import Database.EventStore.Internal.Types  ---------------------------------------------------------------------------------volatile :: Text -> Bool -> Maybe Credentials -> Operation SubAction-volatile stream tos cred = construct (issueRequest stream tos cred)+volatile :: StreamId t -> Bool -> Maybe Credentials -> Operation SubAction+volatile streamId tos cred = construct (issueRequest stream tos cred)+  where+    stream = streamIdRaw streamId  -------------------------------------------------------------------------------- issueRequest :: Text -> Bool -> Maybe Credentials -> Code SubAction ()
Database/EventStore/Internal/Operation/WriteEvents.hs view
@@ -55,6 +55,6 @@         OP_FORWARD_TIMEOUT        -> retry         OP_COMMIT_TIMEOUT         -> retry         OP_WRONG_EXPECTED_VERSION -> wrongVersion s v-        OP_STREAM_DELETED         -> streamDeleted s+        OP_STREAM_DELETED         -> streamDeleted $ StreamName s         OP_INVALID_TRANSACTION    -> invalidTransaction         OP_ACCESS_DENIED          -> accessDenied (StreamName s)
Database/EventStore/Internal/Stream.hs view
@@ -17,26 +17,34 @@  -------------------------------------------------------------------------------- import Database.EventStore.Internal.Prelude+import Database.EventStore.Internal.Types  ----------------------------------------------------------------------------------- | A stream can either point to $all or a regular one.-data StreamType = All | RegularStream deriving (Eq, Ord)+-- | Represents a regular stream name or $all stream.+data StreamId loc where+    StreamName :: Text -> StreamId EventNumber+    All        :: StreamId Position  ----------------------------------------------------------------------------------- | Represents a regular stream name or $all stream.-data StreamName = StreamName Text | AllStream deriving Eq+-- | If the stream is the $all stream.+isAllStream :: StreamId t -> Bool+isAllStream StreamName{} = False+isAllStream _            = True  ---------------------------------------------------------------------------------streamNameRaw :: StreamName -> Text-streamNameRaw (StreamName n) = n-streamNameRaw AllStream      = ""+instance Eq (StreamId t) where+  StreamName n == StreamName v = n == v+  All          == _            = True  ---------------------------------------------------------------------------------instance Show StreamName where-    show (StreamName t) = show t-    show AllStream      = "$all"+type StreamName = StreamId EventNumber  ---------------------------------------------------------------------------------instance IsString StreamName where-    fromString "$all" = AllStream-    fromString stream = StreamName $ pack stream+streamIdRaw :: StreamId t -> Text+streamIdRaw (StreamName n) = n+streamIdRaw All            = ""++--------------------------------------------------------------------------------+instance Show (StreamId t) where+    show (StreamName n) = show n+    show All            = "$all"
Database/EventStore/Internal/Subscription/Api.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE DeriveDataTypeable  #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DeriveDataTypeable     #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE ScopedTypeVariables    #-} -------------------------------------------------------------------------------- -- | -- Module : Database.EventStore.Internal.Subscription.Api@@ -46,13 +47,15 @@   -- | Returns the runtime details of a subscription.   getSubscriptionDetailsSTM :: s -> STM SubDetails -  -- | Get subscription stream.-  subscriptionStream :: s -> StreamName-   -- | Asynchronously unsubscribe from the the stream.   unsubscribe :: s -> IO ()  --------------------------------------------------------------------------------+-- | Returns the stream of a subscription.+class SubscriptionStream s t | t -> s where+    subscriptionStream :: s -> StreamId t++-------------------------------------------------------------------------------- -- | Awaits for the next event. nextEvent :: Subscription s => s -> IO ResolvedEvent nextEvent s = atomically $ do@@ -105,14 +108,6 @@   for_ outcome $ \details -> do     let pkg = createUnsubscribePackage (subId details)     publishWith pub (SendPackage pkg)------------------------------------------------------------------------------------- | If the subscription is on the $all stream.-isSubscribedToAll :: Subscription s => s -> Bool-isSubscribedToAll s =-  case subscriptionStream s of-    StreamName{} -> False-    _            -> True  -------------------------------------------------------------------------------- -- | Gets the ID of the subscription.
Database/EventStore/Internal/Subscription/Catchup.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE RecordWildCards     #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -16,6 +18,7 @@  -------------------------------------------------------------------------------- import Control.Monad.Fix+import Safe (fromJustNote)  -------------------------------------------------------------------------------- import Database.EventStore.Internal.Callback@@ -38,28 +41,24 @@   | Closed (Either SomeException SubDropReason)  ---------------------------------------------------------------------------------data CatchupTrack-  = CatchupRegular !(Maybe Int64)-  | CatchupAll !(Maybe Position)-----------------------------------------------------------------------------------catchupTrack :: CatchupState -> CatchupTrack-catchupTrack RegularCatchup{} = CatchupRegular Nothing-catchupTrack AllCatchup{}     = CatchupAll Nothing-----------------------------------------------------------------------------------receivedAlready :: CatchupTrack -> ResolvedEvent -> Bool-receivedAlready (CatchupRegular old) e =-  maybe False (resolvedEventOriginalEventNumber e <=) old-receivedAlready (CatchupAll old) e =-  fromMaybe False ((<=) <$> resolvedEventPosition e <*> old)+receivedAlready :: StreamId t -> t -> ResolvedEvent -> Bool+receivedAlready StreamName{} old e =+    EventNumber (resolvedEventOriginalEventNumber e) < old+receivedAlready All old e =+    let pos =+            fromJustNote+                "Position is always defined when reading events from $all stream"+                $ resolvedEventPosition e in+    pos < old  ---------------------------------------------------------------------------------updateTrack :: ResolvedEvent -> CatchupTrack -> CatchupTrack-updateTrack e (CatchupRegular _) =-  CatchupRegular (Just $ resolvedEventOriginalEventNumber e)-updateTrack e (CatchupAll _) =-  CatchupAll (resolvedEventPosition e)+nextTarget :: StreamId t -> ResolvedEvent -> t+nextTarget StreamName{} e =+    EventNumber (resolvedEventOriginalEventNumber e)+nextTarget All e =+    fromJustNote+        "Position is always defined when reading events from $all stream"+        $ resolvedEventPosition e  -------------------------------------------------------------------------------- -- | This kind of subscription specifies a starting point, in the form of an@@ -71,16 +70,16 @@ --   events in it, the subscriber can expect to see events 51 through 100, and --   then any events subsequently written until such time as the subscription is --   dropped or closed.-data CatchupSubscription =+data CatchupSubscription t =   CatchupSubscription { _catchupExec   :: Exec-                      , _catchupStream :: StreamName+                      , _catchupStream :: StreamId t                       , _catchupPhase  :: TVar Phase-                      , _catchupTrack  :: TVar CatchupTrack+                      , _catchupTrack  :: TVar t                       , _catchupNext   :: STM (Maybe ResolvedEvent)                       }  ---------------------------------------------------------------------------------instance Subscription CatchupSubscription where+instance Subscription (CatchupSubscription t) where   nextEventMaybeSTM = _catchupNext    getSubscriptionDetailsSTM s = do@@ -90,34 +89,27 @@       Closed r        -> throwClosed r       _               -> retrySTM -  subscriptionStream = _catchupStream-   unsubscribe s = subUnsubscribe (_catchupExec s) s  ---------------------------------------------------------------------------------streamName :: CatchupState -> StreamName-streamName (RegularCatchup stream _) = StreamName stream-streamName _                         = "$all"-----------------------------------------------------------------------------------streamText :: StreamName -> Text-streamText (StreamName s) = s-streamText _              = ""+instance SubscriptionStream (CatchupSubscription t) t where+    subscriptionStream = _catchupStream  -------------------------------------------------------------------------------- newCatchupSubscription :: Exec                        -> Bool                        -> Maybe Int32                        -> Maybe Credentials-                       -> CatchupState-                       -> IO CatchupSubscription-newCatchupSubscription exec tos batch cred state = do+                       -> StreamId t+                       -> t+                       -> IO (CatchupSubscription t)+newCatchupSubscription exec tos batch cred streamId seed = do   phaseVar <- newTVarIO CatchingUp   queue    <- newTQueueIO-  track    <- newTVarIO $ catchupTrack state+  track    <- newTVarIO seed -  let stream = streamName state-      sub = CatchupSubscription exec stream phaseVar track $ do+  let stream = streamIdRaw streamId+      sub = CatchupSubscription exec streamId phaseVar track $ do         p       <- readTVar phaseVar         isEmpty <- isEmptyTQueue queue         if isEmpty@@ -132,7 +124,7 @@           Just opE ->             case opE of               StreamNotFound{} -> do-                let op = volatile (streamText stream) tos cred+                let op = volatile streamId tos cred                 publishWith exec (SubmitOperation cb op)               _ -> atomically $ writeTVar phaseVar (Closed $ Left e)           _ -> atomically $ writeTVar phaseVar (Closed $ Left e)@@ -143,29 +135,18 @@             atomically $ writeTVar phaseVar (Closed $ Right r)           Submit e -> atomically $ do             tracker <- readTVar track-            unless (receivedAlready tracker e) $ do-              writeTVar track (updateTrack e tracker)+            unless (receivedAlready streamId tracker e) $ do+              writeTVar track (nextTarget streamId e)               writeTQueue queue e           ConnectionReset -> do-            tpe <- readTVarIO track-            let newState =-                  case tpe of-                    CatchupRegular old ->-                      case old of-                        Just n -> RegularCatchup (streamText stream) n-                        _      -> state-                    CatchupAll old ->-                      case old of-                        Just p -> AllCatchup p-                        _      -> state--                newOp = catchup (execSettings exec) newState tos batch cred+            chk <- readTVarIO track+            let newOp = catchup (execSettings exec) streamId chk tos batch cred              newCb <- mfix $ \self -> newCallback (callback self)             publishWith exec (SubmitOperation newCb newOp)    cb <- mfix $ \self -> newCallback (callback self)-  let op = catchup (execSettings exec) state tos batch cred+  let op = catchup (execSettings exec) streamId seed tos batch cred   publishWith exec (SubmitOperation cb op)   return sub @@ -176,17 +157,17 @@  -------------------------------------------------------------------------------- -- | Non blocking version of `waitTillCatchup`.-hasCaughtUp :: CatchupSubscription -> IO Bool+hasCaughtUp :: CatchupSubscription t -> IO Bool hasCaughtUp sub = atomically $ hasCaughtUpSTM sub  -------------------------------------------------------------------------------- -- | Waits until 'CatchupSubscription' subscription catch-up its stream.-waitTillCatchup :: CatchupSubscription -> IO ()+waitTillCatchup :: CatchupSubscription t -> IO () waitTillCatchup sub = atomically $ unlessM (hasCaughtUpSTM sub) retrySTM  -------------------------------------------------------------------------------- -- | Like 'hasCaughtUp' but lives in 'STM' monad.-hasCaughtUpSTM :: CatchupSubscription -> STM Bool+hasCaughtUpSTM :: CatchupSubscription t -> STM Bool hasCaughtUpSTM CatchupSubscription{..} = do   p <- readTVar _catchupPhase   case p of
Database/EventStore/Internal/Subscription/Persistent.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RecordWildCards   #-} -------------------------------------------------------------------------------- -- | -- Module : Database.EventStore.Internal.Subscription.Persistent@@ -62,11 +63,13 @@           Right r -> throwSTM (SubscriptionClosed $ Just r)           Left e  -> throwSTM e -  subscriptionStream = _perStream-   unsubscribe s = subUnsubscribe (_perExec s) s  --------------------------------------------------------------------------------+instance SubscriptionStream PersistentSubscription EventNumber where+    subscriptionStream = _perStream++-------------------------------------------------------------------------------- newPersistentSubscription :: Exec                           -> Text                           -> StreamName@@ -77,7 +80,7 @@   phaseVar <- newTVarIO Pending   queue    <- newTQueueIO -  let name = streamNameRaw stream+  let name = streamIdRaw stream       sub  = PersistentSubscription exec stream cred phaseVar $ do         p       <- readTVar phaseVar         isEmpty <- isEmptyTQueue queue
Database/EventStore/Internal/Subscription/Regular.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleInstances #-} -------------------------------------------------------------------------------- -- | -- Module : Database.EventStore.Internal.Subscription.Regular@@ -34,15 +35,15 @@ --   events in it when a subscriber connects, the subscriber can expect to see --   event number 101 onwards until the time the subscription is closed or --   dropped.-data RegularSubscription =+data RegularSubscription t =   RegularSubscription { _regExec   :: Exec-                      , _regStream :: StreamName+                      , _regStream :: StreamId t                       , _regPhase  :: TVar Phase                       , _regNext   :: STM (Maybe ResolvedEvent)                       }  ---------------------------------------------------------------------------------instance Subscription RegularSubscription where+instance Subscription (RegularSubscription t) where   nextEventMaybeSTM = _regNext    getSubscriptionDetailsSTM s = do@@ -55,22 +56,23 @@           Right r -> throwSTM (SubscriptionClosed $ Just r)           Left e  -> throwSTM e -  subscriptionStream = _regStream-   unsubscribe s = subUnsubscribe (_regExec s) s  --------------------------------------------------------------------------------+instance SubscriptionStream (RegularSubscription t) t where+    subscriptionStream = _regStream++-------------------------------------------------------------------------------- newRegularSubscription :: Exec-                       -> StreamName+                       -> StreamId t                        -> Bool                        -> Maybe Credentials-                       -> IO RegularSubscription-newRegularSubscription exec stream tos cred = do+                       -> IO (RegularSubscription t)+newRegularSubscription exec streamId tos cred = do   phaseVar <- newTVarIO Pending   queue    <- newTQueueIO -  let name = streamNameRaw stream-      sub  = RegularSubscription exec stream phaseVar $ do+  let sub = RegularSubscription exec streamId phaseVar $ do         p       <- readTVar phaseVar         isEmpty <- isEmptyTQueue queue         if isEmpty@@ -99,5 +101,5 @@             writeTVar phaseVar (Closed $ Right SubAborted)    cb <- newCallback callback-  publishWith exec (SubmitOperation cb (volatile name tos cred))+  publishWith exec (SubmitOperation cb (volatile streamId tos cred))   return sub
Database/EventStore/Internal/Types.hs view
@@ -24,6 +24,7 @@ import Data.Maybe import Data.Monoid (Endo(..)) import Foreign.C.Types (CTime(..))+import Numeric.Natural (Natural)  -------------------------------------------------------------------------------- import           Control.Monad.Reader@@ -234,6 +235,46 @@ streamExists = StreamExists  --------------------------------------------------------------------------------+-- | Represents an event position within a stream.+newtype EventNumber = EventNumber Int64 deriving (Eq, Ord, Show)++--------------------------------------------------------------------------------+-- | The first event in a stream.+streamStart :: EventNumber+streamStart = EventNumber 0++--------------------------------------------------------------------------------+-- | The last event in the stream.+streamEnd :: EventNumber+streamEnd = EventNumber (-1)++--------------------------------------------------------------------------------+-- | the Nth event of a stream.+eventNumber :: Natural -> EventNumber+eventNumber n = EventNumber (fromIntegral n)++--------------------------------------------------------------------------------+-- | Returns a 'EventNumber from a raw 'Int64'.+rawEventNumber :: Int64 -> EventNumber+rawEventNumber = EventNumber++--------------------------------------------------------------------------------+-- | Returns a raw 'Int64' from an 'EventNumber'.+eventNumberToInt64 :: EventNumber -> Int64+eventNumberToInt64 (EventNumber n) = n++--------------------------------------------------------------------------------+-- | Determines whether any link event encountered in the stream will be+--   resolved. See the discussion for more information:+--   https://eventstore.org/docs/dotnet-api/reading-events/index.html#resolvedevent+data ResolveLink = ResolveLink | NoResolveLink deriving (Show, Eq)++--------------------------------------------------------------------------------+resolveLinkToBool :: ResolveLink -> Bool+resolveLinkToBool ResolveLink   = True+resolveLinkToBool NoResolveLink = False++-------------------------------------------------------------------------------- -- EventStore Messages -------------------------------------------------------------------------------- -- | Serializes form of an 'Event'.@@ -997,7 +1038,7 @@     = StreamMetadataResult       { streamMetaResultStream :: !Text         -- ^ The name of the stream.-      , streamMetaResultVersion :: !Int32+      , streamMetaResultVersion :: !Int64         -- ^ The version of the metadata format.       , streamMetaResultData :: !StreamMetadata         -- ^ A 'StreamMetadata' containing user-specified metadata.
+ Database/EventStore/Streaming.hs view
@@ -0,0 +1,164 @@+{-# LANGUAGE LambdaCase #-}+--------------------------------------------------------------------------------+-- |+-- Module    :  Database.EventStore.Streaming+-- Copyright :  (C) 2018 Yorick Laupa+-- License   :  (see the file LICENSE)+-- Maintainer:  Yorick Laupa <yo.eight@gmail.com>+-- Stability :  experimental+-- Portability: non-portable+--+--------------------------------------------------------------------------------+module Database.EventStore.Streaming+    ( ReadError(..)+    , readThroughForward+    , readThroughBackward+    , throwOnError+    ) where++--------------------------------------------------------------------------------+import Control.Exception (Exception, throwIO)+import Data.Int (Int32)+import Data.Maybe (fromMaybe)+import Data.Typeable (Typeable)+import Prelude++--------------------------------------------------------------------------------+import           Control.Concurrent.Async.Lifted (wait)+import           Control.Monad.Except (ExceptT, throwError, runExceptT)+import           Data.Text (Text)+import           Streaming+import qualified Streaming.Prelude as Streaming++--------------------------------------------------------------------------------+import qualified Database.EventStore as ES+import           Database.EventStore.Internal.Operation.Read.Common (emptySlice)+import           Database.EventStore.Internal.Types (EventNumber(..))++--------------------------------------------------------------------------------+data ReadError t+    = StreamDeleted !ES.StreamName+    | ReadError !(Maybe Text)+    | AccessDenied !(ES.StreamId t)+    deriving Show++--------------------------------------------------------------------------------+instance (Show t, Typeable t) => Exception (ReadError t)++--------------------------------------------------------------------------------+data Fetch t = FetchError !(ReadError t) | Fetch !(ES.Slice t)++--------------------------------------------------------------------------------+toFetch :: ES.ReadResult t (ES.Slice t) -> Fetch t+toFetch ES.ReadNoStream          = Fetch ES.emptySlice+toFetch ES.ReadNotModified       = Fetch ES.emptySlice+toFetch (ES.ReadStreamDeleted n) = FetchError (StreamDeleted n)+toFetch (ES.ReadError e)         = FetchError (ReadError e)+toFetch (ES.ReadAccessDenied n)  = FetchError (AccessDenied n)+toFetch (ES.ReadSuccess s)       = Fetch s++--------------------------------------------------------------------------------+handleBatchResult :: ES.StreamId t -> ES.BatchResult t -> Fetch t+handleBatchResult ES.StreamName{} = toFetch+handleBatchResult ES.All          = Fetch++--------------------------------------------------------------------------------+data State t = Need t | Fetched ![ES.ResolvedEvent] !(Maybe t)++--------------------------------------------------------------------------------+streaming :: (t -> IO (Fetch t))+          -> t+          -> Stream (Of ES.ResolvedEvent) (ExceptT (ReadError t) IO) ()+streaming iteratee = Streaming.unfoldr go . Need+  where+      go (Fetched buffer next) =+          case buffer of+            e:rest -> pure (Right (e, Fetched rest next))+            []     -> maybe stop (go . Need) next+      go (Need pos) = do+          liftIO (iteratee pos) >>= \case+              FetchError e -> throwError e+              Fetch s      ->+                  case s of+                      ES.SliceEndOfStream -> stop+                      ES.Slice xs next    -> go (Fetched xs next)++      stop = pure (Left ())++--------------------------------------------------------------------------------+-- | Returns an iterator able to consume a stream entirely. When reading forward,+--   the iterator ends when the last stream's event is reached.+readThroughForward :: ES.Connection+                   -> ES.StreamId t+                   -> ES.ResolveLink+                   -> t+                   -> Maybe Int32+                   -> Maybe ES.Credentials+                   -> Stream (Of ES.ResolvedEvent) (ExceptT (ReadError t) IO) ()+readThroughForward conn = readThrough conn ES.Forward++--------------------------------------------------------------------------------+-- | Returns an iterator able to consume a stream entirely. When reading backward,+--   the iterator ends when the first stream's event is reached.+readThroughBackward :: ES.Connection+                    -> ES.StreamId t+                    -> ES.ResolveLink+                    -> t+                    -> Maybe Int32+                    -> Maybe ES.Credentials+                    -> Stream (Of ES.ResolvedEvent) (ExceptT (ReadError t) IO) ()+readThroughBackward conn = readThrough conn ES.Backward++--------------------------------------------------------------------------------+-- | Throws an exception in case 'ExceptT' is a 'Left'.+throwOnError :: (Show t, Typeable t)+             => Stream (Of a) (ExceptT (ReadError t) IO) ()+             -> Stream (Of a) IO ()+throwOnError = hoist go+  where+    go action =+        runExceptT action >>= \case+            Left e  -> throwIO e+            Right a -> pure a++--------------------------------------------------------------------------------+readThrough :: ES.Connection+            -> ES.ReadDirection+            -> ES.StreamId t+            -> ES.ResolveLink+            -> t+            -> Maybe Int32+            -> Maybe ES.Credentials+            -> Stream (Of ES.ResolvedEvent) (ExceptT (ReadError t) IO) ()+readThrough conn dir streamId lnk from sizMay cred = streaming iteratee from+  where+    batchSize = fromMaybe 500 sizMay++    iteratee =+        case dir of+            ES.Forward  -> readForward conn streamId batchSize lnk cred+            ES.Backward -> readBackward conn streamId batchSize lnk cred++--------------------------------------------------------------------------------+readForward :: ES.Connection+            -> ES.StreamId t+            -> Int32+            -> ES.ResolveLink+            -> Maybe ES.Credentials+            -> t+            -> IO (Fetch t)+readForward conn streamId siz lnk creds start =+    fmap (handleBatchResult streamId) . wait =<<+        ES.readEventsForward conn streamId start siz lnk creds++--------------------------------------------------------------------------------+readBackward :: ES.Connection+             -> ES.StreamId t+             -> Int32+             -> ES.ResolveLink+             -> Maybe ES.Credentials+             -> t+             -> IO (Fetch t)+readBackward conn streamId siz lnk creds start =+    fmap (handleBatchResult streamId) . wait =<<+        ES.readEventsBackward conn streamId start siz lnk creds
README.md view
@@ -9,9 +9,9 @@ Requirements ============   * 64bits system-  * GHC        >= 7.8.3+  * GHC        >= 8.0.3   * Cabal      >= 1.18-  * EventStore >= 3.0.0 (>= 3.1.0 if you want competing consumers).+  * EventStore >= 4  *Note: If you use this client version >= to `1.1`, it will only supports EventStore >= 4.0.0.* @@ -45,8 +45,6 @@ How to use ========== -This code snippet showcases client version >= `1.1`.- ```haskell {-# LANGUAGE OverloadedStrings #-} -- That library uses `Text` pervasively. This pragma permits to use                                    -- String literal when a Text is needed.@@ -74,7 +72,7 @@         evt = createEvent "programming" Nothing (withJson js)      -- Appends an event to a stream named `languages`.-    as <- sendEvent conn "languages" anyVersion evt Nothing+    as <- sendEvent conn (StreamName "languages") anyVersion evt Nothing      -- EventStore interactions are fundamentally asynchronous. Nothing requires you to wait     -- for the completion of an operation, but it's good to know if something went wrong.
eventstore.cabal view
@@ -1,26 +1,27 @@--- This file has been generated from package.yaml by hpack version 0.28.2.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.1. -- -- see: https://github.com/sol/hpack ----- hash: efad84983fbffd630c221007e541d0a71ec04435a4d4e1aa642cc25e5108ccf0+-- hash: 397c16fc115765cfccc8c21c8b7133555d40e98546632200395b77c3551720c8  name:           eventstore-version:        1.1.6+version:        1.2.0 synopsis:       EventStore TCP Client description:    EventStore TCP Client <https://eventstore.org> category:       Database-homepage:       https://gitlab.com/YoEight/eventstore-hs.git+homepage:       https://gitlab.com/YoEight/eventstore-hs author:         Yorick Laupa maintainer:     yo.eight@gmail.com copyright:      Yorick Laupa license:        BSD3 license-file:   LICENSE-tested-with:    GHC >= 7.8 && < 8.6+tested-with:    GHC >= 7.8 && <= 8.6 build-type:     Simple-cabal-version:  >= 1.10 extra-source-files:-    CHANGELOG.markdown     README.md+    CHANGELOG.markdown  source-repository head   type: git@@ -29,6 +30,7 @@ library   exposed-modules:       Database.EventStore+      Database.EventStore.Streaming       Database.EventStore.Internal.Test   other-modules:       Database.EventStore.Internal.Callback@@ -94,7 +96,7 @@     , cereal >=0.4 && <0.6     , clock     , connection ==0.2.*-    , containers ==0.5.*+    , containers     , dns >=3.0.1     , dotnet-timespan     , ekg-core@@ -112,10 +114,12 @@     , mtl     , protobuf >=0.2.1.1 && <0.3     , random ==1.*+    , safe     , safe-exceptions     , semigroups >=0.5     , stm     , stm-chans+    , streaming     , text     , time >=1.4     , transformers-base@@ -157,10 +161,12 @@     , monad-control     , mono-traversable ==1.*     , protobuf+    , safe     , safe-exceptions     , semigroups     , stm     , stm-chans+    , streaming     , tasty     , tasty-hspec     , tasty-hunit
tests/Test/Integration/Tests.hs view
@@ -22,6 +22,7 @@ import Data.Maybe (fromMaybe) import Data.UUID hiding (null) import Data.UUID.V4+import qualified Streaming.Prelude as Streaming import System.Environment (lookupEnv) import Test.Tasty.HUnit import Test.Tasty.Hspec@@ -30,7 +31,8 @@ import Database.EventStore     ( SubscriptionClosed(..)     , ReadResult(..)-    , StreamName(..)+    , StreamId(..)+    , StreamName     , Slice(..)     , ConnectionType(..)     , Connection@@ -50,10 +52,8 @@     , waitUnsubscribeConfirmed     , subscribeFrom     , waitTillCatchup-    , readAllEventsBackward-    , readAllEventsForward-    , readStreamEventsBackward-    , readStreamEventsForward+    , readEventsBackward+    , readEventsForward     , subscribe     , connect     , waitTillClosed@@ -63,6 +63,7 @@     , transactionWrite     , deleteStream     , transactionCommit+    , sliceEvents     ) import Database.EventStore.Internal.Test hiding     ( Connection(..)@@ -75,6 +76,7 @@     , transactionCommit     , i     )+import Database.EventStore.Streaming import Test.Common  --------------------------------------------------------------------------------@@ -116,6 +118,8 @@     it "deletes a persistent subscription" deletePersistentTest     it "connects to a persistent subscription" connectToPersistentTest     it "set MaxAge metadata correctly" maxAgeTest+    it "streams regular stream (forward)" streamRegularStreamForwardTest+    it "streams regular stream (backward)" streamRegularStreamBackwardTest  -------------------------------------------------------------------------------- freshStreamId :: IO StreamName@@ -141,7 +145,7 @@         evt = createEvent "foo" Nothing $ withJson js     as <- sendEvent conn stream anyVersion evt Nothing     _  <- wait as-    bs <- readEvent conn stream 0 False Nothing+    bs <- readEvent conn stream streamStart NoResolveLink Nothing     rs <- wait bs     case rs of         ReadSuccess re ->@@ -172,13 +176,13 @@         evt = createEvent "foo" Nothing $ withJson js     t  <- startTransaction conn stream anyVersion Nothing >>= wait     _  <- transactionWrite t [evt] Nothing >>= wait-    rs <- readEvent conn stream 0 False Nothing >>= wait+    rs <- readEvent conn stream streamStart NoResolveLink Nothing >>= wait     case rs of         ReadNoStream -> return ()         e -> fail $ "transaction-test stream is supposed to not exist "                   <> show e     _   <- transactionCommit t Nothing >>= wait-    rs2 <- readEvent conn stream 0 False Nothing >>= wait+    rs2 <- readEvent conn stream streamStart NoResolveLink Nothing >>= wait     case rs2 of         ReadSuccess re ->             case re of@@ -200,7 +204,7 @@               ]         evts = fmap (createEvent "foo" Nothing . withJson) jss     _  <- sendEvents conn stream anyVersion evts Nothing >>= wait-    rs <- readStreamEventsForward conn stream 0 10 False Nothing >>= wait+    rs <- readEventsForward conn stream streamStart 10 NoResolveLink Nothing >>= wait     case rs of         ReadSuccess sl -> do             let jss_evts = catMaybes $ fmap resolvedEventDataAsJson@@ -216,8 +220,9 @@               , object [ "bar" .= True]               ]         evts = fmap (createEvent "foo" Nothing . withJson) jss-    _  <- sendEvents conn "read-backward-test" anyVersion evts Nothing >>= wait-    rs <- readStreamEventsBackward conn "read-backward-test" 2 10 False Nothing >>= wait+    _  <- sendEvents conn (StreamName "read-backward-test") anyVersion evts Nothing >>= wait+    let startFrom = eventNumber 2+    rs <- readEventsBackward conn (StreamName "read-backward-test") startFrom 10 NoResolveLink Nothing >>= wait     case rs of         ReadSuccess sl -> do             let jss_evts = catMaybes $ fmap resolvedEventDataAsJson@@ -228,13 +233,13 @@ -------------------------------------------------------------------------------- readAllEventsForwardTest :: Connection -> IO () readAllEventsForwardTest conn = do-    sl <- readAllEventsForward conn positionStart 3 False Nothing >>= wait+    sl <- readEventsForward conn All positionStart 3 NoResolveLink Nothing >>= wait     assertEqual "Events is not empty" False (null $ sliceEvents sl)  -------------------------------------------------------------------------------- readAllEventsBackwardTest :: Connection -> IO () readAllEventsBackwardTest conn = do-    sl <- readAllEventsBackward conn positionEnd 3 False Nothing >>= wait+    sl <- readEventsBackward conn All positionEnd 3 NoResolveLink Nothing >>= wait     assertEqual "Events is not empty" False (null $ sliceEvents sl)  --------------------------------------------------------------------------------@@ -247,7 +252,7 @@               , object [ "bar" .= True]               ]         evts = fmap (createEvent "foo" Nothing . withJson) jss-    sub  <- subscribe conn stream False Nothing+    sub  <- subscribe conn stream NoResolveLink Nothing     _    <- waitConfirmation sub     _    <- sendEvents conn stream anyVersion evts Nothing >>= wait     let loop 3 = return []@@ -281,7 +286,7 @@         evts   = fmap (createEvent "foo" Nothing . withJson) jss         evts2  = fmap (createEvent "foo" Nothing . withJson) jss2     _   <- sendEvents conn stream anyVersion evts Nothing >>= wait-    sub <- subscribeFrom conn stream False Nothing (Just 1) Nothing+    sub <- subscribeFrom conn stream NoResolveLink Nothing (Just 1) Nothing     _   <- waitConfirmation sub     _   <- sendEvents conn stream anyVersion evts2 Nothing >>= wait @@ -316,7 +321,7 @@ subscribeFromNoStreamTest :: Connection -> IO () subscribeFromNoStreamTest conn = do   stream <- freshStreamId-  sub <- subscribeFrom conn stream False Nothing Nothing Nothing+  sub <- subscribeFrom conn stream NoResolveLink Nothing Nothing Nothing   let loop [] = do           m <- nextEventMaybe sub           case m of@@ -456,3 +461,49 @@             assertEqual "Should have equal timespan" (Just timespan)             (streamMetadataMaxAge m)         _ -> fail $ "Stream " <> show stream <> " doesn't exist"++--------------------------------------------------------------------------------+generateEvents :: Int -> [Value]+generateEvents n = take n $ fmap toObj [1..]++--------------------------------------------------------------------------------+toObj :: Int -> Value+toObj n = object [ pack (show n) .= n ]++--------------------------------------------------------------------------------+streamRegularStreamForwardTest :: Connection -> IO ()+streamRegularStreamForwardTest conn = do+    stream <- freshStreamId++    let jss  = generateEvents 10+        evts = fmap (createEvent "foo" Nothing . withJson) jss+        src = throwOnError $ readThroughForward conn stream NoResolveLink streamStart (Just 1) Nothing++    _ <- sendEvents conn stream anyVersion evts Nothing >>= wait+    rest <- Streaming.foldM_ check (pure [1..10]) pure src+    assertEqual "Should be empty" [] rest+  where+    check (x:xs) e =+        case resolvedEventDataAsJson e of+            Just e | e == toObj x -> pure xs+                   | otherwise    -> fail "Out of order event's appeared (stream)"+            _ -> fail "Can't deserialized event"++--------------------------------------------------------------------------------+streamRegularStreamBackwardTest :: Connection -> IO ()+streamRegularStreamBackwardTest conn = do+    stream <- freshStreamId++    let jss  = generateEvents 10+        evts = fmap (createEvent "foo" Nothing . withJson) jss+        src = throwOnError $ readThroughBackward conn stream NoResolveLink streamEnd (Just 1) Nothing++    _ <- sendEvents conn stream anyVersion evts Nothing >>= wait+    rest <- Streaming.foldM_ check (pure $ reverse [1..10]) pure src+    assertEqual "Should be empty" [] rest+  where+    check (x:xs) e =+        case resolvedEventDataAsJson e of+            Just e | e == toObj x -> pure xs+                   | otherwise    -> fail "Out of order event's appeared (stream)"+            _ -> fail "Can't deserialized event"