module Hasql.Transaction.Queries
where

import Hasql.Transaction.Prelude
import qualified Hasql.Query as HQ
import qualified Hasql.Encoding as HE
import qualified Hasql.Decoding as HD
import qualified ByteString.TreeBuilder as TB


-- * Transactions
-------------------------

data Isolation =
  ReadCommitted |
  RepeatableRead |
  Serializable 

type TransactionMode =
  (Isolation, Bool)

beginTransaction :: TransactionMode -> HQ.Query () ()
beginTransaction (isolation, write) =
  HQ.Query sql HE.unit HD.unit True
  where
    sql =
      TB.toByteString $
      mconcat $
      [
        "BEGIN "
        ,
        case isolation of
          ReadCommitted  -> "ISOLATION LEVEL READ COMMITTED"
          RepeatableRead -> "ISOLATION LEVEL REPEATABLE READ"
          Serializable   -> "ISOLATION LEVEL SERIALIZABLE"
        ,
        " "
        ,
        case write of
          True  -> "READ WRITE"
          False -> "READ ONLY"
      ]

commitTransaction :: HQ.Query () ()
commitTransaction =
  HQ.Query "commit" HE.unit HD.unit True

abortTransaction :: HQ.Query () ()
abortTransaction =
  HQ.Query "abort" HE.unit HD.unit True


-- * Streaming
-------------------------

declareCursor :: ByteString -> ByteString -> HE.Params a -> HQ.Query a ()
declareCursor name sql encoder =
  HQ.Query sql' encoder HD.unit False
  where
    sql' =
      TB.toByteString $
      "DECLARE " <> TB.byteString name <> " NO SCROLL CURSOR FOR " <> TB.byteString sql

closeCursor :: HQ.Query ByteString ()
closeCursor =
  HQ.Query "CLOSE $1" (HE.value HE.bytea) HD.unit True

fetchFromCursor :: (b -> a -> b) -> b -> HD.Row a -> HQ.Query (Int64, ByteString) b
fetchFromCursor step init rowDec =
  HQ.Query sql encoder decoder True
  where
    sql =
      "FETCH FORWARD $1 FROM $2"
    encoder =
      contrazip2
        (HE.value HE.int8)
        (HE.value HE.bytea)
    decoder =
      HD.foldlRows step init rowDec