Skip to content

Commit 9dfeca2

Browse files
committed
add pgWithTransactionMode and friends
1 parent dbcda6e commit 9dfeca2

File tree

1 file changed

+49
-2
lines changed

1 file changed

+49
-2
lines changed

Diff for: src/Database/PostgreSQL/Query/Functions.hs

+49-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ module Database.PostgreSQL.Query.Functions
66
-- * Transactions
77
, pgWithTransaction
88
, pgWithSavepoint
9+
, pgWithTransactionMode
10+
, pgWithTransactionModeRetry
11+
, pgWithTransactionSerializable
912
-- * Work with entities
1013
, pgInsertEntity
1114
, pgInsertManyEntities
@@ -49,12 +52,14 @@ import Database.PostgreSQL.Query.Types
4952
( FN, HasPostgres(..), TransactionSafe,
5053
ToMarkedRow(..), MarkedRow(..), mrToBuilder )
5154
import Database.PostgreSQL.Simple
52-
( ToRow, FromRow, execute_, query_,
53-
withTransaction, withSavepoint )
55+
( ToRow, FromRow, execute_, query_, )
5456
import Database.PostgreSQL.Simple.FromField
5557
( FromField )
58+
import Database.PostgreSQL.Simple.Internal
59+
( SqlError )
5660
import Database.PostgreSQL.Simple.ToField
5761
( ToField )
62+
import Database.PostgreSQL.Simple.Transaction
5863
import Database.PostgreSQL.Simple.Types
5964
( Query(..), Only(..), (:.)(..) )
6065

@@ -76,6 +81,48 @@ pgWithSavepoint action = withPGConnection $ \con -> do
7681
control $ \runInIO -> do
7782
withSavepoint con $ runInIO action
7883

84+
-- | Wrapper for 'withTransactionMode': Execute an action inside a SQL
85+
-- transaction with a given transaction mode.
86+
pgWithTransactionMode :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m)
87+
=> TransactionMode
88+
-> m a
89+
-> m a
90+
pgWithTransactionMode tmode ma = withPGConnection $ \con -> do
91+
control $ \runInIO -> do
92+
withTransactionMode tmode con $ runInIO ma
93+
94+
-- | Wrapper for 'withTransactionModeRetry': Like 'pgWithTransactionMode',
95+
-- but also takes a custom callback to determine if a transaction
96+
-- should be retried if an SqlError occurs. If the callback returns
97+
-- True, then the transaction will be retried. If the callback returns
98+
-- False, or an exception other than an SqlError occurs then the
99+
-- transaction will be rolled back and the exception rethrown.
100+
pgWithTransactionModeRetry :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m)
101+
=> TransactionMode
102+
-> (SqlError -> Bool)
103+
-> m a
104+
-> m a
105+
pgWithTransactionModeRetry tmode epred ma = withPGConnection $ \con -> do
106+
control $ \runInIO -> do
107+
withTransactionModeRetry tmode epred con $ runInIO ma
108+
109+
-- | Wrapper for 'withTransactionSerializable': Execute an action
110+
-- inside of a 'Serializable' transaction. If a serialization failure
111+
-- occurs, roll back the transaction and try again. Be warned that
112+
-- this may execute the IO action multiple times.
113+
--
114+
-- A Serializable transaction creates the illusion that your program
115+
-- has exclusive access to the database. This means that, even in a
116+
-- concurrent setting, you can perform queries in sequence without
117+
-- having to worry about what might happen between one statement and
118+
-- the next.
119+
pgWithTransactionSerializable :: (HasPostgres m, MonadBaseControl IO m, TransactionSafe m)
120+
=> m a
121+
-> m a
122+
pgWithTransactionSerializable ma = withPGConnection $ \con -> do
123+
control $ \runInIO -> do
124+
withTransactionSerializable con $ runInIO ma
125+
79126
{- | Execute query generated by 'SqlBuilder'. Typical use case:
80127
81128
@

0 commit comments

Comments
 (0)