module Database.PostgreSQL.PQTypes.Cursor
  ( CursorName (..)
  , Scroll (..)
  , Hold (..)
  , Cursor
  , CursorDirection (..)
  , cursorName
  , cursorQuery
  , withCursor
  , withCursorSQL
  , cursorFetch
  , cursorFetch_
  , cursorMove
  , cursorMove_
  ) where

import Control.Monad
import Control.Monad.Catch
import Data.String
import GHC.Stack

import Data.Monoid.Utils
import Database.PostgreSQL.PQTypes.Class
import Database.PostgreSQL.PQTypes.SQL
import Database.PostgreSQL.PQTypes.SQL.Class
import Database.PostgreSQL.PQTypes.Utils

-- | Name of a cursor.
newtype CursorName sql = CursorName {forall sql. CursorName sql -> sql
unCursorName :: sql}
  deriving (CursorName sql -> CursorName sql -> Bool
(CursorName sql -> CursorName sql -> Bool)
-> (CursorName sql -> CursorName sql -> Bool)
-> Eq (CursorName sql)
forall sql. Eq sql => CursorName sql -> CursorName sql -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall sql. Eq sql => CursorName sql -> CursorName sql -> Bool
== :: CursorName sql -> CursorName sql -> Bool
$c/= :: forall sql. Eq sql => CursorName sql -> CursorName sql -> Bool
/= :: CursorName sql -> CursorName sql -> Bool
Eq, Eq (CursorName sql)
Eq (CursorName sql) =>
(CursorName sql -> CursorName sql -> Ordering)
-> (CursorName sql -> CursorName sql -> Bool)
-> (CursorName sql -> CursorName sql -> Bool)
-> (CursorName sql -> CursorName sql -> Bool)
-> (CursorName sql -> CursorName sql -> Bool)
-> (CursorName sql -> CursorName sql -> CursorName sql)
-> (CursorName sql -> CursorName sql -> CursorName sql)
-> Ord (CursorName sql)
CursorName sql -> CursorName sql -> Bool
CursorName sql -> CursorName sql -> Ordering
CursorName sql -> CursorName sql -> CursorName sql
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall sql. Ord sql => Eq (CursorName sql)
forall sql. Ord sql => CursorName sql -> CursorName sql -> Bool
forall sql. Ord sql => CursorName sql -> CursorName sql -> Ordering
forall sql.
Ord sql =>
CursorName sql -> CursorName sql -> CursorName sql
$ccompare :: forall sql. Ord sql => CursorName sql -> CursorName sql -> Ordering
compare :: CursorName sql -> CursorName sql -> Ordering
$c< :: forall sql. Ord sql => CursorName sql -> CursorName sql -> Bool
< :: CursorName sql -> CursorName sql -> Bool
$c<= :: forall sql. Ord sql => CursorName sql -> CursorName sql -> Bool
<= :: CursorName sql -> CursorName sql -> Bool
$c> :: forall sql. Ord sql => CursorName sql -> CursorName sql -> Bool
> :: CursorName sql -> CursorName sql -> Bool
$c>= :: forall sql. Ord sql => CursorName sql -> CursorName sql -> Bool
>= :: CursorName sql -> CursorName sql -> Bool
$cmax :: forall sql.
Ord sql =>
CursorName sql -> CursorName sql -> CursorName sql
max :: CursorName sql -> CursorName sql -> CursorName sql
$cmin :: forall sql.
Ord sql =>
CursorName sql -> CursorName sql -> CursorName sql
min :: CursorName sql -> CursorName sql -> CursorName sql
Ord)

instance IsString sql => IsString (CursorName sql) where
  fromString :: String -> CursorName sql
fromString = sql -> CursorName sql
forall sql. sql -> CursorName sql
CursorName (sql -> CursorName sql)
-> (String -> sql) -> String -> CursorName sql
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> sql
forall a. IsString a => String -> a
fromString

instance Show sql => Show (CursorName sql) where
  showsPrec :: Int -> CursorName sql -> ShowS
showsPrec Int
n (CursorName sql
name) = (String
"Cursor " String -> ShowS
forall a. [a] -> [a] -> [a]
++) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> sql -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
n sql
name

