{-# LANGUAGE DataKinds       #-}
{-# LANGUAGE GADTs           #-}
{-# LANGUAGE KindSignatures  #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies    #-}
--------------------------------------------------------------------------------
-- |
-- Module : Database.EventStore.Internal.Operation.Transaction
-- Copyright : (C) 2015 Yorick Laupa
-- License : (see the file LICENSE)
--
-- Maintainer : Yorick Laupa <yo.eight@gmail.com>
-- Stability : provisional
-- Portability : non-portable
--
--------------------------------------------------------------------------------
module Database.EventStore.Internal.Operation.Transaction
    ( transactionStart
    , transactionWrite
    , transactionCommit
    ) where

--------------------------------------------------------------------------------
import Data.Int
import Data.Maybe

--------------------------------------------------------------------------------
import Data.ProtocolBuffers

--------------------------------------------------------------------------------
import Database.EventStore.Internal.Command
import Database.EventStore.Internal.Control (publishWith)
import Database.EventStore.Internal.Communication (Transmit(..))
import Database.EventStore.Internal.Exec (Exec)
import Database.EventStore.Internal.Operation (OpResult(..))
import Database.EventStore.Internal.Operation
import Database.EventStore.Internal.Operation.Transaction.Message
import Database.EventStore.Internal.Operation.Write.Common
import Database.EventStore.Internal.Prelude
import Database.EventStore.Internal.Settings
import Database.EventStore.Internal.Stream
import Database.EventStore.Internal.Types

--------------------------------------------------------------------------------
-- | Start transaction operation.
transactionStart
  :: Settings
  -> Exec
  -> Text
  -> ExpectedVersion
  -> Maybe Credentials
  -> IO (Async Int64)
transactionStart :: Settings
-> Exec
-> Text
-> ExpectedVersion
-> Maybe Credentials
-> IO (Async Int64)
transactionStart Settings{Bool
Maybe Text
Maybe TLSSettings
Maybe Credentials
LogType
NominalDiffTime
LoggerFilter
MonitoringBackend
Retry
s_defaultUserCredentials :: Settings -> Maybe Credentials
s_defaultConnectionName :: Settings -> Maybe Text
s_monitoring :: Settings -> MonitoringBackend
s_operationRetry :: Settings -> Retry
s_operationTimeout :: Settings -> NominalDiffTime
s_loggerDetailed :: Settings -> Bool
s_loggerFilter :: Settings -> LoggerFilter
s_loggerType :: Settings -> LogType
s_ssl :: Settings -> Maybe TLSSettings
s_reconnect_delay :: Settings -> NominalDiffTime
s_retry :: Settings -> Retry
s_requireMaster :: Settings -> Bool
s_heartbeatTimeout :: Settings -> NominalDiffTime
s_heartbeatInterval :: Settings -> NominalDiffTime
s_defaultUserCredentials :: Maybe Credentials
s_defaultConnectionName :: Maybe Text
s_monitoring :: MonitoringBackend
s_operationRetry :: Retry
s_operationTimeout :: NominalDiffTime
s_loggerDetailed :: Bool
s_loggerFilter :: LoggerFilter
s_loggerType :: LogType
s_ssl :: Maybe TLSSettings
s_reconnect_delay :: NominalDiffTime
s_retry :: Retry
s_requireMaster :: Bool
s_heartbeatTimeout :: NominalDiffTime
s_heartbeatInterval :: NominalDiffTime
..} Exec
exec Text
stream ExpectedVersion
exp_v Maybe Credentials
cred
  = do Mailbox
m <- IO Mailbox
forall (m :: * -> *). MonadBase IO m => m Mailbox
mailboxNew
       IO Int64 -> IO (Async (StM IO Int64))
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> m (Async (StM m a))
async (IO Int64 -> IO (Async (StM IO Int64)))
-> IO Int64 -> IO (Async (StM IO Int64))
forall a b. (a -> b) -> a -> b
$
         do let req :: Start
req = Text -> Int64 -> Bool -> Start
newStart Text
stream (ExpectedVersion -> Int64
expVersionInt64 ExpectedVersion
exp_v) Bool
s_requireMaster
            Package
pkg <- Command -> Maybe Credentials -> Start -> IO Package
forall msg (m :: * -> *).
(Encode msg, MonadIO m) =>
Command -> Maybe Credentials -> msg -> m Package
createPkg Command
transactionStartCmd Maybe Credentials
cred Start
req

            IO (Loop Int64) -> IO Int64
forall (m :: * -> *) a. Monad m => m (Loop a) -> m a
keepLooping (IO (Loop Int64) -> IO Int64) -> IO (Loop Int64) -> IO Int64
forall a b. (a -> b) -> a -> b
$
              do Exec -> Transmit -> IO ()
forall p a (m :: * -> *).
(Pub p, Typeable a, MonadIO m) =>
p -> a -> m ()
publishWith Exec
exec (Mailbox -> Lifetime -> Package -> Transmit
Transmit Mailbox
m Lifetime
OneTime Package
pkg)
                 Either OperationError Started
outcome <- Mailbox -> IO (Either OperationError Started)
forall (m :: * -> *) resp.
(MonadBase IO m, Decode resp) =>
Mailbox -> m (Either OperationError resp)
mailboxReadDecoded Mailbox
m
                 case Either OperationError Started
outcome of
                   Left OperationError
e
                     -> OperationError -> IO (Loop Int64)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
e
                   Right Started
resp
                     -> let tid :: FieldType (Field 1 (RequiredField (Always (Value Int64))))
tid = Field 1 (RequiredField (Always (Value Int64)))
-> FieldType (Field 1 (RequiredField (Always (Value Int64))))
forall a. HasField a => a -> FieldType a
getField (Field 1 (RequiredField (Always (Value Int64)))
 -> FieldType (Field 1 (RequiredField (Always (Value Int64)))))
-> Field 1 (RequiredField (Always (Value Int64)))
-> FieldType (Field 1 (RequiredField (Always (Value Int64))))
forall a b. (a -> b) -> a -> b
$ Started -> Required 1 (Value Int64)
_transId Started
resp
                            r :: FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r   = Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a. HasField a => a -> FieldType a
getField (Field 2 (RequiredField (Always (Enumeration OpResult)))
 -> FieldType
      (Field 2 (RequiredField (Always (Enumeration OpResult)))))
-> Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a b. (a -> b) -> a -> b
$ Started -> Required 2 (Enumeration OpResult)
_result Started
resp in
                        case FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r of
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_PREPARE_TIMEOUT -> Loop Int64 -> IO (Loop Int64)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop Int64
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_FORWARD_TIMEOUT -> Loop Int64 -> IO (Loop Int64)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop Int64
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_COMMIT_TIMEOUT -> Loop Int64 -> IO (Loop Int64)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop Int64
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_WRONG_EXPECTED_VERSION -> OperationError -> IO (Loop Int64)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop Int64))
-> OperationError -> IO (Loop Int64)
forall a b. (a -> b) -> a -> b
$ Text -> ExpectedVersion -> OperationError
WrongExpectedVersion Text
stream ExpectedVersion
exp_v
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_STREAM_DELETED -> OperationError -> IO (Loop Int64)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop Int64))
-> OperationError -> IO (Loop Int64)
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
StreamDeleted (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_INVALID_TRANSACTION -> OperationError -> IO (Loop Int64)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
InvalidTransaction
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_ACCESS_DENIED -> OperationError -> IO (Loop Int64)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop Int64))
-> OperationError -> IO (Loop Int64)
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
forall t. StreamId t -> OperationError
AccessDenied (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_SUCCESS -> Loop Int64 -> IO (Loop Int64)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Loop Int64 -> IO (Loop Int64)) -> Loop Int64 -> IO (Loop Int64)
forall a b. (a -> b) -> a -> b
$ Int64 -> Loop Int64
forall a. a -> Loop a
Break Int64
FieldType (Field 1 (RequiredField (Always (Value Int64))))
tid

