{-# LANGUAGE CPP, DeriveDataTypeable, DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Database.SQLite.Simple.FromField
(
FromField(..)
, FieldParser
, ResultError(..)
, Field
, fieldData
, returnError
) where
import Control.Exception (SomeException(..), Exception)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as LB
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Time (UTCTime, Day)
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import Data.Typeable (Typeable, typeOf)
import Data.Word (Word8, Word16, Word32, Word64)
import GHC.Float (double2Float)
import Database.SQLite3 as Base
import Database.SQLite.Simple.Types
import Database.SQLite.Simple.Internal
import Database.SQLite.Simple.Ok
import Database.SQLite.Simple.Time
data ResultError = Incompatible { ResultError -> String
errSQLType :: String
, ResultError -> String
errHaskellType :: String
, ResultError -> String
errMessage :: String }
| UnexpectedNull { errSQLType :: String
, errHaskellType :: String
, errMessage :: String }
| ConversionFailed { errSQLType :: String
, errHaskellType :: String
, errMessage :: String }
deriving (ResultError -> ResultError -> Bool
(ResultError -> ResultError -> Bool)
-> (ResultError -> ResultError -> Bool) -> Eq ResultError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ResultError -> ResultError -> Bool
$c/= :: ResultError -> ResultError -> Bool
== :: ResultError -> ResultError -> Bool
$c== :: ResultError -> ResultError -> Bool
Eq, Int -> ResultError -> ShowS
[ResultError] -> ShowS
ResultError -> String
(Int -> ResultError -> ShowS)
-> (ResultError -> String)
-> ([ResultError] -> ShowS)
-> Show ResultError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ResultError] -> ShowS
$cshowList :: [ResultError] -> ShowS
show :: ResultError -> String
$cshow :: ResultError -> String
showsPrec :: Int -> ResultError -> ShowS
$cshowsPrec :: Int -> ResultError -> ShowS
Show, Typeable)
instance Exception ResultError
left :: Exception a => a -> Ok b
left :: a -> Ok b
left = [SomeException] -> Ok b
forall a. [SomeException] -> Ok a
Errors ([SomeException] -> Ok b) -> (a -> [SomeException]) -> a -> Ok b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SomeException -> [SomeException] -> [SomeException]
forall a. a -> [a] -> [a]
:[]) (SomeException -> [SomeException])
-> (a -> SomeException) -> a -> [SomeException]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> SomeException
forall e. Exception e => e -> SomeException
SomeException
type FieldParser a = Field -> Ok a
class FromField a where
fromField :: FieldParser a
instance (FromField a) => FromField (Maybe a) where
fromField :: FieldParser (Maybe a)
fromField (Field SQLNull _) = Maybe a -> Ok (Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
fromField f :: Field
f = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> Ok a -> Ok (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FieldParser a
forall a. FromField a => FieldParser a
fromField Field
f
instance FromField Null where
fromField :: FieldParser Null
fromField (Field SQLNull _) = Null -> Ok Null
forall (f :: * -> *) a. Applicative f => a -> f a
pure Null
Null
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Null
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "data is not null"
takeInt :: (Num a, Typeable a) => Field -> Ok a
takeInt :: Field -> Ok a
takeInt (Field (SQLInteger i :: Int64
i) _) = a -> Ok a
forall a. a -> Ok a
Ok (a -> Ok a) -> (Int64 -> a) -> Int64 -> Ok a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Ok a) -> Int64 -> Ok a
forall a b. (a -> b) -> a -> b
$ Int64
i
takeInt f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok a
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "need an int"
instance FromField Int8 where
fromField :: FieldParser Int8
fromField = FieldParser Int8
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Int16 where
fromField :: FieldParser Int16
fromField = FieldParser Int16
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Int32 where
fromField :: FieldParser Int32
fromField = FieldParser Int32
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Int where
fromField :: FieldParser Int
fromField = FieldParser Int
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Int64 where
fromField :: FieldParser Int64
fromField = FieldParser Int64
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Integer where
fromField :: FieldParser Integer
fromField = FieldParser Integer
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Word8 where
fromField :: FieldParser Word8
fromField = FieldParser Word8
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Word16 where
fromField :: FieldParser Word16
fromField = FieldParser Word16
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Word32 where
fromField :: FieldParser Word32
fromField = FieldParser Word32
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Word64 where
fromField :: FieldParser Word64
fromField = FieldParser Word64
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Word where
fromField :: FieldParser Word
fromField = FieldParser Word
forall a. (Num a, Typeable a) => Field -> Ok a
takeInt
instance FromField Double where
fromField :: FieldParser Double
fromField (Field (SQLFloat flt :: Double
flt) _) = Double -> Ok Double
forall a. a -> Ok a
Ok Double
flt
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Double
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting an SQLFloat column type"
instance FromField Float where
fromField :: FieldParser Float
fromField (Field (SQLFloat flt :: Double
flt) _) = Float -> Ok Float
forall a. a -> Ok a
Ok (Float -> Ok Float) -> (Double -> Float) -> Double -> Ok Float
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Float
double2Float (Double -> Ok Float) -> Double -> Ok Float
forall a b. (a -> b) -> a -> b
$ Double
flt
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Float
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting an SQLFloat column type"
instance FromField Bool where
fromField :: FieldParser Bool
fromField f :: Field
f@(Field (SQLInteger b :: Int64
b) _)
| (Int64
b Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
== 0) Bool -> Bool -> Bool
|| (Int64
b Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
== 1) = Bool -> Ok Bool
forall a. a -> Ok a
Ok (Int64
b Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
/= 0)
| Bool
otherwise = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Bool
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f ("bool must be 0 or 1, got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int64 -> String
forall a. Show a => a -> String
show Int64
b)
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Bool
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting an SQLInteger column type"
instance FromField T.Text where
fromField :: FieldParser Text
fromField (Field (SQLText txt :: Text
txt) _) = Text -> Ok Text
forall a. a -> Ok a
Ok Text
txt
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Text
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "need a text"
instance FromField LT.Text where
fromField :: FieldParser Text
fromField (Field (SQLText txt :: Text
txt) _) = Text -> Ok Text
forall a. a -> Ok a
Ok (Text -> Ok Text) -> (Text -> Text) -> Text -> Ok Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
LT.fromStrict (Text -> Ok Text) -> Text -> Ok Text
forall a b. (a -> b) -> a -> b
$ Text
txt
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Text
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "need a text"
instance FromField [Char] where
fromField :: FieldParser String
fromField (Field (SQLText t :: Text
t) _) = String -> Ok String
forall a. a -> Ok a
Ok (String -> Ok String) -> String -> Ok String
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
t
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok String
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLText column type"
instance FromField ByteString where
fromField :: FieldParser ByteString
fromField (Field (SQLBlob blb :: ByteString
blb) _) = ByteString -> Ok ByteString
forall a. a -> Ok a
Ok ByteString
blb
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok ByteString
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLBlob column type"
instance FromField LB.ByteString where
fromField :: FieldParser ByteString
fromField (Field (SQLBlob blb :: ByteString
blb) _) = ByteString -> Ok ByteString
forall a. a -> Ok a
Ok (ByteString -> Ok ByteString)
-> ([ByteString] -> ByteString) -> [ByteString] -> Ok ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
LB.fromChunks ([ByteString] -> Ok ByteString) -> [ByteString] -> Ok ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString
blb]
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok ByteString
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLBlob column type"
instance FromField UTCTime where
fromField :: FieldParser UTCTime
fromField f :: Field
f@(Field (SQLText t :: Text
t) _) =
case Text -> Either String UTCTime
parseUTCTime Text
t of
Right t :: UTCTime
t -> UTCTime -> Ok UTCTime
forall a. a -> Ok a
Ok UTCTime
t
Left e :: String
e -> (String -> String -> String -> ResultError)
-> Field -> String -> Ok UTCTime
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f ("couldn't parse UTCTime field: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
e)
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok UTCTime
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLText column type"
instance FromField Day where
fromField :: FieldParser Day
fromField f :: Field
f@(Field (SQLText t :: Text
t) _) =
case Text -> Either String Day
parseDay Text
t of
Right t :: Day
t -> Day -> Ok Day
forall a. a -> Ok a
Ok Day
t
Left e :: String
e -> (String -> String -> String -> ResultError)
-> Field -> String -> Ok Day
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f ("couldn't parse Day field: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
e)
fromField f :: Field
f = (String -> String -> String -> ResultError)
-> Field -> String -> Ok Day
forall a err.
(Typeable a, Exception err) =>
(String -> String -> String -> err) -> Field -> String -> Ok a
returnError String -> String -> String -> ResultError
ConversionFailed Field
f "expecting SQLText column type"
instance FromField SQLData where
fromField :: FieldParser SQLData
fromField f :: Field
f = SQLData -> Ok SQLData
forall a. a -> Ok a
Ok (Field -> SQLData
fieldData Field
f)
fieldTypename :: Field -> String
fieldTypename :: Field -> String
fieldTypename = ByteString -> String
B.unpack (ByteString -> String) -> (Field -> ByteString) -> Field -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SQLData -> ByteString
gettypename (SQLData -> ByteString)
-> (Field -> SQLData) -> Field -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Field -> SQLData
result
fieldData :: Field -> SQLData
fieldData :: Field -> SQLData
fieldData = Field -> SQLData
result
returnError :: forall a err . (Typeable a, Exception err)
=> (String -> String -> String -> err)
-> Field -> String -> Ok a
returnError :: (String -> String -> String -> err) -> Field -> String -> Ok a
returnError mkErr :: String -> String -> String -> err
mkErr f :: Field
f = err -> Ok a
forall a b. Exception a => a -> Ok b
left (err -> Ok a) -> (String -> err) -> String -> Ok a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String -> err
mkErr (Field -> String
fieldTypename Field
f)
(TypeRep -> String
forall a. Show a => a -> String
show (a -> TypeRep
forall a. Typeable a => a -> TypeRep
typeOf (a
forall a. HasCallStack => a
undefined :: a)))