----------------------------------------

-- | Defines whether a cursor will be declared as @SCROLL@ or @NO
-- SCROLL@. Scrollable cursors can be scrolled in all directions, otherwise only
-- forward.
data Scroll = Scroll | NoScroll
  deriving (Scroll -> Scroll -> Bool
(Scroll -> Scroll -> Bool)
-> (Scroll -> Scroll -> Bool) -> Eq Scroll
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Scroll -> Scroll -> Bool
== :: Scroll -> Scroll -> Bool
$c/= :: Scroll -> Scroll -> Bool
/= :: Scroll -> Scroll -> Bool
Eq, Eq Scroll
Eq Scroll =>
(Scroll -> Scroll -> Ordering)
-> (Scroll -> Scroll -> Bool)
-> (Scroll -> Scroll -> Bool)
-> (Scroll -> Scroll -> Bool)
-> (Scroll -> Scroll -> Bool)
-> (Scroll -> Scroll -> Scroll)
-> (Scroll -> Scroll -> Scroll)
-> Ord Scroll
Scroll -> Scroll -> Bool
Scroll -> Scroll -> Ordering
Scroll -> Scroll -> Scroll
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Scroll -> Scroll -> Ordering
compare :: Scroll -> Scroll -> Ordering
$c< :: Scroll -> Scroll -> Bool
< :: Scroll -> Scroll -> Bool
$c<= :: Scroll -> Scroll -> Bool
<= :: Scroll -> Scroll -> Bool
$c> :: Scroll -> Scroll -> Bool
> :: Scroll -> Scroll -> Bool
$c>= :: Scroll -> Scroll -> Bool
>= :: Scroll -> Scroll -> Bool
$cmax :: Scroll -> Scroll -> Scroll
max :: Scroll -> Scroll -> Scroll
$cmin :: Scroll -> Scroll -> Scroll
min :: Scroll -> Scroll -> Scroll
Ord, Int -> Scroll -> ShowS
[Scroll] -> ShowS
Scroll -> String
(Int -> Scroll -> ShowS)
-> (Scroll -> String) -> ([Scroll] -> ShowS) -> Show Scroll
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Scroll -> ShowS
showsPrec :: Int -> Scroll -> ShowS
$cshow :: Scroll -> String
show :: Scroll -> String
$cshowList :: [Scroll] -> ShowS
showList :: [Scroll] -> ShowS
Show)

-- | Defines whether a cursor will be declared as @WITH HOLD@ or @WITHOUT HOLD@.
--
-- From the PostgreSQL manual: WITH HOLD specifies that the cursor can continue
-- to be used after the transaction that created it successfully commits.
-- WITHOUT HOLD specifies that the cursor cannot be used outside of the
-- transaction that created it.
data Hold = Hold | NoHold
  deriving (Hold -> Hold -> Bool
(Hold -> Hold -> Bool) -> (Hold -> Hold -> Bool) -> Eq Hold
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Hold -> Hold -> Bool
== :: Hold -> Hold -> Bool
$c/= :: Hold -> Hold -> Bool
/= :: Hold -> Hold -> Bool
Eq, Eq Hold
Eq Hold =>
(Hold -> Hold -> Ordering)
-> (Hold -> Hold -> Bool)
-> (Hold -> Hold -> Bool)
-> (Hold -> Hold -> Bool)
-> (Hold -> Hold -> Bool)
-> (Hold -> Hold -> Hold)
-> (Hold -> Hold -> Hold)
-> Ord Hold
Hold -> Hold -> Bool
Hold -> Hold -> Ordering
Hold -> Hold -> Hold
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Hold -> Hold -> Ordering
compare :: Hold -> Hold -> Ordering
$c< :: Hold -> Hold -> Bool
< :: Hold -> Hold -> Bool
$c<= :: Hold -> Hold -> Bool
<= :: Hold -> Hold -> Bool
$c> :: Hold -> Hold -> Bool
> :: Hold -> Hold -> Bool
$c>= :: Hold -> Hold -> Bool
>= :: Hold -> Hold -> Bool
$cmax :: Hold -> Hold -> Hold
max :: Hold -> Hold -> Hold
$cmin :: Hold -> Hold -> Hold
min :: Hold -> Hold -> Hold
Ord, Int -> Hold -> ShowS
[Hold] -> ShowS
Hold -> String
(Int -> Hold -> ShowS)
-> (Hold -> String) -> ([Hold] -> ShowS) -> Show Hold
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Hold -> ShowS
showsPrec :: Int -> Hold -> ShowS
$cshow :: Hold -> String
show :: Hold -> String
$cshowList :: [Hold] -> ShowS
showList :: [Hold] -> ShowS
Show)

