@@ -26,13 +26,12 @@ module Database.PostgreSQL.Simple.Result
27 Result(..)
27 Result(..)
28 , ResultError(..)
28 , ResultError(..)
32#include "MachDeps.h"
31#include "MachDeps.h"
34import Control.Applicative (Applicative, (<$>), (<*>), (<*), pure)
33import Control.Applicative (Applicative, (<$>), (<*>), (<*), pure)
35−import Control.Exception (Exception, throw)
34+import Control.Exception (SomeException(..), Exception, throw)
36import Data.Attoparsec.Char8 hiding (Result)
35import Data.Attoparsec.Char8 hiding (Result)
37import Data.Bits ((.&.), (.|.), shiftL)
36import Data.Bits ((.&.), (.|.), shiftL)
38import Data.ByteString (ByteString)
37import Data.ByteString (ByteString)
@@ -81,12 +80,17 @@ data ResultError = Incompatible { errSQLType :: String
82instance Exception ResultError
81instance Exception ResultError
83+left :: Exception a => a -> Either SomeException b
84+left = Left . SomeException
84-- | A type that may be converted from a SQL type.
86-- | A type that may be converted from a SQL type.
85class Result a where
87class Result a where
86− convert :: Field -> Maybe ByteString -> Status ResultError a
88+ convert :: Field -> Maybe ByteString -> Either SomeException a
87 -- ^ Convert a SQL value to a Haskell value.
89 -- ^ Convert a SQL value to a Haskell value.
89− -- Throws a 'ResultError' if conversion fails.
91+ -- Returns an exception if the conversion fails. In the case of
92+ -- library instances, this will usually be a 'ResultError', but may
93+ -- be a 'UnicodeError'.
91instance (Result a) => Result (Maybe a) where
95instance (Result a) => Result (Maybe a) where
92 convert _ Nothing = pure Nothing
96 convert _ Nothing = pure Nothing
@@ -155,7 +159,7 @@ instance Result LB.ByteString where
157instance Result ST.Text where
161instance Result ST.Text where
158− convert f {- | isText f -} = doConvert f okText $ (Success . ST.decodeUtf8)
162+ convert f {- | isText f -} = doConvert f okText $ (Right . ST.decodeUtf8)
159{- | otherwise = incompatible f (typeOf ST.empty)
163{- | otherwise = incompatible f (typeOf ST.empty)
160 "attempt to mix binary and text" -}
164 "attempt to mix binary and text" -}
161 -- FIXME: return a "Fail someUnicodeError" instead of throwing it
165 -- FIXME: return a "Fail someUnicodeError" instead of throwing it
@@ -170,7 +174,7 @@ instance Result [Char] where
170instance Result UTCTime where
174instance Result UTCTime where
171 convert f = doConvert f ok $ \bs ->
175 convert f = doConvert f ok $ \bs ->
172 case parseTime defaultTimeLocale "%F %T%Q%z" (B8.unpack bs ++ "00") of
176 case parseTime defaultTimeLocale "%F %T%Q%z" (B8.unpack bs ++ "00") of
173− Just t -> Success t
177+ Just t -> Right t
174 Nothing -> conversionFailed f "UTCTime" "could not parse"
178 Nothing -> conversionFailed f "UTCTime" "could not parse"
175 where ok = mkCompats [TimestampWithTimeZone]
179 where ok = mkCompats [TimestampWithTimeZone]
@@ -224,29 +228,29 @@ okInt = ok64
226doConvert :: forall a . (Typeable a)
230doConvert :: forall a . (Typeable a)
227− => Field -> Compat -> (ByteString -> Status ResultError a)
231+ => Field -> Compat -> (ByteString -> Either SomeException a)
228− -> Maybe ByteString -> Status ResultError a
232+ -> Maybe ByteString -> Either SomeException a
229doConvert f types cvt (Just bs)
233doConvert f types cvt (Just bs)
230 | Just typ <- oid2builtin (typeOid f)
234 | Just typ <- oid2builtin (typeOid f)
231 , mkCompat typ `compat` types = cvt bs
235 , mkCompat typ `compat` types = cvt bs
232 | otherwise = incompatible f (typeOf (undefined::a)) "types incompatible"
236 | otherwise = incompatible f (typeOf (undefined::a)) "types incompatible"
233−doConvert f _ cvt _ = Fail $ UnexpectedNull (B.unpack (typename f))
237+doConvert f _ cvt _ = left $ UnexpectedNull (B.unpack (typename f))
234 (show (typeOf (undefined::a))) ""
238 (show (typeOf (undefined::a))) ""
236−incompatible :: Field -> TypeRep -> String -> Status ResultError a
240+incompatible :: Field -> TypeRep -> String -> Either SomeException a
237−incompatible f r = Fail . Incompatible (B.unpack (typename f)) (show r)
241+incompatible f r = left . Incompatible (B.unpack (typename f)) (show r)
239−conversionFailed :: Field -> String -> String -> Status ResultError a
243+conversionFailed :: Field -> String -> String -> Either SomeException a
240−conversionFailed f s = Fail . ConversionFailed (B.unpack (typename f)) s
244+conversionFailed f s = left . ConversionFailed (B.unpack (typename f)) s
242−atto :: (Typeable a) => Compat -> Parser a -> Field -> Maybe ByteString -> Status ResultError a
246+atto :: (Typeable a) => Compat -> Parser a -> Field -> Maybe ByteString -> Either SomeException a
243atto types p0 f dat = doConvert f types (go undefined p0) dat
247atto types p0 f dat = doConvert f types (go undefined p0) dat
245− go :: (Typeable a) => a -> Parser a -> ByteString -> Status ResultError a
249+ go :: (Typeable a) => a -> Parser a -> ByteString -> Either SomeException a
246 go dummy p s =
250 go dummy p s =
247 case parseOnly p s of
251 case parseOnly p s of
248 Left err -> conversionFailed f (show (typeOf dummy)) err
252 Left err -> conversionFailed f (show (typeOf dummy)) err
249− Right v -> Success v
253+ Right v -> Right v
251instance Result RawResult where
255instance Result RawResult where
252− convert field rawData = Success (RawResult field rawData)
256+ convert field rawData = Right (RawResult field rawData)