module Database.Persist.SqlBackend.SqlPoolHooks
  ( SqlPoolHooks
  , defaultSqlPoolHooks
  , getAlterBackend
  , modifyAlterBackend
  , setAlterBackend
  , getRunBefore
  , modifyRunBefore
  , setRunBefore
  , getRunAfter
  , modifyRunAfter
  , setRunAfter
  , getRunOnException
  )
  where

import Control.Exception
import Control.Monad.IO.Class
import Database.Persist.Sql.Raw
import Database.Persist.SqlBackend.Internal
import Database.Persist.SqlBackend.Internal.SqlPoolHooks
import Database.Persist.SqlBackend.Internal.IsolationLevel
import Database.Persist.Class.PersistStore

-- | Lifecycle hooks that may be altered to extend SQL pool behavior
-- in a backwards compatible fashion.
--
-- By default, the hooks have the following semantics:
--
-- - 'alterBackend' has no effect
-- - 'runBefore' begins a transaction
-- - 'runAfter' commits the current transaction
-- - 'runOnException' rolls back the current transaction
--
-- @since 2.13.3.0
defaultSqlPoolHooks :: (MonadIO m, BackendCompatible SqlBackend backend) => SqlPoolHooks m backend
defaultSqlPoolHooks :: forall (m :: * -> *) backend.
(MonadIO m, BackendCompatible SqlBackend backend) =>
SqlPoolHooks m backend
defaultSqlPoolHooks = SqlPoolHooks
    { alterBackend :: backend -> m backend
alterBackend = backend -> m backend
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    , runBefore :: backend -> Maybe IsolationLevel -> m ()
runBefore = \backend
conn Maybe IsolationLevel
mi -> do
        let sqlBackend :: SqlBackend
sqlBackend = backend -> SqlBackend
forall sup sub. BackendCompatible sup sub => sub -> sup
projectBackend backend
conn
        let getter :: Text -> IO Statement
getter = SqlBackend -> Text -> IO Statement
getStmtConn SqlBackend
sqlBackend
        IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ SqlBackend
-> (Text -> IO Statement) -> Maybe IsolationLevel -> IO ()
connBegin SqlBackend
sqlBackend Text -> IO Statement
getter Maybe IsolationLevel
mi
    , runAfter :: backend -> Maybe IsolationLevel -> m ()
runAfter = \backend
conn Maybe IsolationLevel
_ -> do
        let sqlBackend :: SqlBackend
sqlBackend = backend -> SqlBackend
forall sup sub. BackendCompatible sup sub => sub -> sup
projectBackend backend
conn
        let getter :: Text -> IO Statement
getter = SqlBackend -> Text -> IO Statement
getStmtConn SqlBackend
sqlBackend
        IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ SqlBackend -> (Text -> IO Statement) -> IO ()
connCommit SqlBackend
sqlBackend Text -> IO Statement
getter
    , runOnException :: backend -> Maybe IsolationLevel -> SomeException -> m ()
runOnException = \backend
conn Maybe IsolationLevel
_ SomeException
_ -> do
        let sqlBackend :: SqlBackend
sqlBackend = backend -> SqlBackend
forall sup sub. BackendCompatible sup sub => sub -> sup
projectBackend backend
conn
        let getter :: Text -> IO Statement
getter = SqlBackend -> Text -> IO Statement
getStmtConn SqlBackend
sqlBackend
        IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ SqlBackend -> (Text -> IO Statement) -> IO ()
connRollback SqlBackend
sqlBackend Text -> IO Statement
getter
    }

getAlterBackend :: SqlPoolHooks m backend -> (backend -> m backend)
getAlterBackend :: forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> m backend
getAlterBackend = SqlPoolHooks m backend -> backend -> m backend
forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> m backend
alterBackend

modifyAlterBackend :: SqlPoolHooks m backend -> ((backend -> m backend) -> (backend -> m backend)) -> SqlPoolHooks m backend
modifyAlterBackend :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> ((backend -> m backend) -> backend -> m backend)
-> SqlPoolHooks m backend
modifyAlterBackend SqlPoolHooks m backend
hooks (backend -> m backend) -> backend -> m backend
f = SqlPoolHooks m backend
hooks { alterBackend = f $ alterBackend hooks }

