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 Data.Monoid.Utils
import Database.PostgreSQL.PQTypes.Class
import Database.PostgreSQL.PQTypes.SQL
import Database.PostgreSQL.PQTypes.SQL.Class
import Database.PostgreSQL.PQTypes.Utils
newtype CursorName sql = CursorName { unCursorName :: sql }
deriving (Eq, Ord)
instance IsString sql => IsString (CursorName sql) where
fromString = CursorName . fromString
instance Show sql => Show (CursorName sql) where
showsPrec n (CursorName name) = ("Cursor " ++) . showsPrec n name
data Scroll = Scroll | NoScroll
deriving (Eq, Ord, Show)
data Hold = Hold | NoHold
deriving (Eq, Ord, Show)
data Cursor sql = Cursor !(CursorName sql) !sql
deriving (Eq, Ord, Show)
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 (Eq, Ord, Show)
cursorDirectionToSQL :: (IsString sql, IsSQL sql, Monoid sql) => CursorDirection -> sql
cursorDirectionToSQL = \case
CD_Next -> "NEXT"
CD_Prior -> "PRIOR"
CD_First -> "FIRST"
CD_Last -> "LAST"
CD_Forward_All -> "FORWARD ALL"
CD_Backward_All -> "BACKWARD ALL"
CD_Absolute n -> "ABSOLUTE" <+> unsafeSQL (show n)
CD_Relative n -> "RELATIVE" <+> unsafeSQL (show n)
CD_Forward n -> "FORWARD" <+> unsafeSQL (show n)
CD_Backward n -> "BACKWARD" <+> unsafeSQL (show n)
cursorName :: Cursor sql -> CursorName sql
cursorName (Cursor name _) = name
cursorQuery :: Cursor sql -> sql
cursorQuery (Cursor _ query) = query
withCursor
:: (IsString sql, IsSQL sql, Monoid sql, MonadDB m, MonadMask m)
=> CursorName sql
-> Scroll
-> Hold
-> sql
-> (Cursor sql -> m r)
-> m r
withCursor name scroll hold sql k = bracket_
(runQuery_ declareCursor)
(runQuery_ closeCursor)
(k $ Cursor name sql)
where
declareCursor = smconcat
[ "DECLARE"
, unCursorName name
, case scroll of
Scroll -> "SCROLL"
NoScroll -> "NO SCROLL"
, "CURSOR"
, case hold of
Hold -> "WITH HOLD"
NoHold -> "WITHOUT HOLD"
, "FOR"
, sql
]
closeCursor = smconcat
[ "DO $$"
, "BEGIN"
, " EXECUTE 'CLOSE" <+> unCursorName name <+> "';"
, "EXCEPTION WHEN invalid_cursor_name THEN"
, "END $$"
]
withCursorSQL
:: (MonadDB m, MonadMask m)
=> CursorName SQL
-> Scroll
-> Hold
-> SQL
-> (Cursor SQL -> m r)
-> m r
withCursorSQL = withCursor
cursorFetch
:: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
=> Cursor sql
-> CursorDirection
-> m Int
cursorFetch cursor direction = runQuery $ smconcat
[ "FETCH"
, cursorDirectionToSQL direction
, "FROM"
, unCursorName $ cursorName cursor
]
cursorFetch_ :: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
=> Cursor sql
-> CursorDirection
-> m ()
cursorFetch_ cursor = void . cursorFetch cursor
cursorMove
:: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
=> Cursor sql
-> CursorDirection
-> m Int
cursorMove cursor direction = runQuery $ smconcat
[ "MOVE"
, cursorDirectionToSQL direction
, "FROM"
, unCursorName $ cursorName cursor
]
cursorMove_
:: (IsSQL sql, IsString sql, Monoid sql, MonadDB m)
=> Cursor sql
-> CursorDirection
-> m ()
cursorMove_ cursor = void . cursorMove cursor