hasql/library/Hasql/Private/Session.hs

59 lines
2.4 KiB
Haskell
Raw Normal View History

2015-12-21 16:11:14 +03:00
module Hasql.Private.Session
where
import Hasql.Private.Prelude
import Hasql.Private.Errors
2015-12-21 16:11:14 +03:00
import qualified Database.PostgreSQL.LibPQ as LibPQ
import qualified Hasql.Private.Decoders.Results as Decoders.Results
import qualified Hasql.Private.Decoders.Result as Decoders.Result
import qualified Hasql.Private.Encoders.Params as Encoders.Params
import qualified Hasql.Private.Settings as Settings
2015-12-21 16:11:14 +03:00
import qualified Hasql.Private.IO as IO
import qualified Hasql.Query as Query
2015-12-21 16:45:10 +03:00
import qualified Hasql.Private.Connection as Connection
2015-12-21 16:11:14 +03:00
-- |
-- A batch of actions to be executed in the context of a database connection.
newtype Session a =
Session (ReaderT Connection.Connection (ExceptT QueryError IO) a)
deriving (Functor, Applicative, Monad, MonadError QueryError, MonadIO)
2015-12-21 16:45:10 +03:00
-- |
-- Executes a bunch of commands on the provided connection.
run :: Session a -> Connection.Connection -> IO (Either QueryError a)
2015-12-21 16:45:10 +03:00
run (Session impl) connection =
2017-11-26 11:24:40 +03:00
runExceptT $
2015-12-21 16:45:10 +03:00
runReaderT impl connection
2015-12-21 16:11:14 +03:00
-- |
-- Possibly a multi-statement query,
-- which however cannot be parameterized or prepared,
-- nor can any results of it be collected.
sql :: ByteString -> Session ()
sql sql =
2016-01-06 09:39:14 +03:00
Session $ ReaderT $ \(Connection.Connection pqConnectionRef integerDatetimes registry) ->
ExceptT $ fmap (mapLeft (QueryError sql [])) $ withMVar pqConnectionRef $ \pqConnection -> do
2016-01-24 19:52:53 +03:00
r1 <- IO.sendNonparametricQuery pqConnection sql
r2 <- IO.getResults pqConnection integerDatetimes decoder
return $ r1 *> r2
2016-01-22 18:50:13 +03:00
where
decoder =
Decoders.Results.single Decoders.Result.unit
2015-12-21 16:11:14 +03:00
-- |
-- Parameters and a specification of the parametric query to apply them to.
query :: params -> Query.Query params result -> Session result
query input (Query.Query template encoder decoder preparable) =
Session $ ReaderT $ \(Connection.Connection pqConnectionRef integerDatetimes registry) ->
ExceptT $ fmap (mapLeft (QueryError template inputReps)) $ withMVar pqConnectionRef $ \pqConnection -> do
r1 <- IO.sendParametricQuery pqConnection integerDatetimes registry template (unsafeCoerce encoder) preparable input
r2 <- IO.getResults pqConnection integerDatetimes (unsafeCoerce decoder)
return $ r1 *> r2
where
inputReps =
let
Encoders.Params.Params (Op encoderOp) = (unsafeCoerce encoder)
step (_, _, _, rendering) acc =
rendering : acc
in foldr step [] (encoderOp input)