on master help sign in
Allow composable error-handling in simple client API
commite7e3cf2dc4e8d9df5d772516d700658c5af95dd6 author3noch <eacameron@gmail.com> dateFri 15 Sep 2017, 17:06 (9 years ago) parent0c88ce7
1 file changed+15−13
src/lib/ProjectM36/Client/Simple.hs+15−13
src/lib/ProjectM36/Client/Simple.hs+15−13
@@ -8,6 +8,8 @@ module ProjectM36.Client.Simple (
88 executeOrErr,
99 query,
1010 queryOrErr,
11+ cancelTransaction,
12+ orCancelTransaction,
1113 rollback,
1214 close,
1315 Atom(..),
@@ -16,6 +18,7 @@ module ProjectM36.Client.Simple (
1618 DbConn,
1719 DbError(..),
1820 Attribute(..),
21+ C.Atomable(toAtom, fromAtom),
1922 C.ConnectionInfo(..),
2023 C.PersistenceStrategy(..),
2124 C.NotificationCallback,
@@ -24,7 +27,9 @@ module ProjectM36.Client.Simple (
2427 C.RelationalExprBase(..)
2528 ) where
2629-- | A simplified client interface for Project:M36 database access.
30+
2731import Control.Exception.Base
32+import Control.Monad ((<=<))
2833import Control.Monad.Reader
2934import ProjectM36.Base
3035import qualified ProjectM36.Client as C
@@ -89,19 +94,11 @@ data DbError = ConnError C.ConnectionError |
8994
9095-- | 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.
9196execute :: C.DatabaseContextExpr -> Db ()
92−execute expr = do
93− ret <- executeOrErr expr
94− case ret of
95− Left err -> liftIO $ cancelTransaction (RelError err)
96− Right _ -> pure ()
97+execute = orCancelTransaction <=< executeOrErr
9798
9899-- | Run a 'RelationalExpr' query in the 'DB' monad. Relational expressions perform read-only queries against the current database state.
99100query :: C.RelationalExpr -> Db Relation
100−query expr = do
101− ret <- queryOrErr expr
102− case ret of
103− Left err -> liftIO $ cancelTransaction (RelError err)
104− Right rel -> pure rel
101+query = orCancelTransaction <=< queryOrErr
105102
106103-- | Run a 'DatabaseContextExpr' update expression. If there is an error, just return it without cancelling the current transaction.
107104executeOrErr :: C.DatabaseContextExpr -> Db (Either RelationalError ())
@@ -117,7 +114,12 @@ queryOrErr expr = Db $ do
117114
118115-- | Unconditionally roll back the current transaction and throw an exception to terminate the execution of the Db monad.
119116rollback :: Db ()
120−rollback = Db $ lift $ cancelTransaction TransactionRolledBack
117+rollback = cancelTransaction TransactionRolledBack
118+
119+-- | Cancel a transaction and carry some error information with it.
120+cancelTransaction :: DbError -> Db a
121+cancelTransaction err = liftIO $ throwIO (TransactionCancelled err)
121122
122−cancelTransaction :: DbError -> IO a
123−cancelTransaction err = throwIO (TransactionCancelled err)
123+-- | Converts the 'Either' result from a 'Db' action into an immediate cancel in the case of error.
124+orCancelTransaction :: Either RelationalError a -> Db a
125+orCancelTransaction = either (cancelTransaction . RelError) pure