-- |
-- An API for retrieval of multiple results.
-- Can be used to handle:
-- 
-- * A single result,
-- 
-- * Individual results of a multi-statement query
-- with the help of "Applicative" and "Monad",
-- 
-- * Row-by-row fetching.
-- 
module Hasql.Private.Decoders.Results where

import Hasql.Private.Prelude hiding (maybe, many)
import Hasql.Private.Errors
import qualified Database.PostgreSQL.LibPQ as LibPQ
import qualified Hasql.Private.Prelude as Prelude
import qualified Hasql.Private.Decoders.Result as Result
import qualified Hasql.Private.Decoders.Row as Row


newtype Results a =
  Results (ReaderT (Bool, LibPQ.Connection) (ExceptT CommandError IO) a)
  deriving (a -> Results b -> Results a
(a -> b) -> Results a -> Results b
(forall a b. (a -> b) -> Results a -> Results b)
-> (forall a b. a -> Results b -> Results a) -> Functor Results
forall a b. a -> Results b -> Results a
forall a b. (a -> b) -> Results a -> Results b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Results b -> Results a
$c<$ :: forall a b. a -> Results b -> Results a
fmap :: (a -> b) -> Results a -> Results b
$cfmap :: forall a b. (a -> b) -> Results a -> Results b
Functor, Functor Results
a -> Results a
Functor Results
-> (forall a. a -> Results a)
-> (forall a b. Results (a -> b) -> Results a -> Results b)
-> (forall a b c.
    (a -> b -> c) -> Results a -> Results b -> Results c)
-> (forall a b. Results a -> Results b -> Results b)
-> (forall a b. Results a -> Results b -> Results a)
-> Applicative Results
Results a -> Results b -> Results b
Results a -> Results b -> Results a
Results (a -> b) -> Results a -> Results b
(a -> b -> c) -> Results a -> Results b -> Results c
forall a. a -> Results a
forall a b. Results a -> Results b -> Results a
forall a b. Results a -> Results b -> Results b
forall a b. Results (a -> b) -> Results a -> Results b
forall a b c. (a -> b -> c) -> Results a -> Results b -> Results c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: Results a -> Results b -> Results a
$c<* :: forall a b. Results a -> Results b -> Results a
*> :: Results a -> Results b -> Results b
$c*> :: forall a b. Results a -> Results b -> Results b
liftA2 :: (a -> b -> c) -> Results a -> Results b -> Results c
$cliftA2 :: forall a b c. (a -> b -> c) -> Results a -> Results b -> Results c
<*> :: Results (a -> b) -> Results a -> Results b
$c<*> :: forall a b. Results (a -> b) -> Results a -> Results b
pure :: a -> Results a
$cpure :: forall a. a -> Results a
$cp1Applicative :: Functor Results
Applicative, Applicative Results
a -> Results a
Applicative Results
-> (forall a b. Results a -> (a -> Results b) -> Results b)
-> (forall a b. Results a -> Results b -> Results b)
-> (forall a. a -> Results a)
-> Monad Results
Results a -> (a -> Results b) -> Results b
Results a -> Results b -> Results b
forall a. a -> Results a
forall a b. Results a -> Results b -> Results b
forall a b. Results a -> (a -> Results b) -> Results b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> Results a
$creturn :: forall a. a -> Results a
>> :: Results a -> Results b -> Results b
$c>> :: forall a b. Results a -> Results b -> Results b
>>= :: Results a -> (a -> Results b) -> Results b
$c>>= :: forall a b. Results a -> (a -> Results b) -> Results b
$cp1Monad :: Applicative Results
Monad)


