module Hasql.Transaction.Private.Transaction
where

import Hasql.Transaction.Private.Prelude
import Hasql.Transaction.Private.Model
import qualified Hasql.Statement as A
import qualified Hasql.Session as B
import qualified Hasql.Transaction.Private.Statements as C
import qualified Hasql.Transaction.Private.Sessions as D


-- |
-- A composable abstraction over the retryable transactions.
--
-- Executes multiple queries under the specified mode and isolation level,
-- while automatically retrying the transaction in case of conflicts.
-- Thus this abstraction closely reproduces the behaviour of 'STM'.
newtype Transaction a =
  Transaction (StateT Bool B.Session a)
  deriving (a -> Transaction b -> Transaction a
(a -> b) -> Transaction a -> Transaction b
(forall a b. (a -> b) -> Transaction a -> Transaction b)
-> (forall a b. a -> Transaction b -> Transaction a)
-> Functor Transaction
forall a b. a -> Transaction b -> Transaction a
forall a b. (a -> b) -> Transaction a -> Transaction b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Transaction b -> Transaction a
$c<$ :: forall a b. a -> Transaction b -> Transaction a
fmap :: (a -> b) -> Transaction a -> Transaction b
$cfmap :: forall a b. (a -> b) -> Transaction a -> Transaction b
Functor, Functor Transaction
a -> Transaction a
Functor Transaction
-> (forall a. a -> Transaction a)
-> (forall a b.
    Transaction (a -> b) -> Transaction a -> Transaction b)
-> (forall a b c.
    (a -> b -> c) -> Transaction a -> Transaction b -> Transaction c)
-> (forall a b. Transaction a -> Transaction b -> Transaction b)
-> (forall a b. Transaction a -> Transaction b -> Transaction a)
-> Applicative Transaction
Transaction a -> Transaction b -> Transaction b
Transaction a -> Transaction b -> Transaction a
Transaction (a -> b) -> Transaction a -> Transaction b
(a -> b -> c) -> Transaction a -> Transaction b -> Transaction c
forall a. a -> Transaction a
forall a b. Transaction a -> Transaction b -> Transaction a
forall a b. Transaction a -> Transaction b -> Transaction b
forall a b. Transaction (a -> b) -> Transaction a -> Transaction b
forall a b c.
(a -> b -> c) -> Transaction a -> Transaction b -> Transaction c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: Transaction a -> Transaction b -> Transaction a
$c<* :: forall a b. Transaction a -> Transaction b -> Transaction a
*> :: Transaction a -> Transaction b -> Transaction b
$c*> :: forall a b. Transaction a -> Transaction b -> Transaction b
liftA2 :: (a -> b -> c) -> Transaction a -> Transaction b -> Transaction c
$cliftA2 :: forall a b c.
(a -> b -> c) -> Transaction a -> Transaction b -> Transaction c
<*> :: Transaction (a -> b) -> Transaction a -> Transaction b
$c<*> :: forall a b. Transaction (a -> b) -> Transaction a -> Transaction b
pure :: a -> Transaction a
$cpure :: forall a. a -> Transaction a
$cp1Applicative :: Functor Transaction
Applicative, Applicative Transaction
a -> Transaction a
Applicative Transaction
-> (forall a b.
    Transaction a -> (a -> Transaction b) -> Transaction b)
-> (forall a b. Transaction a -> Transaction b -> Transaction b)
-> (forall a. a -> Transaction a)
-> Monad Transaction
Transaction a -> (a -> Transaction b) -> Transaction b
Transaction a -> Transaction b -> Transaction b
forall a. a -> Transaction a
forall a b. Transaction a -> Transaction b -> Transaction b
forall a b. Transaction a -> (a -> Transaction b) -> Transaction b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> Transaction a
$creturn :: forall a. a -> Transaction a
>> :: Transaction a -> Transaction b -> Transaction b
$c>> :: forall a b. Transaction a -> Transaction b -> Transaction b
>>= :: Transaction a -> (a -> Transaction b) -> Transaction b
$c>>= :: forall a b. Transaction a -> (a -> Transaction b) -> Transaction b
$cp1Monad :: Applicative Transaction
Monad)

instance Semigroup a => Semigroup (Transaction a) where
  <> :: Transaction a -> Transaction a -> Transaction a
(<>) = (a -> a -> a) -> Transaction a -> Transaction a -> Transaction a
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> a -> a
forall a. Semigroup a => a -> a -> a
(<>)

instance Monoid a => Monoid (Transaction a) where
  mempty :: Transaction a
mempty = a -> Transaction a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
forall a. Monoid a => a
mempty
  mappend :: Transaction a -> Transaction a -> Transaction a
mappend = (a -> a -> a) -> Transaction a -> Transaction a -> Transaction a
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> a -> a
forall a. Monoid a => a -> a -> a
mappend

-- |
-- Execute the transaction using the provided isolation level and mode.
{-# INLINE run #-}
run :: Transaction a -> IsolationLevel -> Mode -> Bool -> B.Session a
run :: Transaction a -> IsolationLevel -> Mode -> Bool -> Session a
run (Transaction StateT Bool Session a
session) IsolationLevel
isolation Mode
mode Bool
preparable =
  IsolationLevel -> Mode -> Session (a, Bool) -> Bool -> Session a
forall a.
IsolationLevel -> Mode -> Session (a, Bool) -> Bool -> Session a
D.inRetryingTransaction IsolationLevel
isolation Mode
mode (StateT Bool Session a -> Bool -> Session (a, Bool)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT StateT Bool Session a
session Bool
True) Bool
preparable

-- |
-- Possibly a multi-statement query,
-- which however cannot be parameterized or prepared,
-- nor can any results of it be collected.
{-# INLINE sql #-}
sql :: ByteString -> Transaction ()
sql :: ByteString -> Transaction ()
sql =
  StateT Bool Session () -> Transaction ()
forall a. StateT Bool Session a -> Transaction a
Transaction (StateT Bool Session () -> Transaction ())
-> (ByteString -> StateT Bool Session ())
-> ByteString
-> Transaction ()
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Session () -> StateT Bool Session ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Session () -> StateT Bool Session ())
-> (ByteString -> Session ())
-> ByteString
-> StateT Bool Session ()
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ByteString -> Session ()
B.sql

-- |
-- Parameters and a specification of the parametric query to apply them to.
{-# INLINE statement #-}
statement :: a -> A.Statement a b -> Transaction b
statement :: a -> Statement a b -> Transaction b
statement a
params Statement a b
statement =
  StateT Bool Session b -> Transaction b
forall a. StateT Bool Session a -> Transaction a
Transaction (StateT Bool Session b -> Transaction b)
-> (Session b -> StateT Bool Session b)
-> Session b
-> Transaction b
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Session b -> StateT Bool Session b
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Session b -> Transaction b) -> Session b -> Transaction b
forall a b. (a -> b) -> a -> b
$ a -> Statement a b -> Session b
forall params result.
params -> Statement params result -> Session result
B.statement a
params Statement a b
statement

-- |
-- Cause transaction to eventually roll back.
{-# INLINE condemn #-}
condemn :: Transaction ()
condemn :: Transaction ()
condemn =
  StateT Bool Session () -> Transaction ()
forall a. StateT Bool Session a -> Transaction a
Transaction (StateT Bool Session () -> Transaction ())
-> StateT Bool Session () -> Transaction ()
forall a b. (a -> b) -> a -> b
$ Bool -> StateT Bool Session ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put Bool
False