-- | Data representing a created cursor.
data Cursor sql = Cursor !(CursorName sql) !sql
  deriving (Cursor sql -> Cursor sql -> Bool
(Cursor sql -> Cursor sql -> Bool)
-> (Cursor sql -> Cursor sql -> Bool) -> Eq (Cursor sql)
forall sql. Eq sql => Cursor sql -> Cursor sql -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall sql. Eq sql => Cursor sql -> Cursor sql -> Bool
== :: Cursor sql -> Cursor sql -> Bool
$c/= :: forall sql. Eq sql => Cursor sql -> Cursor sql -> Bool
/= :: Cursor sql -> Cursor sql -> Bool
Eq, Eq (Cursor sql)
Eq (Cursor sql) =>
(Cursor sql -> Cursor sql -> Ordering)
-> (Cursor sql -> Cursor sql -> Bool)
-> (Cursor sql -> Cursor sql -> Bool)
-> (Cursor sql -> Cursor sql -> Bool)
-> (Cursor sql -> Cursor sql -> Bool)
-> (Cursor sql -> Cursor sql -> Cursor sql)
-> (Cursor sql -> Cursor sql -> Cursor sql)
-> Ord (Cursor sql)
Cursor sql -> Cursor sql -> Bool
Cursor sql -> Cursor sql -> Ordering
Cursor sql -> Cursor sql -> Cursor sql
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall sql. Ord sql => Eq (Cursor sql)
forall sql. Ord sql => Cursor sql -> Cursor sql -> Bool
forall sql. Ord sql => Cursor sql -> Cursor sql -> Ordering
forall sql. Ord sql => Cursor sql -> Cursor sql -> Cursor sql
$ccompare :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Ordering
compare :: Cursor sql -> Cursor sql -> Ordering
$c< :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Bool
< :: Cursor sql -> Cursor sql -> Bool
$c<= :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Bool
<= :: Cursor sql -> Cursor sql -> Bool
$c> :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Bool
> :: Cursor sql -> Cursor sql -> Bool
$c>= :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Bool
>= :: Cursor sql -> Cursor sql -> Bool
$cmax :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Cursor sql
max :: Cursor sql -> Cursor sql -> Cursor sql
$cmin :: forall sql. Ord sql => Cursor sql -> Cursor sql -> Cursor sql
min :: Cursor sql -> Cursor sql -> Cursor sql
Ord, Int -> Cursor sql -> ShowS
[Cursor sql] -> ShowS
Cursor sql -> String
(Int -> Cursor sql -> ShowS)
-> (Cursor sql -> String)
-> ([Cursor sql] -> ShowS)
-> Show (Cursor sql)
forall sql. Show sql => Int -> Cursor sql -> ShowS
forall sql. Show sql => [Cursor sql] -> ShowS
forall sql. Show sql => Cursor sql -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall sql. Show sql => Int -> Cursor sql -> ShowS
showsPrec :: Int -> Cursor sql -> ShowS
$cshow :: forall sql. Show sql => Cursor sql -> String
show :: Cursor sql -> String
$cshowList :: forall sql. Show sql => [Cursor sql] -> ShowS
showList :: [Cursor sql] -> ShowS
Show)

----------------------------------------

