{-# LANGUAGE OverlappingInstances #-}
{-# OPTIONS_GHC -fno-warn-deprecated-flags #-}
module Database.PostgreSQL.PQTypes.Class (
    MonadDB(..)
  ) where

import Control.Monad.Trans
import Control.Monad.Trans.Control

import Database.PostgreSQL.PQTypes.FromRow
import Database.PostgreSQL.PQTypes.Internal.Connection
import Database.PostgreSQL.PQTypes.Internal.Notification
import Database.PostgreSQL.PQTypes.Internal.QueryResult
import Database.PostgreSQL.PQTypes.SQL.Class
import Database.PostgreSQL.PQTypes.Transaction.Settings

class (Applicative m, Monad m) => MonadDB m where
  -- | Run SQL query and return number of affected/returned rows. Note that
  -- for a given connection, only one thread may be executing 'runQuery' at
  -- a given time. If simultaneous call is made from another thread, it
  -- will block until currently running 'runQuery' finishes.
  runQuery :: IsSQL sql => sql -> m Int
  -- | Get last SQL query that was executed.
  getLastQuery :: m SomeSQL
  -- | Subsequent queries in the callback do not alter the result of
  -- 'getLastQuery'.
  withFrozenLastQuery :: m a -> m a

  -- | Get current connection statistics.
  getConnectionStats :: m ConnectionStats

  -- | Get current query result.
  getQueryResult :: FromRow row => m (Maybe (QueryResult row))
  -- | Clear current query result.
  clearQueryResult :: m ()

  -- | Get current transaction settings.
  getTransactionSettings :: m TransactionSettings
  -- | Set transaction settings to supplied ones. Note that it
  -- won't change any properties of currently running transaction,
  -- only the subsequent ones.
  setTransactionSettings :: TransactionSettings -> m ()

  -- | Attempt to receive a notification from the server. This
  -- function waits until a notification arrives or specified
  -- number of microseconds has passed. If a negative number
  -- of microseconds is passed as an argument, it will wait
  -- indefinitely. In addition, there are a couple of things
  -- to be aware of:
  --
  -- * A lock on the underlying database connection is acquired
  -- for the duration of the function.
  --
  -- * Notifications can be received only between transactions
  -- (see <http://www.postgresql.org/docs/current/static/sql-notify.html>
  -- for further info), therefore calling this function within
  -- a transaction block will return 'Just' only if notifications
  -- were received before the transaction began.
  getNotification :: Int -> m (Maybe Notification)

  -- | Execute supplied monadic action with new connection
  -- using current connection source and transaction settings.
  --
  -- Particularly useful when you want to spawn a new thread, but
  -- do not want the connection in child thread to be shared with
  -- the parent one.
  withNewConnection :: m a -> m a

-- | Generic, overlapping instance.
instance (
    Applicative (t m)
  , Monad (t m)
  , MonadTrans t
  , MonadTransControl t
  , MonadDB m
  ) => MonadDB (t m) where
    runQuery :: sql -> t m Int
runQuery = m Int -> t m Int
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m Int -> t m Int) -> (sql -> m Int) -> sql -> t m Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. sql -> m Int
forall (m :: * -> *) sql. (MonadDB m, IsSQL sql) => sql -> m Int
runQuery
    getLastQuery :: t m SomeSQL
getLastQuery = m SomeSQL -> t m SomeSQL
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m SomeSQL
forall (m :: * -> *). MonadDB m => m SomeSQL
getLastQuery
    withFrozenLastQuery :: t m a -> t m a
withFrozenLastQuery t m a
m = (Run t -> m (StT t a)) -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTransControl t, Monad (t m), Monad m) =>
(Run t -> m (StT t a)) -> t m a
controlT ((Run t -> m (StT t a)) -> t m a)
-> (Run t -> m (StT t a)) -> t m a
forall a b. (a -> b) -> a -> b
$ \Run t
run -> m (StT t a) -> m (StT t a)
forall (m :: * -> *) a. MonadDB m => m a -> m a
withFrozenLastQuery (t m a -> m (StT t a)
Run t
run t m a
m)
    getConnectionStats :: t m ConnectionStats
getConnectionStats = m ConnectionStats -> t m ConnectionStats
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m ConnectionStats
forall (m :: * -> *). MonadDB m => m ConnectionStats
getConnectionStats
    getQueryResult :: t m (Maybe (QueryResult row))
getQueryResult = m (Maybe (QueryResult row)) -> t m (Maybe (QueryResult row))
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m (Maybe (QueryResult row))
forall (m :: * -> *) row.
(MonadDB m, FromRow row) =>
m (Maybe (QueryResult row))
getQueryResult
    clearQueryResult :: t m ()
clearQueryResult = m () -> t m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m ()
forall (m :: * -> *). MonadDB m => m ()
clearQueryResult
    getTransactionSettings :: t m TransactionSettings
getTransactionSettings = m TransactionSettings -> t m TransactionSettings
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m TransactionSettings
forall (m :: * -> *). MonadDB m => m TransactionSettings
getTransactionSettings
    setTransactionSettings :: TransactionSettings -> t m ()
setTransactionSettings = m () -> t m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m () -> t m ())
-> (TransactionSettings -> m ()) -> TransactionSettings -> t m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransactionSettings -> m ()
forall (m :: * -> *). MonadDB m => TransactionSettings -> m ()
setTransactionSettings
    getNotification :: Int -> t m (Maybe Notification)
getNotification = m (Maybe Notification) -> t m (Maybe Notification)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Maybe Notification) -> t m (Maybe Notification))
-> (Int -> m (Maybe Notification))
-> Int
-> t m (Maybe Notification)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> m (Maybe Notification)
forall (m :: * -> *). MonadDB m => Int -> m (Maybe Notification)
getNotification
    withNewConnection :: t m a -> t m a
withNewConnection t m a
m = (Run t -> m (StT t a)) -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTransControl t, Monad (t m), Monad m) =>
(Run t -> m (StT t a)) -> t m a
controlT ((Run t -> m (StT t a)) -> t m a)
-> (Run t -> m (StT t a)) -> t m a
forall a b. (a -> b) -> a -> b
$ \Run t
run -> m (StT t a) -> m (StT t a)
forall (m :: * -> *) a. MonadDB m => m a -> m a
withNewConnection (t m a -> m (StT t a)
Run t
run t m a
m)
    {-# INLINE runQuery #-}
    {-# INLINE getLastQuery #-}
    {-# INLINE withFrozenLastQuery #-}
    {-# INLINE getConnectionStats #-}
    {-# INLINE getQueryResult #-}
    {-# INLINE clearQueryResult #-}
    {-# INLINE getTransactionSettings #-}
    {-# INLINE setTransactionSettings #-}
    {-# INLINE getNotification #-}
    {-# INLINE withNewConnection #-}