{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | General class declarations
module PostgreSQL.Class
  ( RunQuery (..)
  , runQueryThrow
  )
where

import qualified Control.Monad.Catch as Catch
import           Control.Monad.Trans (MonadTrans (lift))
import qualified Data.List.NonEmpty as NonEmpty
import           PostgreSQL.Query.Class (Query)
import           PostgreSQL.Types (Errors)

-- | PostgreSQL queries can be executed in @m@
--
-- @since 0.0.0
class Query query => RunQuery query m | m -> query where
  -- | Run a query.
  --
  -- @since 0.0.0
  runQuery :: query a -> m (Either Errors a)

-- | Like 'runQuery' but throws the first error instead.
--
-- @since 0.0.0
runQueryThrow :: (Catch.MonadThrow m, RunQuery query m) => query a -> m a
runQueryThrow :: query a -> m a
runQueryThrow query a
query = do
  Either Errors a
err <- query a -> m (Either Errors a)
forall (query :: * -> *) (m :: * -> *) a.
RunQuery query m =>
query a -> m (Either Errors a)
runQuery query a
query
  (Errors -> m a) -> (a -> m a) -> Either Errors a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Error -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
Catch.throwM (Error -> m a) -> (Errors -> Error) -> Errors -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Errors -> Error
forall a. NonEmpty a -> a
NonEmpty.head) a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Either Errors a
err

{-# INLINE runQueryThrow #-}

-- | @since 0.0.0
instance
  {-# OVERLAPPABLE #-}
  (RunQuery query m, Monad m, MonadTrans t)
  => RunQuery query (t m)
  where
    runQuery :: query a -> t m (Either Errors a)
runQuery query a
query = m (Either Errors a) -> t m (Either Errors a)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (query a -> m (Either Errors a)
forall (query :: * -> *) (m :: * -> *) a.
RunQuery query m =>
query a -> m (Either Errors a)
runQuery query a
query)

    {-# INLINE runQuery #-}