--------------------------------------------------------------------------------
-- | Transactional write operation.
transactionWrite
  :: Settings
  -> Exec
  -> Text
  -> ExpectedVersion
  -> Int64
  -> [Event]
  -> Maybe Credentials
  -> IO (Async ())
transactionWrite :: Settings
-> Exec
-> Text
-> ExpectedVersion
-> Int64
-> [Event]
-> Maybe Credentials
-> IO (Async ())
transactionWrite Settings{Bool
Maybe Text
Maybe TLSSettings
Maybe Credentials
LogType
NominalDiffTime
LoggerFilter
MonitoringBackend
Retry
s_defaultUserCredentials :: Maybe Credentials
s_defaultConnectionName :: Maybe Text
s_monitoring :: MonitoringBackend
s_operationRetry :: Retry
s_operationTimeout :: NominalDiffTime
s_loggerDetailed :: Bool
s_loggerFilter :: LoggerFilter
s_loggerType :: LogType
s_ssl :: Maybe TLSSettings
s_reconnect_delay :: NominalDiffTime
s_retry :: Retry
s_requireMaster :: Bool
s_heartbeatTimeout :: NominalDiffTime
s_heartbeatInterval :: NominalDiffTime
s_defaultUserCredentials :: Settings -> Maybe Credentials
s_defaultConnectionName :: Settings -> Maybe Text
s_monitoring :: Settings -> MonitoringBackend
s_operationRetry :: Settings -> Retry
s_operationTimeout :: Settings -> NominalDiffTime
s_loggerDetailed :: Settings -> Bool
s_loggerFilter :: Settings -> LoggerFilter
s_loggerType :: Settings -> LogType
s_ssl :: Settings -> Maybe TLSSettings
s_reconnect_delay :: Settings -> NominalDiffTime
s_retry :: Settings -> Retry
s_requireMaster :: Settings -> Bool
s_heartbeatTimeout :: Settings -> NominalDiffTime
s_heartbeatInterval :: Settings -> NominalDiffTime
..} Exec
exec Text
stream ExpectedVersion
exp_v Int64
trans_id [Event]
evts Maybe Credentials
cred
  = do Mailbox
