module Hasql.Transaction
(
Mode(..),
IsolationLevel(..),
Transaction,
run,
sql,
query,
)
where
import Hasql.Transaction.Prelude
import qualified Hasql.Query as Query
import qualified Hasql.Session as Session
import qualified Hasql.Transaction.Queries as Queries
import qualified PostgreSQL.ErrorCodes as ErrorCodes
newtype Transaction a =
Transaction (Session.Session a)
deriving (Functor, Applicative, Monad)
data Mode =
Read |
Write |
WriteWithoutCommitting
deriving (Show, Eq, Ord, Enum, Bounded)
data IsolationLevel =
ReadCommitted |
RepeatableRead |
Serializable
deriving (Show, Eq, Ord, Enum, Bounded)
run :: Transaction a -> IsolationLevel -> Mode -> Session.Session a
run (Transaction session) isolation mode =
do
Session.query () (Queries.beginTransaction mode')
resultEither <- tryError session
case resultEither of
Left error -> do
Session.query () Queries.abortTransaction
case error of
Session.ResultError (Session.ServerError code _ _ _) | code == ErrorCodes.serialization_failure ->
run (Transaction session) isolation mode
_ ->
throwError error
Right result -> do
Session.query () $ bool Queries.abortTransaction Queries.commitTransaction commit
pure result
where
mode' =
(unsafeCoerce isolation, write)
(write, commit) =
case mode of
Read -> (False, True)
Write -> (True, True)
WriteWithoutCommitting -> (True, False)
sql :: ByteString -> Transaction ()
sql sql =
Transaction $ Session.sql sql
query :: a -> Query.Query a b -> Transaction b
query params query =
Transaction $ Session.query params query