{-# LANGUAGE ScopedTypeVariables #-}
module Database.Persist.Sql.Run where
import Control.Exception (bracket, mask, onException)
import Control.Monad (liftM)
import Control.Monad.IO.Unlift
import Control.Monad.Logger
import Control.Monad.Trans.Reader hiding (local)
import Control.Monad.Trans.Resource
import Data.IORef (readIORef)
import Data.Pool as P
import qualified Data.Map as Map
import System.Timeout (timeout)
import Database.Persist.Class.PersistStore
import Database.Persist.Sql.Types
import Database.Persist.Sql.Types.Internal (IsolationLevel)
import Database.Persist.Sql.Raw
runSqlPool
:: (MonadUnliftIO m, BackendCompatible SqlBackend backend)
=> ReaderT backend m a -> Pool backend -> m a
runSqlPool r pconn = withRunInIO $ \run -> withResource pconn $ run . runSqlConn r
runSqlPoolWithIsolation
:: (MonadUnliftIO m, BackendCompatible SqlBackend backend)
=> ReaderT backend m a -> Pool backend -> IsolationLevel -> m a
runSqlPoolWithIsolation r pconn i = withRunInIO $ \run -> withResource pconn $ run . (\conn -> runSqlConnWithIsolation r conn i)
withResourceTimeout
:: forall a m b. (MonadUnliftIO m)
=> Int
-> Pool a
-> (a -> m b)
-> m (Maybe b)
{-# SPECIALIZE withResourceTimeout :: Int -> Pool a -> (a -> IO b) -> IO (Maybe b) #-}
withResourceTimeout ms pool act = withRunInIO $ \runInIO -> mask $ \restore -> do
mres <- timeout ms $ takeResource pool
case mres of
Nothing -> runInIO $ return (Nothing :: Maybe b)
Just (resource, local) -> do
ret <- restore (runInIO (liftM Just $ act resource)) `onException`
destroyResource pool local resource
putResource local resource
return ret
{-# INLINABLE withResourceTimeout #-}
runSqlConn :: (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> m a
runSqlConn r conn = withRunInIO $ \runInIO -> mask $ \restore -> do
let conn' = projectBackend conn
getter = getStmtConn conn'
restore $ connBegin conn' getter Nothing
x <- onException
(restore $ runInIO $ runReaderT r conn)
(restore $ connRollback conn' getter)
restore $ connCommit conn' getter
return x
runSqlConnWithIsolation :: (MonadUnliftIO m, BackendCompatible SqlBackend backend) => ReaderT backend m a -> backend -> IsolationLevel -> m a
runSqlConnWithIsolation r conn isolation = withRunInIO $ \runInIO -> mask $ \restore -> do
let conn' = projectBackend conn
getter = getStmtConn conn'
restore $ connBegin conn' getter $ Just isolation
x <- onException
(restore $ runInIO $ runReaderT r conn)
(restore $ connRollback conn' getter)
restore $ connCommit conn' getter
return x
runSqlPersistM
:: (BackendCompatible SqlBackend backend)
=> ReaderT backend (NoLoggingT (ResourceT IO)) a -> backend -> IO a
runSqlPersistM x conn = runResourceT $ runNoLoggingT $ runSqlConn x conn
runSqlPersistMPool
:: (BackendCompatible SqlBackend backend)
=> ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> IO a
runSqlPersistMPool x pool = runResourceT $ runNoLoggingT $ runSqlPool x pool
liftSqlPersistMPool
:: (MonadIO m, BackendCompatible SqlBackend backend)
=> ReaderT backend (NoLoggingT (ResourceT IO)) a -> Pool backend -> m a
liftSqlPersistMPool x pool = liftIO (runSqlPersistMPool x pool)
withSqlPool
:: (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
=> (LogFunc -> IO backend)
-> Int
-> (Pool backend -> m a)
-> m a
withSqlPool mkConn connCount f = withUnliftIO $ \u -> bracket
(unliftIO u $ createSqlPool mkConn connCount)
destroyAllResources
(unliftIO u . f)
createSqlPool
:: (MonadLogger m, MonadUnliftIO m, BackendCompatible SqlBackend backend)
=> (LogFunc -> IO backend)
-> Int
-> m (Pool backend)
createSqlPool mkConn size = do
logFunc <- askLogFunc
liftIO $ createPool (mkConn logFunc) close' 1 20 size
askLogFunc :: forall m. (MonadUnliftIO m, MonadLogger m) => m LogFunc
askLogFunc = withRunInIO $ \run ->
return $ \a b c d -> run (monadLoggerLog a b c d)
withSqlConn
:: (MonadUnliftIO m, MonadLogger m, BackendCompatible SqlBackend backend)
=> (LogFunc -> IO backend) -> (backend -> m a) -> m a
withSqlConn open f = do
logFunc <- askLogFunc
withRunInIO $ \run -> bracket
(open logFunc)
close'
(run . f)
close' :: (BackendCompatible SqlBackend backend) => backend -> IO ()
close' conn = do
readIORef (connStmtMap $ projectBackend conn) >>= mapM_ stmtFinalize . Map.elems
connClose $ projectBackend conn