-- | Direction in which to move the cursor. Note that cursors declared as @NO
-- SCROLL@ can only move forward (i.e. only 'CD_Next', 'CD_Forward_All' and
-- 'CD_Forward' is allowed).
data CursorDirection
  = CD_Next
  | CD_Prior
  | CD_First
  | CD_Last
  | CD_Forward_All
  | CD_Backward_All
  | CD_Absolute Int
  | CD_Relative Int
  | CD_Forward Int
  | CD_Backward Int
  deriving (CursorDirection -> CursorDirection -> Bool
(CursorDirection -> CursorDirection -> Bool)
-> (CursorDirection -> CursorDirection -> Bool)
-> Eq CursorDirection
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CursorDirection -> CursorDirection -> Bool
== :: CursorDirection -> CursorDirection -> Bool
$c/= :: CursorDirection -> CursorDirection -> Bool
/= :: CursorDirection -> CursorDirection -> Bool
Eq, Eq CursorDirection
Eq CursorDirection =>
(CursorDirection -> CursorDirection -> Ordering)
-> (CursorDirection -> CursorDirection -> Bool)
-> (CursorDirection -> CursorDirection -> Bool)
-> (CursorDirection -> CursorDirection -> Bool)
-> (CursorDirection -> CursorDirection -> Bool)
-> (CursorDirection -> CursorDirection -> CursorDirection)
-> (CursorDirection -> CursorDirection -> CursorDirection)
-> Ord CursorDirection
CursorDirection -> CursorDirection -> Bool
CursorDirection -> CursorDirection -> Ordering
CursorDirection -> CursorDirection -> CursorDirection
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: CursorDirection -> CursorDirection -> Ordering
compare :: CursorDirection -> CursorDirection -> Ordering
$c< :: CursorDirection -> CursorDirection -> Bool
< :: CursorDirection -> CursorDirection -> Bool
$c<= :: CursorDirection -> CursorDirection -> Bool
<= :: CursorDirection -> CursorDirection -> Bool
$c> :: CursorDirection -> CursorDirection -> Bool
> :: CursorDirection -> CursorDirection -> Bool
$c>= :: CursorDirection -> CursorDirection -> Bool
>= :: CursorDirection -> CursorDirection -> Bool
$cmax :: CursorDirection -> CursorDirection -> CursorDirection
max :: CursorDirection -> CursorDirection -> CursorDirection
$cmin :: CursorDirection -> CursorDirection -> CursorDirection
min :: CursorDirection -> CursorDirection -> CursorDirection
Ord, Int -> CursorDirection -> ShowS
[CursorDirection] -> ShowS
CursorDirection -> String
(Int -> CursorDirection -> ShowS)
-> (CursorDirection -> String)
-> ([CursorDirection] -> ShowS)
-> Show CursorDirection
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CursorDirection -> ShowS
showsPrec :: Int -> CursorDirection -> ShowS
$cshow :: CursorDirection -> String
show :: CursorDirection -> String
$cshowList :: [CursorDirection] -> ShowS
showList :: [CursorDirection] -> ShowS
Show)

cursorDirectionToSQL :: (IsString sql, IsSQL sql, Monoid sql) => CursorDirection -> sql
cursorDirectionToSQL :: forall sql.
(IsString sql, IsSQL sql, Monoid sql) =>
CursorDirection -> sql
cursorDirectionToSQL = \case
  CursorDirection
CD_Next -> sql
"NEXT"
  CursorDirection
CD_Prior -> sql
"PRIOR"
  CursorDirection
CD_First -> sql
"FIRST"
  CursorDirection
CD_Last -> sql
"LAST"
  CursorDirection
CD_Forward_All -> sql
"FORWARD ALL"
  CursorDirection
CD_Backward_All -> sql
"BACKWARD ALL"
  CD_Absolute Int
n -> sql
"ABSOLUTE" sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> String -> sql
forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL (Int -> String
forall a. Show a => a -> String
show Int
n)
  CD_Relative Int
n -> sql
"RELATIVE" sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> String -> sql
forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL (Int -> String
forall a. Show a => a -> String
show Int
n)
  CD_Forward Int
n -> sql
"FORWARD" sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> String -> sql
forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL (Int -> String
forall a. Show a => a -> String
show Int
n)
  CD_Backward Int
n -> sql
"BACKWARD" sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> String -> sql
forall sql. (IsSQL sql, IsString sql) => String -> sql
unsafeSQL (Int -> String
forall a. Show a => a -> String
show Int
n)

----------------------------------------

