@@ -8,6 +8,8 @@ module ProjectM36.Client.Simple (
8 executeOrErr,
8 executeOrErr,
10 queryOrErr,
10 queryOrErr,
@@ -16,6 +18,7 @@ module ProjectM36.Client.Simple (
17 DbError(..),
19 DbError(..),
18 Attribute(..),
20 Attribute(..),
21+ C.Atomable(toAtom, fromAtom),
19 C.ConnectionInfo(..),
22 C.ConnectionInfo(..),
20 C.PersistenceStrategy(..),
23 C.PersistenceStrategy(..),
21 C.NotificationCallback,
24 C.NotificationCallback,
@@ -24,7 +27,9 @@ module ProjectM36.Client.Simple (
24 C.RelationalExprBase(..)
27 C.RelationalExprBase(..)
26-- | A simplified client interface for Project:M36 database access.
29-- | A simplified client interface for Project:M36 database access.
27import Control.Exception.Base
31import Control.Exception.Base
32+import Control.Monad ((<=<))
28import Control.Monad.Reader
33import Control.Monad.Reader
29import ProjectM36.Base
34import ProjectM36.Base
30import qualified ProjectM36.Client as C
35import qualified ProjectM36.Client as C
@@ -89,19 +94,11 @@ data DbError = ConnError C.ConnectionError |
90-- | Execute a 'DatabaseContextExpr' in the 'DB' monad. Database context expressions manipulate the state of the database. In case of an error, the transaction is terminated and the connection's session is rolled back.
95-- | Execute a 'DatabaseContextExpr' in the 'DB' monad. Database context expressions manipulate the state of the database. In case of an error, the transaction is terminated and the connection's session is rolled back.
91execute :: C.DatabaseContextExpr -> Db ()
96execute :: C.DatabaseContextExpr -> Db ()
93− ret <- executeOrErr expr
97+execute = orCancelTransaction <=< executeOrErr
95− Left err -> liftIO $ cancelTransaction (RelError err)
98-- | Run a 'RelationalExpr' query in the 'DB' monad. Relational expressions perform read-only queries against the current database state.
99-- | Run a 'RelationalExpr' query in the 'DB' monad. Relational expressions perform read-only queries against the current database state.
99query :: C.RelationalExpr -> Db Relation
100query :: C.RelationalExpr -> Db Relation
100−query expr = do
101+query = orCancelTransaction <=< queryOrErr
101− ret <- queryOrErr expr
103− Left err -> liftIO $ cancelTransaction (RelError err)
104− Right rel -> pure rel
106-- | Run a 'DatabaseContextExpr' update expression. If there is an error, just return it without cancelling the current transaction.
103-- | Run a 'DatabaseContextExpr' update expression. If there is an error, just return it without cancelling the current transaction.
107executeOrErr :: C.DatabaseContextExpr -> Db (Either RelationalError ())
104executeOrErr :: C.DatabaseContextExpr -> Db (Either RelationalError ())
@@ -117,7 +114,12 @@ queryOrErr expr = Db $ do
118-- | Unconditionally roll back the current transaction and throw an exception to terminate the execution of the Db monad.
115-- | Unconditionally roll back the current transaction and throw an exception to terminate the execution of the Db monad.
119rollback :: Db ()
116rollback :: Db ()
120−rollback = Db $ lift $ cancelTransaction TransactionRolledBack
117+rollback = cancelTransaction TransactionRolledBack
119+-- | Cancel a transaction and carry some error information with it.
120+cancelTransaction :: DbError -> Db a
121+cancelTransaction err = liftIO $ throwIO (TransactionCancelled err)
122−cancelTransaction :: DbError -> IO a
123+-- | Converts the 'Either' result from a 'Db' action into an immediate cancel in the case of error.
123−cancelTransaction err = throwIO (TransactionCancelled err)
124+orCancelTransaction :: Either RelationalError a -> Db a
125+orCancelTransaction = either (cancelTransaction . RelError) pure