Sean Clark Hess
Sean Clark Hess

Reputation: 16079

Catching exceptions of multiple types

When I query my database, it might throw one of four different kinds of exceptions.

FormatError
QueryError
ResultError
SqlError

I want to write a function that catches any of those 4 exceptions generated by query and lifts them into ExceptT.

runQuery :: (ToRow q, FromRow r) => Query -> q -> ExceptT ServantErr IO [r]
runQuery conn q sub = do
    res <- liftIO $ try $ Postgres.query conn q sub
    case res of
      Left err -> throwError (postgresErr err)
      Right r -> return r

postgresErr :: ??? -> ServantErr
postgresErr e = err500 { errBody = ByteString.pack (show e) }

This doesn't work. try isn't catching anything. How can I catch any of the 4 exception types, and map it to a ServantErr depending on the type, but still allow any exceptions I don't handle to pass through?

Upvotes: 2

Views: 215

Answers (1)

&#216;rjan Johansen
&#216;rjan Johansen

Reputation: 18199

GHC's Exception class forms a hierarchy, with the SomeException type at the top. So to catch any exception whatsoever, use that:

postgresErr :: SomeException -> ServantErr

(Ideally postgresql-simple could have added its own intermediate catch-all exception type that you could use, but I couldn't see any.)

If you want to catch exactly those four, the best way I know is to use the catches function:

catches :: IO a -> [Handler a] -> IO a

Unfortunately this requires you to provide one Handler for each of them (although probably they'll only differ in their type signature).

Upvotes: 6

Related Questions