{-# INLINE run #-}
run :: Results a -> (Bool, LibPQ.Connection) -> IO (Either CommandError a)
run :: Results a -> (Bool, Connection) -> IO (Either CommandError a)
run (Results ReaderT (Bool, Connection) (ExceptT CommandError IO) a
stack) (Bool, Connection)
env =
  ExceptT CommandError IO a -> IO (Either CommandError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ReaderT (Bool, Connection) (ExceptT CommandError IO) a
-> (Bool, Connection) -> ExceptT CommandError IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT (Bool, Connection) (ExceptT CommandError IO) a
stack (Bool, Connection)
env)

{-# INLINE clientError #-}
clientError :: Results a
clientError :: Results a
clientError =
  ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT (Bool, Connection) (ExceptT CommandError IO) a
 -> Results a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
-> Results a
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO a)
 -> ReaderT (Bool, Connection) (ExceptT CommandError IO) a)
-> ((Bool, Connection) -> ExceptT CommandError IO a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
forall a b. (a -> b) -> a -> b
$ \(Bool
_, Connection
connection) -> IO (Either CommandError a) -> ExceptT CommandError IO a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either CommandError a) -> ExceptT CommandError IO a)
-> IO (Either CommandError a) -> ExceptT CommandError IO a
forall a b. (a -> b) -> a -> b
$
  (Maybe ByteString -> Either CommandError a)
-> IO (Maybe ByteString) -> IO (Either CommandError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CommandError -> Either CommandError a
forall a b. a -> Either a b
Left (CommandError -> Either CommandError a)
-> (Maybe ByteString -> CommandError)
-> Maybe ByteString
-> Either CommandError a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Maybe ByteString -> CommandError
ClientError) (Connection -> IO (Maybe ByteString)
LibPQ.errorMessage Connection
connection)

-- |
-- Parse a single result.
{-# INLINE single #-}
single :: Result.Result a -> Results a
single :: Result a -> Results a
single Result a
resultDec =
  ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT (Bool, Connection) (ExceptT CommandError IO) a
 -> Results a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
-> Results a
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO a)
 -> ReaderT (Bool, Connection) (ExceptT CommandError IO) a)
-> ((Bool, Connection) -> ExceptT CommandError IO a)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) a
forall a b. (a -> b) -> a -> b
$ \(Bool
integerDatetimes, Connection
connection) -> IO (Either CommandError a) -> ExceptT CommandError IO a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either CommandError a) -> ExceptT CommandError IO a)
-> IO (Either CommandError a) -> ExceptT CommandError IO a
forall a b. (a -> b) -> a -> b
$ do
    Maybe Result
resultMaybe <- Connection -> IO (Maybe Result)
LibPQ.getResult Connection
connection
    case Maybe Result
resultMaybe of
      Just Result
result ->
        (ResultError -> CommandError)
-> Either ResultError a -> Either CommandError a
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft ResultError -> CommandError
ResultError (Either ResultError a -> Either CommandError a)
-> IO (Either ResultError a) -> IO (Either CommandError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Result a -> (Bool, Result) -> IO (Either ResultError a)
forall a. Result a -> (Bool, Result) -> IO (Either ResultError a)
Result.run Result a
resultDec (Bool
integerDatetimes, Result
result) 
      Maybe Result
Nothing ->
        (Maybe ByteString -> Either CommandError a)
-> IO (Maybe ByteString) -> IO (Either CommandError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CommandError -> Either CommandError a
forall a b. a -> Either a b
Left (CommandError -> Either CommandError a)
-> (Maybe ByteString -> CommandError)
-> Maybe ByteString
-> Either CommandError a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Maybe ByteString -> CommandError
ClientError) (Connection -> IO (Maybe ByteString)
LibPQ.errorMessage Connection
connection)

-- |
-- Fetch a single result.
{-# INLINE getResult #-}
getResult :: Results LibPQ.Result
getResult :: Results Result
getResult =
  ReaderT (Bool, Connection) (ExceptT CommandError IO) Result
-> Results Result
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT (Bool, Connection) (ExceptT CommandError IO) Result
 -> Results Result)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) Result
-> Results Result
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO Result)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) Result
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO Result)
 -> ReaderT (Bool, Connection) (ExceptT CommandError IO) Result)
