module Snap.Snaplet.PostgresqlSimple.Internal where
import Control.Monad.IO.Class
import Control.Monad.Trans
import Control.Monad.Trans.Control (MonadBaseControl(..), control)
import Control.Monad.Trans.Identity
import Control.Monad.Trans.List
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
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
import Data.Pool
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 (ListT m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (ListT m) = ListT $
setLocalPostgresState pg m
instance HasPostgres m => HasPostgres (MaybeT m) where
getPostgresState = lift getPostgresState
setLocalPostgresState pg (MaybeT m) = MaybeT $
setLocalPostgresState pg m
instance 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)