m <- IO Mailbox
forall (m :: * -> *). MonadBase IO m => m Mailbox
mailboxNew
       IO () -> IO (Async (StM IO ()))
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> m (Async (StM m a))
async (IO () -> IO (Async (StM IO ())))
-> IO () -> IO (Async (StM IO ()))
forall a b. (a -> b) -> a -> b
$
         do [NewEvent]
nevts <- (Event -> IO NewEvent) -> [Event] -> IO [NewEvent]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Event -> IO NewEvent
eventToNewEventIO [Event]
evts
            let req :: Write
req = Int64 -> [NewEvent] -> Bool -> Write
newWrite Int64
trans_id [NewEvent]
nevts Bool
s_requireMaster
            Package
pkg <- Command -> Maybe Credentials -> Write -> IO Package
forall msg (m :: * -> *).
(Encode msg, MonadIO m) =>
Command -> Maybe Credentials -> msg -> m Package
createPkg Command
transactionWriteCmd Maybe Credentials
cred Write
req
            IO (Loop ()) -> IO ()
forall (m :: * -> *) a. Monad m => m (Loop a) -> m a
keepLooping (IO (Loop ()) -> IO ()) -> IO (Loop ()) -> IO ()
forall a b. (a -> b) -> a -> b
$
              do Exec -> Transmit -> IO ()
forall p a (m :: * -> *).
(Pub p, Typeable a, MonadIO m) =>
p -> a -> m ()
publishWith Exec
exec (Mailbox -> Lifetime -> Package -> Transmit
Transmit Mailbox
m Lifetime
OneTime Package
pkg)
                 Either OperationError Written
