preql-0.4: src/Preql/Wire/Decode.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Decoding values from Postgres wire format to Haskell.
module Preql.Wire.Decode where
import Preql.Wire.Errors
import Preql.Wire.Internal
import Control.Monad.Except
import GHC.TypeNats
import Preql.Imports
import qualified Data.Vector as V
import qualified Data.Vector.Sized as VS
import qualified Database.PostgreSQL.LibPQ as PQ
decodeVector :: KnownNat n =>
(PgType -> IO (Either QueryError PQ.Oid)) -> RowDecoder n a -> PQ.Result -> IO (Either QueryError (Vector a))
decodeVector lookupType rd@(RowDecoder pgtypes _parsers) result = do
mismatches <- fmap (catMaybes . VS.toList) $ for (VS.zip (VS.enumFromN 0) pgtypes) $ \(column@(PQ.Col cint), expected) -> do
actual <- PQ.ftype result column
e_expectedOid <- lookupType expected
case e_expectedOid of
Right oid | actual == oid -> return Nothing
_ -> do
m_name <- liftIO $ PQ.fname result column
let columnName = decodeUtf8With lenientDecode <$> m_name
return $ Just (TypeMismatch{column = fromIntegral cint, ..})
if not (null mismatches)
then return (Left (PgTypeMismatch mismatches))
else do
(PQ.Row ntuples) <- liftIO $ PQ.ntuples result
fmap (first DecoderError) . runExceptT $
V.generateM (fromIntegral ntuples) (decodeRow rd result . PQ.toRow)