-> ((Bool, Connection) -> ExceptT CommandError IO Result)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) Result
forall a b. (a -> b) -> a -> b
$ \(Bool
_, Connection
connection) -> IO (Either CommandError Result) -> ExceptT CommandError IO Result
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either CommandError Result) -> ExceptT CommandError IO Result)
-> IO (Either CommandError Result)
-> ExceptT CommandError IO Result
forall a b. (a -> b) -> a -> b
$ do
    Maybe Result
resultMaybe <- Connection -> IO (Maybe Result)
LibPQ.getResult Connection
connection
    case Maybe Result
resultMaybe of
      Just Result
result -> Either CommandError Result -> IO (Either CommandError Result)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Result -> Either CommandError Result
forall a b. b -> Either a b
Right Result
result)
      Maybe Result
Nothing -> (Maybe ByteString -> Either CommandError Result)
-> IO (Maybe ByteString) -> IO (Either CommandError Result)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (CommandError -> Either CommandError Result
forall a b. a -> Either a b
Left (CommandError -> Either CommandError Result)
-> (Maybe ByteString -> CommandError)
-> Maybe ByteString
-> Either CommandError Result
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Maybe ByteString -> CommandError
ClientError) (Connection -> IO (Maybe ByteString)
LibPQ.errorMessage Connection
connection)

-- |
-- Fetch a single result.
{-# INLINE getResultMaybe #-}
getResultMaybe :: Results (Maybe LibPQ.Result)
getResultMaybe :: Results (Maybe Result)
getResultMaybe =
  ReaderT (Bool, Connection) (ExceptT CommandError IO) (Maybe Result)
-> Results (Maybe Result)
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT
   (Bool, Connection) (ExceptT CommandError IO) (Maybe Result)
 -> Results (Maybe Result))
-> ReaderT
     (Bool, Connection) (ExceptT CommandError IO) (Maybe Result)
-> Results (Maybe Result)
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO (Maybe Result))
-> ReaderT
     (Bool, Connection) (ExceptT CommandError IO) (Maybe Result)
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO (Maybe Result))
 -> ReaderT
      (Bool, Connection) (ExceptT CommandError IO) (Maybe Result))
-> ((Bool, Connection) -> ExceptT CommandError IO (Maybe Result))
-> ReaderT
     (Bool, Connection) (ExceptT CommandError IO) (Maybe Result)
forall a b. (a -> b) -> a -> b
$ \(Bool
_, Connection
connection) -> IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result))
-> IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result)
forall a b. (a -> b) -> a -> b
$ Connection -> IO (Maybe Result)
LibPQ.getResult Connection
connection

{-# INLINE dropRemainders #-}
dropRemainders :: Results ()
dropRemainders :: Results ()
dropRemainders =
  {-# SCC "dropRemainders" #-} 
  ReaderT (Bool, Connection) (ExceptT CommandError IO) ()
-> Results ()
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT (Bool, Connection) (ExceptT CommandError IO) ()
 -> Results ())
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) ()
-> Results ()
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO ())
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) ()
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO ())
 -> ReaderT (Bool, Connection) (ExceptT CommandError IO) ())
-> ((Bool, Connection) -> ExceptT CommandError IO ())
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) ()
forall a b. (a -> b) -> a -> b
$ \(Bool
integerDatetimes, Connection
connection) -> Bool -> Connection -> ExceptT CommandError IO ()
loop Bool
integerDatetimes Connection
connection
  where
    loop :: Bool -> Connection -> ExceptT CommandError IO ()
loop Bool
integerDatetimes Connection
connection =
      ExceptT CommandError IO (Maybe Result)
getResultMaybe ExceptT CommandError IO (Maybe Result)
-> (Maybe Result -> ExceptT CommandError IO ())
-> ExceptT CommandError IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ExceptT CommandError IO ()
-> (Result -> ExceptT CommandError IO ())
-> Maybe Result
-> ExceptT CommandError IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
Prelude.maybe (() -> ExceptT CommandError IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) Result -> ExceptT CommandError IO ()
onResult
      where
        getResultMaybe :: ExceptT CommandError IO (Maybe Result)