-- | Retrieve the name of a cursor.
cursorName :: Cursor sql -> CursorName sql
cursorName :: forall sql. Cursor sql -> CursorName sql
cursorName (Cursor CursorName sql
name sql
_) = CursorName sql
name

-- | Retrieve SQL query used to create a cursor.
cursorQuery :: Cursor sql -> sql
cursorQuery :: forall sql. Cursor sql -> sql
cursorQuery (Cursor CursorName sql
_ sql
query) = sql
query

-- | Create a cursor from the SQL query and use it within the given context.
withCursor
  :: (HasCallStack, IsString sql, IsSQL sql, Monoid sql, MonadDB m, MonadMask m)
  => CursorName sql
  -> Scroll
  -> Hold
  -> sql
  -> (Cursor sql -> m r)
  -> m r
withCursor :: forall sql (m :: * -> *) r.
(HasCallStack, IsString sql, IsSQL sql, Monoid sql, MonadDB m,
 MonadMask m) =>
CursorName sql
-> Scroll -> Hold -> sql -> (Cursor sql -> m r) -> m r
withCursor CursorName sql
name Scroll
scroll Hold
hold sql
sql Cursor sql -> m r
k =
  m () -> m () -> m r -> m r
forall (m :: * -> *) a c b.
(HasCallStack, MonadMask m) =>
m a -> m c -> m b -> m b
bracket_
    (sql -> m ()
forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, MonadDB m) =>
sql -> m ()
runQuery_ sql
declareCursor)
    (sql -> m ()
forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, MonadDB m) =>
sql -> m ()
runQuery_ sql
closeCursor)
    (Cursor sql -> m r
k (Cursor sql -> m r) -> Cursor sql -> m r
forall a b. (a -> b) -> a -> b
$ CursorName sql -> sql -> Cursor sql
forall sql. CursorName sql -> sql -> Cursor sql
Cursor CursorName sql
name sql
sql)
  where
    declareCursor :: sql
declareCursor =
      [sql] -> sql
forall m. (IsString m, Monoid m) => [m] -> m
smconcat
        [ sql
"DECLARE"
        , CursorName sql -> sql
forall sql. CursorName sql -> sql
unCursorName CursorName sql
name
        , case Scroll
scroll of
            Scroll
Scroll -> sql
"SCROLL"
            Scroll
NoScroll -> sql
"NO SCROLL"
        , sql
"CURSOR"
        , case Hold
hold of
            Hold
Hold -> sql
"WITH HOLD"
            Hold
NoHold -> sql
"WITHOUT HOLD"
        , sql
"FOR"
        , sql
sql
        ]

    -- Because the cursor might potentially be closed within the continuation
    -- (either by an explicit CLOSE or finishing the current transaction), we
    -- need to supress a potential 'InvalidCursorName' exception.
    closeCursor :: sql
closeCursor =
      [sql] -> sql
forall m. (IsString m, Monoid m) => [m] -> m
smconcat
        [ sql
"DO $$"
        , sql
"BEGIN"
        , sql
"  EXECUTE 'CLOSE" sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> CursorName sql -> sql
forall sql. CursorName sql -> sql
unCursorName CursorName sql
name sql -> sql -> sql
forall m. (IsString m, Monoid m) => m -> m -> m
<+> sql
"';"
        , sql
"EXCEPTION WHEN invalid_cursor_name THEN"
        , sql
"END $$"
        ]

-- | Version of 'withCursor' without the @sql@ type parameter for convenience.
withCursorSQL
  :: (MonadDB m, MonadMask m)
  => CursorName SQL
  -> Scroll
  -> Hold
  -> SQL
  -> (Cursor SQL -> m r)
  -> m r
withCursorSQL :: forall (m :: * -> *) r.
(MonadDB m, MonadMask m) =>
CursorName SQL
-> Scroll -> Hold -> SQL -> (Cursor SQL -> m r) -> m r
withCursorSQL = CursorName SQL
-> Scroll -> Hold -> SQL -> (Cursor SQL -> m r) -> m r
forall sql (m :: * -> *) r.
(HasCallStack, IsString sql, IsSQL sql, Monoid sql, MonadDB m,
 MonadMask m) =>