setAlterBackend :: SqlPoolHooks m backend -> (backend -> m backend) -> SqlPoolHooks m backend
setAlterBackend :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> (backend -> m backend) -> SqlPoolHooks m backend
setAlterBackend SqlPoolHooks m backend
hooks backend -> m backend
f = SqlPoolHooks m backend
hooks { alterBackend = f }


getRunBefore :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ())
getRunBefore :: forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
getRunBefore = SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
runBefore

modifyRunBefore :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> m ()) -> (backend -> Maybe IsolationLevel -> m ())) -> SqlPoolHooks m backend
modifyRunBefore :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> ((backend -> Maybe IsolationLevel -> m ())
    -> backend -> Maybe IsolationLevel -> m ())
-> SqlPoolHooks m backend
modifyRunBefore SqlPoolHooks m backend
hooks (backend -> Maybe IsolationLevel -> m ())
-> backend -> Maybe IsolationLevel -> m ()
f = SqlPoolHooks m backend
hooks { runBefore = f $ runBefore hooks }

setRunBefore :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ()) -> SqlPoolHooks m backend
setRunBefore :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> (backend -> Maybe IsolationLevel -> m ())
-> SqlPoolHooks m backend
setRunBefore SqlPoolHooks m backend
h backend -> Maybe IsolationLevel -> m ()
f = SqlPoolHooks m backend
h { runBefore = f }


getRunAfter :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ())
getRunAfter :: forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
getRunAfter = SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
forall (m :: * -> *) backend.
SqlPoolHooks m backend -> backend -> Maybe IsolationLevel -> m ()
runAfter

modifyRunAfter :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> m ()) -> (backend -> Maybe IsolationLevel -> m ())) -> SqlPoolHooks m backend
modifyRunAfter :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> ((backend -> Maybe IsolationLevel -> m ())
    -> backend -> Maybe IsolationLevel -> m ())
-> SqlPoolHooks m backend
modifyRunAfter SqlPoolHooks m backend
hooks (backend -> Maybe IsolationLevel -> m ())
-> backend -> Maybe IsolationLevel -> m ()
f = SqlPoolHooks m backend
hooks { runAfter = f $ runAfter hooks }

setRunAfter :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> m ()) -> SqlPoolHooks m backend
setRunAfter :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> (backend -> Maybe IsolationLevel -> m ())
-> SqlPoolHooks m backend
setRunAfter SqlPoolHooks m backend
hooks backend -> Maybe IsolationLevel -> m ()
f = SqlPoolHooks m backend
hooks { runAfter = f }


getRunOnException :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> SomeException -> m ())
getRunOnException :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> backend -> Maybe IsolationLevel -> SomeException -> m ()
getRunOnException = SqlPoolHooks m backend
-> backend -> Maybe IsolationLevel -> SomeException -> m ()
forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> backend -> Maybe IsolationLevel -> SomeException -> m ()
runOnException

modifyRunOnException :: SqlPoolHooks m backend -> ((backend -> Maybe IsolationLevel -> SomeException -> m ()) -> (backend -> Maybe IsolationLevel -> SomeException -> m ())) -> SqlPoolHooks m backend
modifyRunOnException :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> ((backend -> Maybe IsolationLevel -> SomeException -> m ())
    -> backend -> Maybe IsolationLevel -> SomeException -> m ())
-> SqlPoolHooks m backend
modifyRunOnException SqlPoolHooks m backend
hooks (backend -> Maybe IsolationLevel -> SomeException -> m ())
-> backend -> Maybe IsolationLevel -> SomeException -> m ()
f = SqlPoolHooks m backend
hooks { runOnException = f $ runOnException hooks }

setRunOnException :: SqlPoolHooks m backend -> (backend -> Maybe IsolationLevel -> SomeException -> m ()) -> SqlPoolHooks m backend
setRunOnException :: forall (m :: * -> *) backend.
SqlPoolHooks m backend
-> (backend -> Maybe IsolationLevel -> SomeException -> m ())
-> SqlPoolHooks m backend
setRunOnException SqlPoolHooks m backend
hooks backend -> Maybe IsolationLevel -> SomeException -> m ()
f = SqlPoolHooks m backend
hooks { runOnException = f }