Add unit tests and reimplement FromField
This commit is contained in:
@@ -5,12 +5,19 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeOperators #-}
|
||||
|
||||
module Database.PostgreSQL.Opium where
|
||||
module Database.PostgreSQL.Opium
|
||||
( FromField (..)
|
||||
, FromRow (..)
|
||||
, fetch_
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad.Trans.Maybe (MaybeT (..))
|
||||
import Data.ByteString (ByteString)
|
||||
import Data.Proxy (Proxy (Proxy))
|
||||
import Database.PostgreSQL.LibPQ
|
||||
(Result
|
||||
( Connection
|
||||
, Result
|
||||
, Row
|
||||
)
|
||||
import GHC.Generics (C, D, Generic, K1 (..), M1 (..), Meta (..), Rec0, Rep, S, to, (:*:) (..))
|
||||
@@ -21,6 +28,18 @@ import qualified Data.Text as Text
|
||||
import qualified Data.Text.Encoding as Encoding
|
||||
import qualified Database.PostgreSQL.LibPQ as LibPQ
|
||||
|
||||
import Database.PostgreSQL.Opium.FromField (FromField (..))
|
||||
|
||||
fetch_ :: FromRow a => Connection -> ByteString -> IO (Maybe [a])
|
||||
fetch_ conn query = runMaybeT $ do
|
||||
result <- MaybeT $ LibPQ.execParams conn query [] LibPQ.Text
|
||||
MaybeT $ fetchResult result
|
||||
|
||||
fetchResult :: FromRow a => Result -> IO (Maybe [a])
|
||||
fetchResult result = do
|
||||
nRows <- LibPQ.ntuples result
|
||||
runMaybeT $ mapM (MaybeT . flip fromRow result) [0..nRows - 1]
|
||||
|
||||
class FromRow a where
|
||||
fromRow :: Row -> Result -> IO (Maybe a)
|
||||
default fromRow :: (Generic a, FromRow' (Rep a)) => Row -> Result -> IO (Maybe a)
|
||||
@@ -48,16 +67,13 @@ instance (KnownSymbol nameSym, FromField t) => FromRow' (M1 S ('MetaSel ('Just n
|
||||
Nothing -> pure Nothing
|
||||
Just column -> do
|
||||
mbField <- LibPQ.getvalue result row column
|
||||
printf "%s: %s" (show name) (show mbField)
|
||||
pure $ M1 . K1 <$> fromField mbField
|
||||
ty <- LibPQ.ftype result column
|
||||
case fromField ty . Encoding.decodeUtf8 =<< mbField of
|
||||
Nothing -> do
|
||||
format <- LibPQ.fformat result column
|
||||
printf "field %s: %s (oid: %s, format: %s)\n" (show name) (show mbField) (show ty) (show format)
|
||||
pure Nothing
|
||||
Just value ->
|
||||
pure $ Just $ M1 $ K1 value
|
||||
where
|
||||
name = Encoding.encodeUtf8 $ Text.pack $ symbolVal (Proxy :: Proxy nameSym)
|
||||
|
||||
class FromField a where
|
||||
fromField :: Maybe ByteString -> Maybe a
|
||||
|
||||
instance FromField String where
|
||||
fromField = fmap (Text.unpack . Encoding.decodeUtf8)
|
||||
|
||||
instance FromField Int where
|
||||
fromField = fmap (read . Text.unpack . Encoding.decodeUtf8)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
|
||||
module Database.PostgreSQL.Opium.FromField (FromField (..)) where
|
||||
|
||||
import Data.Attoparsec.Text
|
||||
( Parser
|
||||
, decimal
|
||||
, parseOnly
|
||||
, signed
|
||||
)
|
||||
import Data.Text (Text)
|
||||
import Database.PostgreSQL.LibPQ (Oid)
|
||||
|
||||
import qualified Data.Text as Text
|
||||
import qualified Database.PostgreSQL.Opium.Oid as Oid
|
||||
|
||||
(\/) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
|
||||
p \/ q = \x -> p x || q x
|
||||
|
||||
eitherToMaybe :: Either b a -> Maybe a
|
||||
eitherToMaybe = \case
|
||||
Left _ -> Nothing
|
||||
Right x -> Just x
|
||||
|
||||
fromParser
|
||||
:: (Oid -> Bool)
|
||||
-> Parser a
|
||||
-> Oid
|
||||
-> Text
|
||||
-> Maybe a
|
||||
fromParser validOid parser oid value
|
||||
| validOid oid = eitherToMaybe $ parseOnly parser value
|
||||
| otherwise = Nothing
|
||||
|
||||
class FromField a where
|
||||
fromField :: Oid -> Text -> Maybe a
|
||||
|
||||
instance FromField Int where
|
||||
fromField = fromParser
|
||||
(Oid.smallint \/ Oid.integer \/ Oid.bigint)
|
||||
(signed decimal)
|
||||
|
||||
instance FromField Text where
|
||||
fromField oid text =
|
||||
if Oid.text oid || Oid.character oid || Oid.characterVarying oid then
|
||||
Just text
|
||||
else
|
||||
Nothing
|
||||
|
||||
instance FromField String where
|
||||
fromField oid text = Text.unpack <$> fromField oid text
|
||||
@@ -0,0 +1,31 @@
|
||||
module Database.PostgreSQL.Opium.Oid where
|
||||
|
||||
import Database.PostgreSQL.LibPQ (Oid (..))
|
||||
|
||||
eq :: Eq a => a -> a -> Bool
|
||||
eq = (==)
|
||||
|
||||
-- integer types
|
||||
|
||||
-- | 16-bit integer
|
||||
smallint :: Oid -> Bool
|
||||
smallint = eq $ Oid 21
|
||||
|
||||
-- | 32-bit integer
|
||||
integer :: Oid -> Bool
|
||||
integer = eq $ Oid 23
|
||||
|
||||
-- | 64-bit integer
|
||||
bigint :: Oid -> Bool
|
||||
bigint = eq $ Oid 20
|
||||
|
||||
-- string types
|
||||
|
||||
text :: Oid -> Bool
|
||||
text = eq $ Oid 25
|
||||
|
||||
character :: Oid -> Bool
|
||||
character = eq $ Oid 1042
|
||||
|
||||
characterVarying :: Oid -> Bool
|
||||
characterVarying = eq $ Oid 1043
|
||||
Reference in New Issue
Block a user