module Database.Persist.Sql.Run where
import Database.Persist.Sql.Types
import Database.Persist.Sql.Raw
import Control.Monad.Trans.Control
import Data.Pool as P
import Control.Monad.Trans.Reader hiding (local)
import Control.Monad.Trans.Resource
import Control.Monad.Logger
import Control.Monad.Base
import Control.Exception.Lifted (onException, bracket)
import Control.Monad.IO.Class
import Control.Exception (mask)
import System.Timeout (timeout)
import Data.IORef (readIORef, writeIORef, newIORef)
import qualified Data.Map as Map
import Control.Monad (liftM)
runSqlPool :: MonadBaseControl IO m => SqlPersistT m a -> Pool SqlBackend -> m a
runSqlPool r pconn = withResource pconn $ runSqlConn r
withResourceTimeout
:: forall a m b. (MonadBaseControl IO m)
=> Int
-> Pool a
-> (a -> m b)
-> m (Maybe b)
withResourceTimeout ms pool act = control $ \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
runSqlConn :: MonadBaseControl IO m => SqlPersistT m a -> SqlBackend -> m a
runSqlConn r conn = do
let getter = getStmtConn conn
liftBase $ connBegin conn getter
x <- onException
(runReaderT r conn)
(liftBase $ connRollback conn getter)
liftBase $ connCommit conn getter
return x
runSqlPersistM :: SqlPersistM a -> SqlBackend -> IO a
runSqlPersistM x conn = runResourceT $ runNoLoggingT $ runSqlConn x conn
runSqlPersistMPool :: SqlPersistM a -> Pool SqlBackend -> IO a
runSqlPersistMPool x pool = runResourceT $ runNoLoggingT $ runSqlPool x pool
withSqlPool :: (MonadIO m, MonadLogger m, MonadBaseControl IO m)
=> (LogFunc -> IO SqlBackend)
-> Int
-> (Pool SqlBackend -> m a)
-> m a
withSqlPool mkConn connCount f = do
bracket (createSqlPool mkConn connCount) (liftIO . destroyAllResources) f
createSqlPool :: (MonadIO m, MonadLogger m, MonadBaseControl IO m)
=> (LogFunc -> IO SqlBackend)
-> Int
-> m (Pool SqlBackend)
createSqlPool mkConn size = do
logFunc <- askLogFunc
liftIO $ createPool (mkConn logFunc) close' 1 20 size
askLogFunc :: forall m. (MonadBaseControl IO m, MonadLogger m) => m LogFunc
askLogFunc = do
ref <- liftBase $ newIORef undefined
liftBaseWith $ \run -> writeIORef ref run
runInBase <- liftBase $ readIORef ref
return $ \a b c d -> do
_ <- runInBase (monadLoggerLog a b c d)
return ()
withSqlConn :: (MonadIO m, MonadBaseControl IO m, MonadLogger m)
=> (LogFunc -> IO SqlBackend) -> (SqlBackend -> m a) -> m a
withSqlConn open f = do
logFunc <- askLogFunc
bracket (liftIO $ open logFunc) (liftIO . close') f
close' :: SqlBackend -> IO ()
close' conn = do
readIORef (connStmtMap conn) >>= mapM_ stmtFinalize . Map.elems
connClose conn