@@ -19,6 +19,7 @@ module Database.Table.SQLite.Simple.Monad
1919 , SqlM
2020 , runSqlM
2121 , rawSqlite
22+ , SqlException (.. )
2223 ) where
2324
2425import Prelude
@@ -28,6 +29,10 @@ import Control.Concurrent.MVar
2829 , newMVar
2930 , withMVar
3031 )
32+ import Control.Exception
33+ ( Exception (.. )
34+ , SomeException (.. )
35+ )
3136import Control.Monad.Class.MonadThrow
3237 ( MonadCatch (.. )
3338 , MonadThrow (.. )
@@ -110,3 +115,30 @@ runSqlM (SqlM action) Connection{lock,connection} =
110115-- | Wrap a function from "Database.SQLite.Simple" in 'SqlM'.
111116rawSqlite :: (Sqlite. Connection -> IO a ) -> SqlM a
112117rawSqlite = SqlM . ReaderT
118+
119+ -- | Union of exceptions that can occur with "Database.SQLite.Simple".
120+ data SqlException
121+ = SqlFormatError Sqlite. FormatError
122+ | SqlResultError Sqlite. ResultError
123+ | SqlSQLError Sqlite. SQLError
124+ deriving (Eq , Show )
125+
126+ -- | When converting to and from 'SomeException',
127+ -- the constructors of the 'SqlException' type are stripped.
128+ -- In other words, the type 'SqlException' represents a structural union,
129+ -- not a nominal sum of the individual exceptions.
130+ -- This makes it easier to catch the individual exceptions as a union.
131+ --
132+ -- Example:
133+ --
134+ -- > throw (Sqlite.SQLError Sqlite.ErrorIOData "" "")
135+ -- > `catch` \e -> print (e :: SqlException)
136+ instance Exception SqlException where
137+ toException (SqlFormatError e) = SomeException e
138+ toException (SqlResultError e) = SomeException e
139+ toException (SqlSQLError e) = SomeException e
140+ fromException e0
141+ | Just e <- fromException e0 = Just $ SqlFormatError e
142+ | Just e <- fromException e0 = Just $ SqlResultError e
143+ | Just e <- fromException e0 = Just $ SqlSQLError e
144+ | otherwise = Nothing
0 commit comments