module Database.GP.Conn
  ( Conn (..),
    connect,
    Database (..),
  )
where

import           Control.Monad ((>=>))
import           Database.HDBC hiding (withWConn)

{- | 
  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 from the HDBC Database.HDBC.Types module.
-}

-- | A wrapper around an HDBC IConnection.
data Conn = forall conn.
  IConnection conn =>
  Conn
  { -- | The database type
    Conn -> Database
db             :: Database,
    -- | If True, the GenericPersistence functions will commit the transaction after each operation.
    Conn -> Bool
implicitCommit :: Bool,
    -- | The wrapped connection
    ()
connection     :: conn
  }

-- | An enumeration of the supported database types.
data Database = Postgres | MySQL | SQLite | Oracle | MSSQL
  deriving (Int -> Database -> ShowS
[Database] -> ShowS
Database -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Database] -> ShowS
$cshowList :: [Database] -> ShowS
show :: Database -> String
$cshow :: Database -> String
showsPrec :: Int -> Database -> ShowS
$cshowsPrec :: Int -> Database -> ShowS
Show, Database -> Database -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Database -> Database -> Bool
$c/= :: Database -> Database -> Bool
== :: Database -> Database -> Bool
$c== :: Database -> Database -> Bool
Eq, Int -> Database
Database -> Int
Database -> [Database]
Database -> Database
Database -> Database -> [Database]
Database -> Database -> Database -> [Database]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Database -> Database -> Database -> [Database]
$cenumFromThenTo :: Database -> Database -> Database -> [Database]
enumFromTo :: Database -> Database -> [Database]
$cenumFromTo :: Database -> Database -> [Database]
enumFromThen :: Database -> Database -> [Database]
$cenumFromThen :: Database -> Database -> [Database]
enumFrom :: Database -> [Database]
$cenumFrom :: Database -> [Database]
fromEnum :: Database -> Int
$cfromEnum :: Database -> Int
toEnum :: Int -> Database
$ctoEnum :: Int -> Database
pred :: Database -> Database
$cpred :: Database -> Database
succ :: Database -> Database
$csucc :: Database -> Database
Enum)

-- | a smart constructor for the Conn type.
connect :: forall conn. IConnection conn => Database -> conn -> Conn
connect :: forall conn. IConnection conn => Database -> conn -> Conn
connect Database
db = forall conn. IConnection conn => Database -> Bool -> conn -> Conn
Conn Database
db Bool
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 :: forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn (Conn Database
_db Bool
_ic conn
conn) forall conn. IConnection conn => conn -> b
f = forall conn. IConnection conn => conn -> b
f conn
conn
    

-- | manually implement the IConnection type class for the Conn type.
instance IConnection Conn where
  disconnect :: Conn -> IO ()
disconnect Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> IO ()
disconnect
  commit :: Conn -> IO ()
commit Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> IO ()
commit
  rollback :: Conn -> IO ()
rollback Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> IO ()
rollback
  runRaw :: Conn -> String -> IO ()
runRaw Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String -> IO ()
runRaw
  run :: Conn -> String -> [SqlValue] -> IO Integer
run Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn.
IConnection conn =>
conn -> String -> [SqlValue] -> IO Integer
run
  prepare :: Conn -> String -> IO Statement
prepare Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String -> IO Statement
prepare
  clone :: Conn -> IO Conn
clone w :: Conn
w@(Conn Database
db Bool
ic conn
_) = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w (forall conn. IConnection conn => conn -> IO conn
clone forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall conn. IConnection conn => Database -> Bool -> conn -> Conn
Conn Database
db Bool
ic)
  hdbcDriverName :: Conn -> String
hdbcDriverName Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String
hdbcDriverName
  hdbcClientVer :: Conn -> String
hdbcClientVer Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String
hdbcClientVer
  proxiedClientName :: Conn -> String
proxiedClientName Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String
proxiedClientName
  proxiedClientVer :: Conn -> String
proxiedClientVer Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String
proxiedClientVer
  dbServerVer :: Conn -> String
dbServerVer Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> String
dbServerVer
  dbTransactionSupport :: Conn -> Bool
dbTransactionSupport Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> Bool
dbTransactionSupport
  getTables :: Conn -> IO [String]
getTables Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn. IConnection conn => conn -> IO [String]
getTables
  describeTable :: Conn -> String -> IO [(String, SqlColDesc)]
describeTable Conn
w = forall b. Conn -> (forall conn. IConnection conn => conn -> b) -> b
withWConn Conn
w forall conn.
IConnection conn =>
conn -> String -> IO [(String, SqlColDesc)]
describeTable