outcome <- Mailbox -> IO (Either OperationError Written)
forall (m :: * -> *) resp.
(MonadBase IO m, Decode resp) =>
Mailbox -> m (Either OperationError resp)
mailboxReadDecoded Mailbox
m
                 case Either OperationError Written
outcome of
                   Left OperationError
e
                     -> OperationError -> IO (Loop ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
e
                   Right Written
resp
                     -> let r :: FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r = Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a. HasField a => a -> FieldType a
getField (Field 2 (RequiredField (Always (Enumeration OpResult)))
 -> FieldType
      (Field 2 (RequiredField (Always (Enumeration OpResult)))))
-> Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a b. (a -> b) -> a -> b
$ Written -> Required 2 (Enumeration OpResult)
_wwResult Written
resp in
                        case FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r of
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_PREPARE_TIMEOUT -> Loop () -> IO (Loop ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop ()
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_FORWARD_TIMEOUT -> Loop () -> IO (Loop ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop ()
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_COMMIT_TIMEOUT -> Loop () -> IO (Loop ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop ()
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_WRONG_EXPECTED_VERSION -> OperationError -> IO (Loop ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop ())) -> OperationError -> IO (Loop ())
forall a b. (a -> b) -> a -> b
$ Text -> ExpectedVersion -> OperationError
WrongExpectedVersion Text
stream ExpectedVersion
exp_v
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_STREAM_DELETED -> OperationError -> IO (Loop ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop ())) -> OperationError -> IO (Loop ())
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
StreamDeleted (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_INVALID_TRANSACTION -> OperationError -> IO (Loop ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
InvalidTransaction
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_ACCESS_DENIED -> OperationError -> IO (Loop ())
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop ())) -> OperationError -> IO (Loop ())
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
forall t. StreamId t -> OperationError
AccessDenied (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_SUCCESS -> Loop () -> IO (Loop ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Loop () -> IO (Loop ())) -> Loop () -> IO (Loop ())
forall a b. (a -> b) -> a -> b
$ () -> Loop ()
forall a. a -> Loop a
Break ()

--------------------------------------------------------------------------------
-- | Transactional commit operation.
transactionCommit
  :: Settings
  -> Exec
  -> Text
  -> ExpectedVersion
  -> Int64
  -> Maybe Credentials
  -> IO (Async WriteResult)
transactionCommit :: Settings
-> Exec
-> Text
-> ExpectedVersion
-> Int64
-> Maybe Credentials
-> IO (Async WriteResult)
transactionCommit Settings{Bool
Maybe Text
Maybe TLSSettings
Maybe Credentials
LogType
NominalDiffTime
LoggerFilter
MonitoringBackend
Retry
s_defaultUserCredentials :: Maybe Credentials
s_defaultConnectionName :: Maybe Text
s_monitoring :: MonitoringBackend
s_operationRetry :: Retry
s_operationTimeout :: NominalDiffTime
s_loggerDetailed :: Bool
s_loggerFilter :: LoggerFilter
s_loggerType :: LogType
s_ssl :: Maybe TLSSettings
s_reconnect_delay :: NominalDiffTime
s_retry :: Retry
s_requireMaster :: Bool
s_heartbeatTimeout :: NominalDiffTime
s_heartbeatInterval :: NominalDiffTime
s_defaultUserCredentials :: Settings -> Maybe Credentials
s_defaultConnectionName :: Settings -> Maybe Text
s_monitoring :: Settings -> MonitoringBackend
s_operationRetry :: Settings -> Retry
s_operationTimeout :: Settings -> NominalDiffTime
s_loggerDetailed :: Settings -> Bool
s_loggerFilter :: Settings -> LoggerFilter
s_loggerType :: Settings -> LogType
s_ssl :: Settings -> Maybe TLSSettings
s_reconnect_delay :: Settings -> NominalDiffTime
s_retry :: Settings -> Retry
s_requireMaster :: Settings -> Bool
s_heartbeatTimeout :: Settings -> NominalDiffTime
s_heartbeatInterval :: Settings -> NominalDiffTime
..} Exec
exec Text
stream ExpectedVersion
exp_v Int64
trans_id Maybe Credentials
cred
  = do Mailbox
m <- IO Mailbox
forall (m :: * -> *). MonadBase IO m => m Mailbox
mailboxNew
       IO WriteResult -> IO (Async (StM IO WriteResult))
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> m (Async (StM m a))
async (IO WriteResult -> IO (Async (StM IO WriteResult)))
-> IO WriteResult -> IO (Async (StM IO WriteResult))
forall a b. (a -> b) -> a -> b
$
         do let req :: Commit
req = Int64 -> Bool -> Commit
newCommit Int64
trans_id Bool
s_requireMaster
            Package
pkg <- Command -> Maybe Credentials -> Commit -> IO Package
forall msg (m :: * -> *).
(Encode msg, MonadIO m) =>
Command -> Maybe Credentials -> msg -> m Package
createPkg Command
transactionCommitCmd Maybe Credentials
cred Commit
req
            IO (Loop WriteResult) -> IO WriteResult
forall (m :: * -> *) a. Monad m => m (Loop a) -> m a
keepLooping (IO (Loop WriteResult) -> IO WriteResult)
-> IO (Loop WriteResult) -> IO WriteResult
forall a b. (a -> b) -> a -> b
$
              do Exec -> Transmit -> IO ()
forall p a (m :: * -> *).
(Pub p, Typeable a, MonadIO m) =>
p -> a -> m ()
publishWith Exec
exec (Mailbox -> Lifetime -> Package -> Transmit
Transmit Mailbox
m Lifetime
OneTime Package
pkg)
                 Either OperationError Committed
outcome <- Mailbox -> IO (Either OperationError Committed)
forall (m :: * -> *) resp.
(MonadBase IO m, Decode resp) =>
Mailbox -> m (Either OperationError resp)
mailboxReadDecoded Mailbox
m
                 case Either OperationError Committed
outcome of
                   Left OperationError
e
                     -> OperationError -> IO (Loop WriteResult)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
e
                   Right Committed
resp
                     -> let r :: FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r = Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a. HasField a => a -> FieldType a
getField (Field 2 (RequiredField (Always (Enumeration OpResult)))
 -> FieldType
      (Field 2 (RequiredField (Always (Enumeration OpResult)))))
-> Field 2 (RequiredField (Always (Enumeration OpResult)))
-> FieldType
     (Field 2 (RequiredField (Always (Enumeration OpResult))))
forall a b. (a -> b) -> a -> b
$ Committed -> Required 2 (Enumeration OpResult)
_ccResult Committed
resp
                            com_pos :: FieldType (Field 7 (OptionalField (Last (Value Int64))))
com_pos = Field 7 (OptionalField (Last (Value Int64)))
-> FieldType (Field 7 (OptionalField (Last (Value Int64))))
forall a. HasField a => a -> FieldType a
getField (Field 7 (OptionalField (Last (Value Int64)))
 -> FieldType (Field 7 (OptionalField (Last (Value Int64)))))
-> Field 7 (OptionalField (Last (Value Int64)))
-> FieldType (Field 7 (OptionalField (Last (Value Int64))))
forall a b. (a -> b) -> a -> b
$ Committed -> Optional 7 (Value Int64)
_commitPosition Committed
resp
                            pre_pos :: FieldType (Field 6 (OptionalField (Last (Value Int64))))
pre_pos = Field 6 (OptionalField (Last (Value Int64)))
-> FieldType (Field 6 (OptionalField (Last (Value Int64))))
forall a. HasField a => a -> FieldType a
getField (Field 6 (OptionalField (Last (Value Int64)))
 -> FieldType (Field 6 (OptionalField (Last (Value Int64)))))
-> Field 6 (OptionalField (Last (Value Int64)))
-> FieldType (Field 6 (OptionalField (Last (Value Int64))))
forall a b. (a -> b) -> a -> b
$ Committed -> Optional 6 (Value Int64)
_preparePosition Committed
resp
                            lst_num :: FieldType (Field 5 (RequiredField (Always (Value Int64))))
lst_num = Field 5 (RequiredField (Always (Value Int64)))
-> FieldType (Field 5 (RequiredField (Always (Value Int64))))
forall a. HasField a => a -> FieldType a
getField (Field 5 (RequiredField (Always (Value Int64)))
 -> FieldType (Field 5 (RequiredField (Always (Value Int64)))))
-> Field 5 (RequiredField (Always (Value Int64)))
-> FieldType (Field 5 (RequiredField (Always (Value Int64))))
forall a b. (a -> b) -> a -> b
$ Committed -> Required 5 (Value Int64)
_lastNumber Committed
resp
                            p_int :: Int64
p_int = Int64 -> Maybe Int64 -> Int64
forall a. a -> Maybe a -> a
fromMaybe (-Int64
1) Maybe Int64
FieldType (Field 6 (OptionalField (Last (Value Int64))))
pre_pos
                            c_int :: Int64
c_int = Int64 -> Maybe Int64 -> Int64
forall a. a -> Maybe a -> a
fromMaybe (-Int64
1) Maybe Int64
FieldType (Field 7 (OptionalField (Last (Value Int64))))
com_pos
                            pos :: Position
pos = Int64 -> Int64 -> Position
Position Int64
c_int Int64
p_int
                            res :: WriteResult
res = Int64 -> Position -> WriteResult
WriteResult Int64
FieldType (Field 5 (RequiredField (Always (Value Int64))))
lst_num Position
pos in
                        case FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
r of
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_PREPARE_TIMEOUT -> Loop WriteResult -> IO (Loop WriteResult)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop WriteResult
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_FORWARD_TIMEOUT -> Loop WriteResult -> IO (Loop WriteResult)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop WriteResult
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_COMMIT_TIMEOUT -> Loop WriteResult -> IO (Loop WriteResult)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Loop WriteResult
forall a. Loop a
Loop
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_WRONG_EXPECTED_VERSION -> OperationError -> IO (Loop WriteResult)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop WriteResult))
-> OperationError -> IO (Loop WriteResult)
forall a b. (a -> b) -> a -> b
$ Text -> ExpectedVersion -> OperationError
WrongExpectedVersion Text
stream ExpectedVersion
exp_v
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_STREAM_DELETED -> OperationError -> IO (Loop WriteResult)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop WriteResult))
-> OperationError -> IO (Loop WriteResult)
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
StreamDeleted (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_INVALID_TRANSACTION -> OperationError -> IO (Loop WriteResult)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw OperationError
InvalidTransaction
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_ACCESS_DENIED -> OperationError -> IO (Loop WriteResult)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (OperationError -> IO (Loop WriteResult))
-> OperationError -> IO (Loop WriteResult)
forall a b. (a -> b) -> a -> b
$ StreamName -> OperationError
forall t. StreamId t -> OperationError
AccessDenied (StreamName -> OperationError) -> StreamName -> OperationError
forall a b. (a -> b) -> a -> b
$ Text -> StreamName
StreamName Text
stream
                          FieldType (Field 2 (RequiredField (Always (Enumeration OpResult))))
OP_SUCCESS -> Loop WriteResult -> IO (Loop WriteResult)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Loop WriteResult -> IO (Loop WriteResult))
-> Loop WriteResult -> IO (Loop WriteResult)
forall a b. (a -> b) -> a -> b
$ WriteResult -> Loop WriteResult
forall a. a -> Loop a
Break WriteResult
res