{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Snap.Snaplet.PostgresqlSimple.Internal where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans (lift)
import Control.Monad.Trans.Control (MonadBaseControl (..),
control)
import Control.Monad.Trans.Identity (IdentityT (IdentityT))
import Control.Monad.Trans.Maybe (MaybeT (MaybeT))
import Control.Monad.Trans.Reader (ReaderT (ReaderT))
import qualified Control.Monad.Trans.RWS.Lazy as LRWS
import qualified Control.Monad.Trans.RWS.Strict as SRWS
import qualified Control.Monad.Trans.State.Lazy as LS
import qualified Control.Monad.Trans.State.Strict as SS
import qualified Control.Monad.Trans.Writer.Lazy as LW
import qualified Control.Monad.Trans.Writer.Strict as SW
import Data.ByteString (ByteString)
import Data.Monoid (Monoid)
import Data.Pool (Pool, withResource)
import qualified Database.PostgreSQL.Simple as P
data Postgres = PostgresPool (Pool P.Connection)
| PostgresConn P.Connection
class (MonadIO m, MonadBaseControl IO m) => HasPostgres m where
getPostgresState :: m Postgres
setLocalPostgresState :: Postgres -> m a -> m a
instance HasPostgres m => HasPostgres (IdentityT m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (IdentityT m) = IdentityT $
setLocalPostgresState pg m
instance HasPostgres m => HasPostgres (MaybeT m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (MaybeT m) = MaybeT $
setLocalPostgresState pg m
instance {-#OVERLAPPABLE #-} HasPostgres m => HasPostgres (ReaderT r m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (ReaderT m) = ReaderT $ \e ->
setLocalPostgresState pg (m e)
instance (Monoid w, HasPostgres m) => HasPostgres (LW.WriterT w m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (LW.WriterT m) = LW.WriterT $
setLocalPostgresState pg m
instance (Monoid w, HasPostgres m) => HasPostgres (SW.WriterT w m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (SW.WriterT m) = SW.WriterT $
setLocalPostgresState pg m
instance HasPostgres m => HasPostgres (LS.StateT w m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (LS.StateT m) = LS.StateT $ \s ->
setLocalPostgresState pg (m s)
instance HasPostgres m => HasPostgres (SS.StateT w m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (SS.StateT m) = SS.StateT $ \s ->
setLocalPostgresState pg (m s)
instance (Monoid w, HasPostgres m) => HasPostgres (LRWS.RWST r w s m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (LRWS.RWST m) = LRWS.RWST $ \e s ->
setLocalPostgresState pg (m e s)
instance (Monoid w, HasPostgres m) => HasPostgres (SRWS.RWST r w s m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (SRWS.RWST m) = SRWS.RWST $ \e s ->
setLocalPostgresState pg (m e s)
data PGSConfig = PGSConfig
{ pgsConnStr :: ByteString
, pgsNumStripes :: Int
, pgsIdleTime :: Double
, pgsResources :: Int
}
pgsDefaultConfig :: ByteString
-> PGSConfig
pgsDefaultConfig connstr = PGSConfig connstr 1 5 20
withPG :: (HasPostgres m)
=> m b -> m b
withPG f = do
s <- getPostgresState
case s of
(PostgresPool p) -> withResource p (\c -> setLocalPostgresState (PostgresConn c) f)
(PostgresConn _) -> f
liftPG :: (HasPostgres m) => (P.Connection -> m a) -> m a
liftPG act = do
pg <- getPostgresState
control $ \run ->
withConnection pg $ \con -> run (act con)
liftPG' :: (HasPostgres m) => (P.Connection -> IO b) -> m b
liftPG' f = do
s <- getPostgresState
withConnection s f
withConnection :: MonadIO m => Postgres -> (P.Connection -> IO b) -> m b
withConnection (PostgresPool p) f = liftIO (withResource p f)
withConnection (PostgresConn c) f = liftIO (f c)