-- |
-- 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.Decoders.Results where

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

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

{-# INLINE run #-}
run :: Results a -> (Bool, LibPQ.Connection) -> IO (Either CommandError a)
run :: forall a.
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 :: forall a. 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 a b. (a -> b) -> IO a -> IO b
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 b c a. (b -> c) -> (a -> b) -> a -> c
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 :: forall a. 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 a b. (a -> b) -> IO a -> IO b
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 b c a. (b -> c) -> (a -> b) -> a -> c
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 a. a -> IO a
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 a b. (a -> b) -> IO a -> IO b
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 b c a. (b -> c) -> (a -> b) -> a -> c
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 (m :: * -> *) a. Monad m => m a -> ExceptT CommandError m a
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 a b.
ExceptT CommandError IO a
-> (a -> ExceptT CommandError IO b) -> ExceptT CommandError IO b
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 a. a -> ExceptT CommandError IO a
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 (m :: * -> *) a. Monad m => m a -> ExceptT CommandError m a
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 a b.
ExceptT CommandError IO a
-> ExceptT CommandError IO b -> ExceptT CommandError IO a
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 a b. (a -> b) -> IO a -> IO b
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 :: forall a b. (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 a. a -> IO a
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 a b.
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 b c a. (b -> c) -> (a -> b) -> a -> c
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 b c a. (b -> c) -> (a -> b) -> a -> c
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