module Hasql.Transaction.Private.Sessions where

import Hasql.Session
import Hasql.Transaction.Config
import Hasql.Transaction.Private.Prelude
import qualified Hasql.Transaction.Private.Statements as Statements

{-
We may want to
do one transaction retry in case of the 23505 error, and fail if an identical
error is seen.
-}
inRetryingTransaction :: IsolationLevel -> Mode -> Session (a, Bool) -> Bool -> Session a
inRetryingTransaction :: forall a.
IsolationLevel -> Mode -> Session (a, Bool) -> Bool -> Session a
inRetryingTransaction IsolationLevel
level Mode
mode Session (a, Bool)
session Bool
preparable =
  forall a. (a -> a) -> a
fix forall a b. (a -> b) -> a -> b
$ \Session a
retry -> do
    Maybe a
attemptRes <- forall a.
IsolationLevel
-> Mode -> Session (a, Bool) -> Bool -> Session (Maybe a)
tryTransaction IsolationLevel
level Mode
mode Session (a, Bool)
session Bool
preparable
    case Maybe a
attemptRes of
      Just a
a -> forall (m :: * -> *) a. Monad m => a -> m a
return a
a
      Maybe a
Nothing -> Session a
retry

tryTransaction :: IsolationLevel -> Mode -> Session (a, Bool) -> Bool -> Session (Maybe a)
tryTransaction :: forall a.
IsolationLevel
-> Mode -> Session (a, Bool) -> Bool -> Session (Maybe a)
tryTransaction IsolationLevel
level Mode
mode Session (a, Bool)
body Bool
preparable = do
  forall params result.
params -> Statement params result -> Session result
statement () (IsolationLevel -> Mode -> Bool -> Statement () ()
Statements.beginTransaction IsolationLevel
level Mode
mode Bool
preparable)

  Maybe (a, Bool)
bodyRes <- forall e (m :: * -> *) a.
MonadError e m =>
m a -> (e -> m a) -> m a
catchError (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just Session (a, Bool)
body) forall a b. (a -> b) -> a -> b
$ \QueryError
error -> do
    forall params result.
params -> Statement params result -> Session result
statement () (Bool -> Statement () ()
Statements.abortTransaction Bool
preparable)
    forall a. QueryError -> Session a -> Session a
handleTransactionError QueryError
error forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing

  case Maybe (a, Bool)
bodyRes of
    Just (a
res, Bool
commit) -> forall e (m :: * -> *) a.
MonadError e m =>
m a -> (e -> m a) -> m a
catchError (Bool -> Bool -> Session ()
commitOrAbort Bool
commit Bool
preparable forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> forall a. a -> Maybe a
Just a
res) forall a b. (a -> b) -> a -> b
$ \QueryError
error -> do
      forall a. QueryError -> Session a -> Session a
handleTransactionError QueryError
error forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
    Maybe (a, Bool)
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing

commitOrAbort :: Bool -> Bool -> Session ()
commitOrAbort :: Bool -> Bool -> Session ()
commitOrAbort Bool
commit Bool
preparable =
  if Bool
commit
    then forall params result.
params -> Statement params result -> Session result
statement () (Bool -> Statement () ()
Statements.commitTransaction Bool
preparable)
    else forall params result.
params -> Statement params result -> Session result
statement () (Bool -> Statement () ()
Statements.abortTransaction Bool
preparable)

handleTransactionError :: QueryError -> Session a -> Session a
handleTransactionError :: forall a. QueryError -> Session a -> Session a
handleTransactionError QueryError
error Session a
onTransactionError = case QueryError
error of
  QueryError ByteString
_ [Text]
_ (ResultError (ServerError ByteString
"40001" ByteString
_ Maybe ByteString
_ Maybe ByteString
_ Maybe Int
_)) -> Session a
onTransactionError
  QueryError
error -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError QueryError
error