module Hasql.CursorTransaction.Private.CursorTransaction where import Hasql.CursorTransaction.Private.Prelude import qualified Hasql.Transaction as A import qualified Hasql.Encoders as D import qualified Hasql.Decoders as F import qualified Hasql.CursorTransaction.Private.Transactions as C import qualified Hasql.CursorTransaction.Private.Specs as G import qualified ByteString.TreeBuilder as E -- | -- Context for fetching from multiple cursors in an intertwined fashion. newtype CursorTransaction s result = CursorTransaction (StateT (Int, A.Transaction ()) A.Transaction result) deriving (Functor, Applicative, Monad) -- | -- Cursor reference. newtype Cursor s = Cursor ByteString -- | -- Given a template and encoded params produces a cursor, -- while automating its resource management. declareCursor :: ByteString -> G.EncodedParams -> CursorTransaction s (Cursor s) declareCursor template (G.EncodedParams (Supplied encoder params)) = CursorTransaction $ do name <- state $ do (inc, finaliser) <- id name <- return (incToName inc) newFinaliser <- return (finaliser *> C.closeCursor name) return (name, (succ inc, newFinaliser)) lift (C.declareCursor name template encoder params) return (Cursor name) where incToName inc = E.toByteString $ E.byteString "Hasql_CursorTransaction_" <> E.asciiIntegral inc -- | -- Fetch from a cursor a batch of the given size and decode it using the specified result decoder. fetchBatch :: Cursor s -> G.BatchSize -> F.Result result -> CursorTransaction s result fetchBatch (Cursor name) batchSize decoder = transaction (C.fetchFromCursor name batchSize decoder) -- | -- Lift a standard transaction. -- Note that the transaction must not execute other CursorTransactions. transaction :: A.Transaction result -> CursorTransaction s result transaction = CursorTransaction . lift run :: (forall s. CursorTransaction s result) -> A.Transaction result run (CursorTransaction stack) = do (result, (_, finaliser)) <- runStateT stack (1, pure ()) finaliser return result