-- | Definition of internal DBT state.
module Database.PostgreSQL.PQTypes.Internal.State
  ( DBState (..)
  , updateStateWith
  ) where

import Foreign.ForeignPtr

import Database.PostgreSQL.PQTypes.FromRow
import Database.PostgreSQL.PQTypes.Internal.C.Types
import Database.PostgreSQL.PQTypes.Internal.Connection
import Database.PostgreSQL.PQTypes.Internal.QueryResult
import Database.PostgreSQL.PQTypes.SQL.Class
import Database.PostgreSQL.PQTypes.Transaction.Settings

-- | Internal DB state.
data DBState m = DBState
  { forall (m :: * -> *). DBState m -> Connection
dbConnection :: !Connection
  -- ^ Active connection.
  , forall (m :: * -> *). DBState m -> ConnectionSourceM m
dbConnectionSource :: !(ConnectionSourceM m)
  -- ^ Supplied connection source.
  , forall (m :: * -> *). DBState m -> TransactionSettings
dbTransactionSettings :: !TransactionSettings
  -- ^ Current transaction settings.
  , forall (m :: * -> *). DBState m -> SomeSQL
dbLastQuery :: !SomeSQL
  -- ^ Last SQL query that was executed.
  , forall (m :: * -> *). DBState m -> Bool
dbRecordLastQuery :: !Bool
  -- ^ Whether running query should override 'dbLastQuery'.
  , forall (m :: * -> *).
DBState m -> forall row. FromRow row => Maybe (QueryResult row)
dbQueryResult :: !(forall row. FromRow row => Maybe (QueryResult row))
  -- ^ Current query result.
  }

updateStateWith
  :: IsSQL sql
  => DBState m
  -> sql
  -> (r, ForeignPtr PGresult)
  -> IO (r, DBState m)
updateStateWith :: forall sql (m :: * -> *) r.
IsSQL sql =>
DBState m -> sql -> (r, ForeignPtr PGresult) -> IO (r, DBState m)
updateStateWith DBState m
st sql
sql (r
r, ForeignPtr PGresult
res) = do
  BackendPid
pid <- Connection -> IO BackendPid
getBackendPidIO (Connection -> IO BackendPid) -> Connection -> IO BackendPid
forall a b. (a -> b) -> a -> b
$ DBState m -> Connection
forall (m :: * -> *). DBState m -> Connection
dbConnection DBState m
st
  (r, DBState m) -> IO (r, DBState m)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    ( r
r
    , DBState m
st
        { dbLastQuery =
            if dbRecordLastQuery st
              then SomeSQL sql
              else dbLastQuery st
        , dbQueryResult = Just $ mkQueryResult sql pid res
        }
    )