{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}

-- | Implements pagination in terms of `beam-postgres`.
module Servant.Util.Beam.Postgres.Pagination
    ( paginate_
    ) where

import Universum

import Database.Beam.Query (Q, limit_, offset_)
import Database.Beam.Query.Internal (QNested)

import Servant.Util.Combinators.Pagination
import Servant.Util.Internal.Util

-- | Truncate response according to the given pagination specification.
paginate_
    :: _
    => PaginationSpec
    -> Q select db (QNested (QNested s)) a
    -> Q select db s _
paginate_ :: PaginationSpec
-> Q select db (QNested (QNested s)) a
-> Q select
     db
     s
     (WithRewrittenThread
        (QNested s)
        s
        (WithRewrittenThread (QNested (QNested s)) (QNested s) a))
paginate_ PaginationSpec{Natural
Maybe (Positive Natural)
psOffset :: PaginationSpec -> Natural
psLimit :: PaginationSpec -> Maybe (Positive Natural)
psLimit :: Maybe (Positive Natural)
psOffset :: Natural
..} =
    Integer
-> Q select
     db
     (QNested s)
     (WithRewrittenThread (QNested (QNested s)) (QNested s) a)
-> Q select
     db
     s
     (WithRewrittenThread
        (QNested s)
        s
        (WithRewrittenThread (QNested (QNested s)) (QNested s) a))
forall s a be (db :: (* -> *) -> *).
(Projectible be a, ThreadRewritable (QNested s) a) =>
Integer
-> Q be db (QNested s) a
-> Q be db s (WithRewrittenThread (QNested s) s a)
limit_ (Integer
-> (Positive Natural -> Integer)
-> Maybe (Positive Natural)
-> Integer
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Integer
maxLimit (Natural -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Natural -> Integer)
-> (Positive Natural -> Natural) -> Positive Natural -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Positive Natural -> Natural
forall a. Positive a -> a
unPositive) Maybe (Positive Natural)
psLimit) (Q select
   db
   (QNested s)
   (WithRewrittenThread (QNested (QNested s)) (QNested s) a)
 -> Q select
      db
      s
      (WithRewrittenThread
         (QNested s)
         s
         (WithRewrittenThread (QNested (QNested s)) (QNested s) a)))
-> (Q select db (QNested (QNested s)) a
    -> Q select
         db
         (QNested s)
         (WithRewrittenThread (QNested (QNested s)) (QNested s) a))
-> Q select db (QNested (QNested s)) a
-> Q select
     db
     s
     (WithRewrittenThread
        (QNested s)
        s
        (WithRewrittenThread (QNested (QNested s)) (QNested s) a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Integer
-> Q select db (QNested (QNested s)) a
-> Q select
     db
     (QNested s)
     (WithRewrittenThread (QNested (QNested s)) (QNested s) a)
forall s a be (db :: (* -> *) -> *).
(Projectible be a, ThreadRewritable (QNested s) a) =>
Integer
-> Q be db (QNested s) a
-> Q be db s (WithRewrittenThread (QNested s) s a)
offset_ (Natural -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
psOffset)
  where
    -- We cannot just omit 'limit_' (types won't match),
    -- negative value does not work as well.
    -- So applying max value which can be passed to limit.
    maxLimit :: Integer
maxLimit = Int64 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Bounded Int64 => Int64
forall a. Bounded a => a
maxBound @Int64)