CursorName sql
-> Scroll -> Hold -> sql -> (Cursor sql -> m r) -> m r
withCursor

-- | Retrieve rows from a query using a cursor. See
-- https://www.postgresql.org/docs/current/sql-fetch.html for more information.
cursorFetch
  :: (HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m)
  => Cursor sql
  -> CursorDirection
  -> m Int
cursorFetch :: forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m Int
cursorFetch Cursor sql
cursor CursorDirection
direction =
  sql -> m Int
forall sql. (HasCallStack, IsSQL sql) => sql -> m Int
forall (m :: * -> *) sql.
(MonadDB m, HasCallStack, IsSQL sql) =>
sql -> m Int
runQuery (sql -> m Int) -> sql -> m Int
forall a b. (a -> b) -> a -> b
$
    [sql] -> sql
forall m. (IsString m, Monoid m) => [m] -> m
smconcat
      [ sql
"FETCH"
      , CursorDirection -> sql
forall sql.
(IsString sql, IsSQL sql, Monoid sql) =>
CursorDirection -> sql
cursorDirectionToSQL CursorDirection
direction
      , sql
"FROM"
      , CursorName sql -> sql
forall sql. CursorName sql -> sql
unCursorName (CursorName sql -> sql) -> CursorName sql -> sql
forall a b. (a -> b) -> a -> b
$ Cursor sql -> CursorName sql
forall sql. Cursor sql -> CursorName sql
cursorName Cursor sql
cursor
      ]

-- | Same as 'cursorFetch', except the result (i.e. the number of fetched rows)
-- is ignored.
cursorFetch_
  :: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
  => Cursor sql
  -> CursorDirection
  -> m ()
cursorFetch_ :: forall sql (m :: * -> *).
(IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m ()
cursorFetch_ Cursor sql
cursor = m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Int -> m ())
-> (CursorDirection -> m Int) -> CursorDirection -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor sql -> CursorDirection -> m Int
forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m Int
cursorFetch Cursor sql
cursor

-- | Move a cursor to a specific position. It works exactly like 'cursorFetch',
-- except it only positions the cursor and does not return rows. See
-- https://www.postgresql.org/docs/current/sql-move.html for more information.
cursorMove
  :: (HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m)
  => Cursor sql
  -> CursorDirection
  -> m Int
cursorMove :: forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m Int
cursorMove Cursor sql
cursor CursorDirection
direction =
  sql -> m Int
forall sql. (HasCallStack, IsSQL sql) => sql -> m Int
forall (m :: * -> *) sql.
(MonadDB m, HasCallStack, IsSQL sql) =>
sql -> m Int
runQuery (sql -> m Int) -> sql -> m Int
forall a b. (a -> b) -> a -> b
$
    [sql] -> sql
forall m. (IsString m, Monoid m) => [m] -> m
smconcat
      [ sql
"MOVE"
      , CursorDirection -> sql
forall sql.
(IsString sql, IsSQL sql, Monoid sql) =>
CursorDirection -> sql
cursorDirectionToSQL CursorDirection
direction
      , sql
"FROM"
      , CursorName sql -> sql
forall sql. CursorName sql -> sql
unCursorName (CursorName sql -> sql) -> CursorName sql -> sql
forall a b. (a -> b) -> a -> b
$ Cursor sql -> CursorName sql
forall sql. Cursor sql -> CursorName sql
cursorName Cursor sql
cursor
      ]

-- | Same as 'cursorMove', except the result (i.e. the number of rows that would
-- be fetched) is ignored.
cursorMove_
  :: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
  => Cursor sql
  -> CursorDirection
  -> m ()
cursorMove_ :: forall sql (m :: * -> *).
(IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m ()
cursorMove_ Cursor sql
cursor = m Int -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Int -> m ())
-> (CursorDirection -> m Int) -> CursorDirection -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cursor sql -> CursorDirection -> m Int
forall sql (m :: * -> *).
(HasCallStack, IsSQL sql, IsString sql, Monoid sql, MonadDB m) =>
Cursor sql -> CursorDirection -> m Int
cursorMove Cursor sql
cursor