getResultMaybe =
          IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result))
-> IO (Maybe Result) -> ExceptT CommandError IO (Maybe Result)
forall a b. (a -> b) -> a -> b
$ Connection -> IO (Maybe Result)
LibPQ.getResult Connection
connection
        onResult :: Result -> ExceptT CommandError IO ()
onResult Result
result =
          Bool -> Connection -> ExceptT CommandError IO ()
loop Bool
integerDatetimes Connection
connection ExceptT CommandError IO ()
-> ExceptT CommandError IO () -> ExceptT CommandError IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ExceptT CommandError IO ()
checkErrors
          where
            checkErrors :: ExceptT CommandError IO ()
checkErrors =
              IO (Either CommandError ()) -> ExceptT CommandError IO ()
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either CommandError ()) -> ExceptT CommandError IO ())
-> IO (Either CommandError ()) -> ExceptT CommandError IO ()
forall a b. (a -> b) -> a -> b
$ (Either ResultError () -> Either CommandError ())
-> IO (Either ResultError ()) -> IO (Either CommandError ())
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ResultError -> CommandError)
-> Either ResultError () -> Either CommandError ()
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft ResultError -> CommandError
ResultError) (IO (Either ResultError ()) -> IO (Either CommandError ()))
-> IO (Either ResultError ()) -> IO (Either CommandError ())
forall a b. (a -> b) -> a -> b
$ Result () -> (Bool, Result) -> IO (Either ResultError ())
forall a. Result a -> (Bool, Result) -> IO (Either ResultError a)
Result.run Result ()
Result.noResult (Bool
integerDatetimes, Result
result)

refine :: (a -> Either Text b) -> Results a -> Results b
refine :: (a -> Either Text b) -> Results a -> Results b
refine a -> Either Text b
refiner Results a
results = ReaderT (Bool, Connection) (ExceptT CommandError IO) b -> Results b
forall a.
ReaderT (Bool, Connection) (ExceptT CommandError IO) a -> Results a
Results (ReaderT (Bool, Connection) (ExceptT CommandError IO) b
 -> Results b)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) b
-> Results b
forall a b. (a -> b) -> a -> b
$ ((Bool, Connection) -> ExceptT CommandError IO b)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) b
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT (((Bool, Connection) -> ExceptT CommandError IO b)
 -> ReaderT (Bool, Connection) (ExceptT CommandError IO) b)
-> ((Bool, Connection) -> ExceptT CommandError IO b)
-> ReaderT (Bool, Connection) (ExceptT CommandError IO) b
forall a b. (a -> b) -> a -> b
$ \ (Bool, Connection)
env -> IO (Either CommandError b) -> ExceptT CommandError IO b
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either CommandError b) -> ExceptT CommandError IO b)
-> IO (Either CommandError b) -> ExceptT CommandError IO b
forall a b. (a -> b) -> a -> b
$ do
  Either CommandError a
resultEither <- Results a -> (Bool, Connection) -> IO (Either CommandError a)
forall a.
Results a -> (Bool, Connection) -> IO (Either CommandError a)
run Results a
results (Bool, Connection)
env
  Either CommandError b -> IO (Either CommandError b)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either CommandError b -> IO (Either CommandError b))
-> Either CommandError b -> IO (Either CommandError b)
forall a b. (a -> b) -> a -> b
$ Either CommandError a
resultEither Either CommandError a
-> (a -> Either CommandError b) -> Either CommandError b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Text -> CommandError) -> Either Text b -> Either CommandError b
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft (ResultError -> CommandError
ResultError (ResultError -> CommandError)
-> (Text -> ResultError) -> Text -> CommandError
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> ResultError
UnexpectedResult) (Either Text b -> Either CommandError b)
-> (a -> Either Text b) -> a -> Either CommandError b
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. a -> Either Text b
refiner