orville-postgresql-1.1.0.0: src/Orville/PostgreSQL/Expr/FetchClause.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
Copyright : Flipstone Technology Partners 2024
License : MIT
Stability : Stable
@since 1.1.0.0
-}
module Orville.PostgreSQL.Expr.FetchClause
( FetchClause
, fetchClauseInt
, FetchClauseModifier
, withTiesFetchClauseModifier
, onlyFetchClauseModifier
)
where
import qualified Orville.PostgreSQL.Raw.RawSql as RawSql
import qualified Orville.PostgreSQL.Raw.SqlValue as SqlValue
{- | Type to represent a SQL FETCH clause. E.G.
> FETCH FIRST 2 ROWS ONLY
'FetchClause' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype FetchClause
= FetchClause RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | Build a SQL FETCH clause for a given number of rows and 'FetchClauseModifier'.
@since 1.1.0.0
-}
fetchClauseInt :: Int -> FetchClauseModifier -> FetchClause
fetchClauseInt fetchNumber =
internal_fetchRaw (RawSql.parameter (SqlValue.fromInt fetchNumber))
-- Internal helper for FETCH. Note this allows illegal expressions to be put together. However many
-- potentially interesting expressions are valid. Such as:
--
-- `VALUES (1, 'o'), (2, 't'), (3, 'th') order by column2 fetch first (select 2) ROW with ties;`
--
-- How to best expose these is not clear at this moment as we do not generally allow any raw sql to
-- be injected, but we do not have a good expression to capture the allowed values here. Finally, it
-- would _appear_ that the same restrictions here would also apply to expressions allowed for
-- LIMIT. Which as of this writing, we do not have a helper for creation.
--
-- Finally note that NEXT and ROW are as PostgreSQL docs call them, noise words, they do not impact
-- the meaning. See https://www.postgresql.org/docs/13/sql-select.html. 'NEXT' and 'ROW' are chosen
-- over 'FIRST' and 'ROWS' respecitvely because they are shorter and thus result in a smaller
-- bytestring being sent over the wire.
internal_fetchRaw :: RawSql.RawSql -> FetchClauseModifier -> FetchClause
internal_fetchRaw countingRawSql modifier =
FetchClause $
RawSql.fromString "FETCH NEXT "
<> RawSql.parenthesized countingRawSql
<> RawSql.fromString " ROW "
<> RawSql.toRawSql modifier
{- | Type to represent the treatment of ties in a SQL FETCH expression. E.G.
> WITH TIES
'FetchClauseModifier' provides a 'RawSql.SqlExpression' instance. See
'RawSql.unsafeSqlExpression' for how to construct a value with your own custom
SQL.
@since 1.1.0.0
-}
newtype FetchClauseModifier
= FetchClauseModifier RawSql.RawSql
deriving
( -- | @since 1.1.0.0
RawSql.SqlExpression
)
{- | Allow a FETCH clause to have ties.
@since 1.1.0.0
-}
withTiesFetchClauseModifier :: FetchClauseModifier
withTiesFetchClauseModifier =
FetchClauseModifier (RawSql.fromString "WITH TIES")
{- | Disallow a FETCH clause to have ties.
@since 1.1.0.0
-}
onlyFetchClauseModifier :: FetchClauseModifier
onlyFetchClauseModifier =
FetchClauseModifier (RawSql.fromString "ONLY")