{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} module Database.PostgreSQL.Opium.FromField ( FieldError (..) , FromField (..) ) where import Data.Attoparsec.Text ( Parser , decimal , parseOnly , signed , takeText ) 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 data FieldError = FieldErrorUnexpectedNull | FieldErrorInvalidOid Oid | FieldErrorInvalidField Oid Text String deriving (Eq, Show) mapLeft :: (b -> c) -> Either b a -> Either c a mapLeft f (Left l) = Left $ f l mapLeft _ (Right r) = Right r fromParser :: (Oid -> Bool) -> Parser a -> Oid -> Text -> Either FieldError a fromParser validOid parser oid field | validOid oid = mapLeft (FieldErrorInvalidField oid field) $ parseOnly parser field | otherwise = Left $ FieldErrorInvalidOid oid class FromField a where fromField :: Oid -> Text -> Either FieldError a instance FromField Int where fromField = fromParser (Oid.smallint \/ Oid.integer \/ Oid.bigint) (signed decimal) instance FromField Text where fromField = fromParser (Oid.text \/ Oid.character \/ Oid.characterVarying) takeText instance FromField String where fromField oid text = Text.unpack <$> fromField oid text