module Database.GP.Conn ( Conn (..), connect, Database (..), ConnectionPool, createConnPool, withResource, ) where import Control.Monad ((>=>)) import Data.Pool (Pool, PoolConfig, defaultPoolConfig, newPool, withResource) import Database.HDBC (IConnection (..)) -- | -- This module defines a wrapper around an HDBC IConnection. -- Using this wrapper `Conn` simplifies the signature of the functions in the `Database.GP` module. -- It allows to use any HDBC connection without having to define a new function for each connection type. -- It also provides additional attributes to the connection, like the database type and the implicit commit flag. -- These attributes can be used to implement database specific functionality, modify transaction behaviour, etc. -- -- This code has been inspired by the HDBC ConnectionWrapper and some parts have been copied verbatim -- from the HDBC Database.HDBC.Types module. -- -- This module also defines a ConnectionPool type, which provides basic connection pooling functionality. -- | A wrapper around an HDBC IConnection. data Conn = forall conn. IConnection conn => Conn { -- | The database type db :: Database, -- | If True, the GenericPersistence functions will commit the transaction after each operation. implicitCommit :: Bool, -- | The wrapped connection connection :: conn } -- | An enumeration of the supported database types. data Database = Postgres | MySQL | SQLite | Oracle | MSSQL deriving (Show, Eq, Enum) -- | a smart constructor for the Conn type. connect :: forall conn. IConnection conn => Database -> conn -> Conn connect db = Conn db True -- | allows to execute a function that requires an `IConnection` argument on a `Conn`. withWConn :: forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b withWConn (Conn _db _ic conn) f = f conn -- | manually implement the IConnection type class for the Conn type. instance IConnection Conn where disconnect w = withWConn w disconnect commit w = withWConn w commit rollback w = withWConn w rollback runRaw w = withWConn w runRaw run w = withWConn w run prepare w = withWConn w prepare clone w@(Conn db ic _) = withWConn w (clone >=> return . Conn db ic) hdbcDriverName w = withWConn w hdbcDriverName hdbcClientVer w = withWConn w hdbcClientVer proxiedClientName w = withWConn w proxiedClientName proxiedClientVer w = withWConn w proxiedClientVer dbServerVer w = withWConn w dbServerVer dbTransactionSupport w = withWConn w dbTransactionSupport getTables w = withWConn w getTables describeTable w = withWConn w describeTable -- | A pool of connections. type ConnectionPool = Pool Conn -- | Creates a connection pool. createConnPool :: IConnection conn => -- | the database type e.g. Postgres, MySQL, SQLite Database -> -- | the connection string String -> -- | a function that takes a connection string and returns an IConnection (String -> IO conn) -> -- | the time (in seconds) to keep idle connections open Double -> -- | the maximum number of connections to keep open Int -> -- | the resulting connection pool IO ConnectionPool createConnPool db connectString connectFun idle numConns = newPool poolConfig where freshConnection :: IO Conn freshConnection = connect db <$> connectFun connectString poolConfig :: PoolConfig Conn poolConfig = defaultPoolConfig freshConnection disconnect idle numConns