| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Hasql.Session
Documentation
A sequence of operations to be executed in the context of a single database connection with exclusive access to it.
Construct sessions using helpers in this module such as
statement, pipeline and script, or use onLibpqConnection for a low-level
escape hatch.
To actually execute a Session use use, which manages
concurrent access to the shared connection state and returns either a
UseError or the result:
result <- Hasql.Connection.use connection mySession
The MonadError instance ranges over
SessionError only - the failures that leave the connection
usable. A failure that leaves the connection gone
(ConnectionUseError) is not a value
throwError can construct or
catchError can see: it propagates through every
later >>= untouched and reaches use
whole. This is enforced structurally by this Monad instance rather than
by a check any handler has to remember to make.
A caught error retains every connection-state change made before it -
both branches below thread the state through, matching ExceptT e (State
s) rather than StateT s (Either e). A statement whose PARSE succeeded
and whose EXECUTE failed has truthfully been prepared on the server, so
the cache entry survives the catch; only statement and pipeline
revert it themselves, on an ordinary failure, since they alone know
whether what they recorded was actually confirmed by the server.
Note: while most session errors are returned as values, user code executed
inside a session may still throw exceptions, and an interruption from
another thread (timeout, killThread)
arrives the same way. Such an exception propagates out of
use, which finishes the connection on the way out rather
than trying to bring it back to a clean state.
Instances
| Applicative Session # | |
| Functor Session # | |
| Monad Session # | |
| MonadIO Session # | |
Defined in Hasql.Engine.Contexts.Session | |
| MonadError SessionError Session # | Ranges over |
Defined in Hasql.Engine.Contexts.Session Methods throwError :: SessionError -> Session a # catchError :: Session a -> (SessionError -> Session a) -> Session a # | |
script :: Text -> Session () #
Possibly a multi-statement query, which however cannot be parameterized or prepared, nor can any results of it be collected.
statement :: params -> Statement params result -> Session result #
Execute a statement by providing parameters to it.
onLibpqConnection :: (Connection -> IO (Either UseError a, Connection)) -> Session a #
Execute an operation on the raw libpq connection possibly producing an error and updating the connection. This is a low-level escape hatch for custom integrations.
You can supply a new connection in the result to replace it in the running Hasql connection. The responsibility to close the old libpq connection is on you. Otherwise, just return the same connection you've received.
Producing a Left value will cause the session to fail with the given error.
Regardless of success or failure, the connection will be replaced with the one you return.
Throwing exceptions is okay, but it costs the connection:
use finishes the one it handed to the session and spends
the handle. It finishes that one - not any replacement you returned before
the exception, since an exception unwinds past the state carrying it. A
replacement lost that way is yours to close, like the connection it
displaced.
Restoring the connection is on you on the ordinary return path. Whatever
protocol state you leave it in - pipeline mode still on, results
undrained, a command in progress - is what the next session in the same
use inherits, and what gets handed back to the pool
afterwards. Nothing repairs it for you: the driver only ever finishes a
connection it cannot vouch for, and it has no way of telling that this
one is in that state. Returning a Left of ConnectionUseError
is how you say so - use finishes the connection when
it sees it.