{-# LANGUAGE DeriveAnyClass        #-}
{-# LANGUAGE DerivingStrategies    #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE NamedFieldPuns        #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE UndecidableInstances  #-}
{-

Pagination allows to return a subset of results through pages. Once the first
page was requested, we can request the next ones until we get empty results.

There are multiple strategies for implementation pagination, such as Offset
Pagination and Seek Pagination. Offset Pagination is the easiest to implement
and use. However, it is not performant for large offset values and it is not
consistent if new items are inserted in the database while we are querying.
For these reasons, we decided to use Seek Pagination which doesn't suffer from
those drawbacks. Seek Pagination works as follows. For a given page request, we
need to provide the number of items per page and last element we queried (can
be Nothing). We suppose the elements are ordered in ascending order.

Here's a simple illustrative example:

* Suppose we have the following items in the database [1..100].
* We first request the 50 first items.
* We obtain the first page containing [1..50].
* To request the next page, we request 50 items after the last item of the
  previous page (which is 50).
* We obtain the second page containing [51..100].
* Since we don't know this was the last page, we would request the next 50
  items after the last item (which is 100).
* We obtain a page with no elements, thus we don't need to query for more pages.
-}
module Control.Monad.Freer.Extras.Pagination
    ( PageQuery(..)
    , Page(..)
    , PageSize(..)
    , pageOf
    ) where

import Control.Monad (guard)
import Data.Aeson (FromJSON, ToJSON)
import Data.Default (Default (..))
import Data.List.NonEmpty qualified as L
import Data.Maybe (isJust, listToMaybe)
import Data.Set (Set)
import Data.Set qualified as Set
import GHC.Generics (Generic)
import Numeric.Natural (Natural)

-- | Query parameters for pagination.
data PageQuery a = PageQuery
    { PageQuery a -> PageSize
pageQuerySize     :: PageSize -- ^ Number of items per page.
    , PageQuery a -> Maybe a
pageQueryLastItem :: Maybe a -- ^ Last item of the queried page.
    }
    deriving stock (PageQuery a -> PageQuery a -> Bool
(PageQuery a -> PageQuery a -> Bool)
-> (PageQuery a -> PageQuery a -> Bool) -> Eq (PageQuery a)
forall a. Eq a => PageQuery a -> PageQuery a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PageQuery a -> PageQuery a -> Bool
$c/= :: forall a. Eq a => PageQuery a -> PageQuery a -> Bool
== :: PageQuery a -> PageQuery a -> Bool
$c== :: forall a. Eq a => PageQuery a -> PageQuery a -> Bool
Eq, Eq (PageQuery a)
Eq (PageQuery a)
-> (PageQuery a -> PageQuery a -> Ordering)
-> (PageQuery a -> PageQuery a -> Bool)
-> (PageQuery a -> PageQuery a -> Bool)
-> (PageQuery a -> PageQuery a -> Bool)
-> (PageQuery a -> PageQuery a -> Bool)
-> (PageQuery a -> PageQuery a -> PageQuery a)
-> (PageQuery a -> PageQuery a -> PageQuery a)
-> Ord (PageQuery a)
PageQuery a -> PageQuery a -> Bool
PageQuery a -> PageQuery a -> Ordering
PageQuery a -> PageQuery a -> PageQuery a
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 a. Ord a => Eq (PageQuery a)
forall a. Ord a => PageQuery a -> PageQuery a -> Bool
forall a. Ord a => PageQuery a -> PageQuery a -> Ordering
forall a. Ord a => PageQuery a -> PageQuery a -> PageQuery a
min :: PageQuery a -> PageQuery a -> PageQuery a
$cmin :: forall a. Ord a => PageQuery a -> PageQuery a -> PageQuery a
max :: PageQuery a -> PageQuery a -> PageQuery a
$cmax :: forall a. Ord a => PageQuery a -> PageQuery a -> PageQuery a
>= :: PageQuery a -> PageQuery a -> Bool
$c>= :: forall a. Ord a => PageQuery a -> PageQuery a -> Bool
> :: PageQuery a -> PageQuery a -> Bool
$c> :: forall a. Ord a => PageQuery a -> PageQuery a -> Bool
<= :: PageQuery a -> PageQuery a -> Bool
$c<= :: forall a. Ord a => PageQuery a -> PageQuery a -> Bool
< :: PageQuery a -> PageQuery a -> Bool
$c< :: forall a. Ord a => PageQuery a -> PageQuery a -> Bool
compare :: PageQuery a -> PageQuery a -> Ordering
$ccompare :: forall a. Ord a => PageQuery a -> PageQuery a -> Ordering
$cp1Ord :: forall a. Ord a => Eq (PageQuery a)
Ord, Int -> PageQuery a -> ShowS
[PageQuery a] -> ShowS
PageQuery a -> String
(Int -> PageQuery a -> ShowS)
-> (PageQuery a -> String)
-> ([PageQuery a] -> ShowS)
-> Show (PageQuery a)
forall a. Show a => Int -> PageQuery a -> ShowS
forall a. Show a => [PageQuery a] -> ShowS
forall a. Show a => PageQuery a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PageQuery a] -> ShowS
$cshowList :: forall a. Show a => [PageQuery a] -> ShowS
show :: PageQuery a -> String
$cshow :: forall a. Show a => PageQuery a -> String
showsPrec :: Int -> PageQuery a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> PageQuery a -> ShowS
Show, (forall x. PageQuery a -> Rep (PageQuery a) x)
-> (forall x. Rep (PageQuery a) x -> PageQuery a)
-> Generic (PageQuery a)
forall x. Rep (PageQuery a) x -> PageQuery a
forall x. PageQuery a -> Rep (PageQuery a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (PageQuery a) x -> PageQuery a
forall a x. PageQuery a -> Rep (PageQuery a) x
$cto :: forall a x. Rep (PageQuery a) x -> PageQuery a
$cfrom :: forall a x. PageQuery a -> Rep (PageQuery a) x
Generic, a -> PageQuery b -> PageQuery a
(a -> b) -> PageQuery a -> PageQuery b
(forall a b. (a -> b) -> PageQuery a -> PageQuery b)
-> (forall a b. a -> PageQuery b -> PageQuery a)
-> Functor PageQuery
forall a b. a -> PageQuery b -> PageQuery a
forall a b. (a -> b) -> PageQuery a -> PageQuery b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> PageQuery b -> PageQuery a
$c<$ :: forall a b. a -> PageQuery b -> PageQuery a
fmap :: (a -> b) -> PageQuery a -> PageQuery b
$cfmap :: forall a b. (a -> b) -> PageQuery a -> PageQuery b
Functor)
    deriving anyclass ([PageQuery a] -> Value
[PageQuery a] -> Encoding
PageQuery a -> Value
PageQuery a -> Encoding
(PageQuery a -> Value)
-> (PageQuery a -> Encoding)
-> ([PageQuery a] -> Value)
-> ([PageQuery a] -> Encoding)
-> ToJSON (PageQuery a)
forall a. ToJSON a => [PageQuery a] -> Value
forall a. ToJSON a => [PageQuery a] -> Encoding
forall a. ToJSON a => PageQuery a -> Value
forall a. ToJSON a => PageQuery a -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [PageQuery a] -> Encoding
$ctoEncodingList :: forall a. ToJSON a => [PageQuery a] -> Encoding
toJSONList :: [PageQuery a] -> Value
$ctoJSONList :: forall a. ToJSON a => [PageQuery a] -> Value
toEncoding :: PageQuery a -> Encoding
$ctoEncoding :: forall a. ToJSON a => PageQuery a -> Encoding
toJSON :: PageQuery a -> Value
$ctoJSON :: forall a. ToJSON a => PageQuery a -> Value
ToJSON, Value -> Parser [PageQuery a]
Value -> Parser (PageQuery a)
(Value -> Parser (PageQuery a))
-> (Value -> Parser [PageQuery a]) -> FromJSON (PageQuery a)
forall a. FromJSON a => Value -> Parser [PageQuery a]
forall a. FromJSON a => Value -> Parser (PageQuery a)
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [PageQuery a]
$cparseJSONList :: forall a. FromJSON a => Value -> Parser [PageQuery a]
parseJSON :: Value -> Parser (PageQuery a)
$cparseJSON :: forall a. FromJSON a => Value -> Parser (PageQuery a)
FromJSON)

instance Default (PageQuery a) where
  def :: PageQuery a
def = PageSize -> Maybe a -> PageQuery a
forall a. PageSize -> Maybe a -> PageQuery a
PageQuery PageSize
forall a. Default a => a
def Maybe a
forall a. Maybe a
Nothing

newtype PageSize = PageSize { PageSize -> Natural
getPageSize :: Natural }
    deriving stock (PageSize -> PageSize -> Bool
(PageSize -> PageSize -> Bool)
-> (PageSize -> PageSize -> Bool) -> Eq PageSize
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PageSize -> PageSize -> Bool
$c/= :: PageSize -> PageSize -> Bool
== :: PageSize -> PageSize -> Bool
$c== :: PageSize -> PageSize -> Bool
Eq, Eq PageSize
Eq PageSize
-> (PageSize -> PageSize -> Ordering)
-> (PageSize -> PageSize -> Bool)
-> (PageSize -> PageSize -> Bool)
-> (PageSize -> PageSize -> Bool)
-> (PageSize -> PageSize -> Bool)
-> (PageSize -> PageSize -> PageSize)
-> (PageSize -> PageSize -> PageSize)
-> Ord PageSize
PageSize -> PageSize -> Bool
PageSize -> PageSize -> Ordering
PageSize -> PageSize -> PageSize
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
min :: PageSize -> PageSize -> PageSize
$cmin :: PageSize -> PageSize -> PageSize
max :: PageSize -> PageSize -> PageSize
$cmax :: PageSize -> PageSize -> PageSize
>= :: PageSize -> PageSize -> Bool
$c>= :: PageSize -> PageSize -> Bool
> :: PageSize -> PageSize -> Bool
$c> :: PageSize -> PageSize -> Bool
<= :: PageSize -> PageSize -> Bool
$c<= :: PageSize -> PageSize -> Bool
< :: PageSize -> PageSize -> Bool
$c< :: PageSize -> PageSize -> Bool
compare :: PageSize -> PageSize -> Ordering
$ccompare :: PageSize -> PageSize -> Ordering
$cp1Ord :: Eq PageSize
Ord, Int -> PageSize -> ShowS
[PageSize] -> ShowS
PageSize -> String
(Int -> PageSize -> ShowS)
-> (PageSize -> String) -> ([PageSize] -> ShowS) -> Show PageSize
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PageSize] -> ShowS
$cshowList :: [PageSize] -> ShowS
show :: PageSize -> String
$cshow :: PageSize -> String
showsPrec :: Int -> PageSize -> ShowS
$cshowsPrec :: Int -> PageSize -> ShowS
Show, (forall x. PageSize -> Rep PageSize x)
-> (forall x. Rep PageSize x -> PageSize) -> Generic PageSize
forall x. Rep PageSize x -> PageSize
forall x. PageSize -> Rep PageSize x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PageSize x -> PageSize
$cfrom :: forall x. PageSize -> Rep PageSize x
Generic)
    deriving anyclass ([PageSize] -> Value
[PageSize] -> Encoding
PageSize -> Value
PageSize -> Encoding
(PageSize -> Value)
-> (PageSize -> Encoding)
-> ([PageSize] -> Value)
-> ([PageSize] -> Encoding)
-> ToJSON PageSize
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [PageSize] -> Encoding
$ctoEncodingList :: [PageSize] -> Encoding
toJSONList :: [PageSize] -> Value
$ctoJSONList :: [PageSize] -> Value
toEncoding :: PageSize -> Encoding
$ctoEncoding :: PageSize -> Encoding
toJSON :: PageSize -> Value
$ctoJSON :: PageSize -> Value
ToJSON, Value -> Parser [PageSize]
Value -> Parser PageSize
(Value -> Parser PageSize)
-> (Value -> Parser [PageSize]) -> FromJSON PageSize
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [PageSize]
$cparseJSONList :: Value -> Parser [PageSize]
parseJSON :: Value -> Parser PageSize
$cparseJSON :: Value -> Parser PageSize
FromJSON)
    deriving newtype (Integer -> PageSize
PageSize -> PageSize
PageSize -> PageSize -> PageSize
(PageSize -> PageSize -> PageSize)
-> (PageSize -> PageSize -> PageSize)
-> (PageSize -> PageSize -> PageSize)
-> (PageSize -> PageSize)
-> (PageSize -> PageSize)
-> (PageSize -> PageSize)
-> (Integer -> PageSize)
-> Num PageSize
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> PageSize
$cfromInteger :: Integer -> PageSize
signum :: PageSize -> PageSize
$csignum :: PageSize -> PageSize
abs :: PageSize -> PageSize
$cabs :: PageSize -> PageSize
negate :: PageSize -> PageSize
$cnegate :: PageSize -> PageSize
* :: PageSize -> PageSize -> PageSize
$c* :: PageSize -> PageSize -> PageSize
- :: PageSize -> PageSize -> PageSize
$c- :: PageSize -> PageSize -> PageSize
+ :: PageSize -> PageSize -> PageSize
$c+ :: PageSize -> PageSize -> PageSize
Num)

instance Default PageSize where
    def :: PageSize
def = Natural -> PageSize
PageSize Natural
50

-- | Part of a collection.
data Page a = Page
    { Page a -> PageQuery a
currentPageQuery :: PageQuery a
    -- ^ The 'PageQuery' which was used to request this 'Page'.
    , Page a -> Maybe (PageQuery a)
nextPageQuery    :: Maybe (PageQuery a)
    -- ^ The 'PageQuery' to use to request the next 'Page'. Nothing if we requested the last page.
    , Page a -> [a]
pageItems        :: [a]
    -- ^ Items in the current 'Page'.
    }
    deriving stock (Page a -> Page a -> Bool
(Page a -> Page a -> Bool)
-> (Page a -> Page a -> Bool) -> Eq (Page a)
forall a. Eq a => Page a -> Page a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Page a -> Page a -> Bool
$c/= :: forall a. Eq a => Page a -> Page a -> Bool
== :: Page a -> Page a -> Bool
$c== :: forall a. Eq a => Page a -> Page a -> Bool
Eq, Eq (Page a)
Eq (Page a)
-> (Page a -> Page a -> Ordering)
-> (Page a -> Page a -> Bool)
-> (Page a -> Page a -> Bool)
-> (Page a -> Page a -> Bool)
-> (Page a -> Page a -> Bool)
-> (Page a -> Page a -> Page a)
-> (Page a -> Page a -> Page a)
-> Ord (Page a)
Page a -> Page a -> Bool
Page a -> Page a -> Ordering
Page a -> Page a -> Page a
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 a. Ord a => Eq (Page a)
forall a. Ord a => Page a -> Page a -> Bool
forall a. Ord a => Page a -> Page a -> Ordering
forall a. Ord a => Page a -> Page a -> Page a
min :: Page a -> Page a -> Page a
$cmin :: forall a. Ord a => Page a -> Page a -> Page a
max :: Page a -> Page a -> Page a
$cmax :: forall a. Ord a => Page a -> Page a -> Page a
>= :: Page a -> Page a -> Bool
$c>= :: forall a. Ord a => Page a -> Page a -> Bool
> :: Page a -> Page a -> Bool
$c> :: forall a. Ord a => Page a -> Page a -> Bool
<= :: Page a -> Page a -> Bool
$c<= :: forall a. Ord a => Page a -> Page a -> Bool
< :: Page a -> Page a -> Bool
$c< :: forall a. Ord a => Page a -> Page a -> Bool
compare :: Page a -> Page a -> Ordering
$ccompare :: forall a. Ord a => Page a -> Page a -> Ordering
$cp1Ord :: forall a. Ord a => Eq (Page a)
Ord, Int -> Page a -> ShowS
[Page a] -> ShowS
Page a -> String
(Int -> Page a -> ShowS)
-> (Page a -> String) -> ([Page a] -> ShowS) -> Show (Page a)
forall a. Show a => Int -> Page a -> ShowS
forall a. Show a => [Page a] -> ShowS
forall a. Show a => Page a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Page a] -> ShowS
$cshowList :: forall a. Show a => [Page a] -> ShowS
show :: Page a -> String
$cshow :: forall a. Show a => Page a -> String
showsPrec :: Int -> Page a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Page a -> ShowS
Show, (forall x. Page a -> Rep (Page a) x)
-> (forall x. Rep (Page a) x -> Page a) -> Generic (Page a)
forall x. Rep (Page a) x -> Page a
forall x. Page a -> Rep (Page a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (Page a) x -> Page a
forall a x. Page a -> Rep (Page a) x
$cto :: forall a x. Rep (Page a) x -> Page a
$cfrom :: forall a x. Page a -> Rep (Page a) x
Generic, a -> Page b -> Page a
(a -> b) -> Page a -> Page b
(forall a b. (a -> b) -> Page a -> Page b)
-> (forall a b. a -> Page b -> Page a) -> Functor Page
forall a b. a -> Page b -> Page a
forall a b. (a -> b) -> Page a -> Page b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Page b -> Page a
$c<$ :: forall a b. a -> Page b -> Page a
fmap :: (a -> b) -> Page a -> Page b
$cfmap :: forall a b. (a -> b) -> Page a -> Page b
Functor)
    deriving anyclass ([Page a] -> Value
[Page a] -> Encoding
Page a -> Value
Page a -> Encoding
(Page a -> Value)
-> (Page a -> Encoding)
-> ([Page a] -> Value)
-> ([Page a] -> Encoding)
-> ToJSON (Page a)
forall a. ToJSON a => [Page a] -> Value
forall a. ToJSON a => [Page a] -> Encoding
forall a. ToJSON a => Page a -> Value
forall a. ToJSON a => Page a -> Encoding
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [Page a] -> Encoding
$ctoEncodingList :: forall a. ToJSON a => [Page a] -> Encoding
toJSONList :: [Page a] -> Value
$ctoJSONList :: forall a. ToJSON a => [Page a] -> Value
toEncoding :: Page a -> Encoding
$ctoEncoding :: forall a. ToJSON a => Page a -> Encoding
toJSON :: Page a -> Value
$ctoJSON :: forall a. ToJSON a => Page a -> Value
ToJSON, Value -> Parser [Page a]
Value -> Parser (Page a)
(Value -> Parser (Page a))
-> (Value -> Parser [Page a]) -> FromJSON (Page a)
forall a. FromJSON a => Value -> Parser [Page a]
forall a. FromJSON a => Value -> Parser (Page a)
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [Page a]
$cparseJSONList :: forall a. FromJSON a => Value -> Parser [Page a]
parseJSON :: Value -> Parser (Page a)
$cparseJSON :: forall a. FromJSON a => Value -> Parser (Page a)
FromJSON)

-- | Given a 'Set', request the 'Page' with the given 'PageQuery'.
pageOf
  :: (Eq a)
  => PageQuery a -- ^ Pagination query parameters.
  -> Set a
  -> Page a
pageOf :: PageQuery a -> Set a -> Page a
pageOf pageQuery :: PageQuery a
pageQuery@PageQuery { pageQuerySize :: forall a. PageQuery a -> PageSize
pageQuerySize = PageSize Natural
ps, Maybe a
pageQueryLastItem :: Maybe a
pageQueryLastItem :: forall a. PageQuery a -> Maybe a
pageQueryLastItem } Set a
items =
    let ps' :: Int
ps' = Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
ps
        -- The extract the @PageSize + 1@ next elements after the last query
        -- element. The @+1@ allows to now if there is a next page or not.
        pageItems :: [a]
pageItems = case Maybe a
pageQueryLastItem of
                      Maybe a
Nothing -> Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take (Int
ps' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ Set a -> [a]
forall a. Set a -> [a]
Set.toList Set a
items
                      Just a
i  -> Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take (Int
ps' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
1 ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(/=) a
i) ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ Set a -> [a]
forall a. Set a -> [a]
Set.toList Set a
items

        nextLastItem :: Maybe a
nextLastItem = Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Set a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Set a
items Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
ps)
                 Maybe () -> Maybe (NonEmpty a) -> Maybe (NonEmpty a)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [a] -> Maybe (NonEmpty a)
forall a. [a] -> Maybe (NonEmpty a)
L.nonEmpty [a]
pageItems
                 Maybe (NonEmpty a) -> (NonEmpty a -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe ([a] -> Maybe a) -> (NonEmpty a -> [a]) -> NonEmpty a -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
L.tail (NonEmpty a -> [a])
-> (NonEmpty a -> NonEmpty a) -> NonEmpty a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty a -> NonEmpty a
forall a. NonEmpty a -> NonEmpty a
L.reverse
    in Page :: forall a. PageQuery a -> Maybe (PageQuery a) -> [a] -> Page a
Page
        { currentPageQuery :: PageQuery a
currentPageQuery = PageQuery a
pageQuery
        , nextPageQuery :: Maybe (PageQuery a)
nextPageQuery = (a -> PageQuery a) -> Maybe a -> Maybe (PageQuery a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (PageSize -> Maybe a -> PageQuery a
forall a. PageSize -> Maybe a -> PageQuery a
PageQuery (Natural -> PageSize
PageSize Natural
ps) (Maybe a -> PageQuery a) -> (a -> Maybe a) -> a -> PageQuery a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Maybe a
forall a. a -> Maybe a
Just) Maybe a
nextLastItem
        , pageItems :: [a]
pageItems = if Maybe a -> Bool
forall a. Maybe a -> Bool
isJust Maybe a
nextLastItem then [a] -> [a]
forall a. [a] -> [a]
init [a]
pageItems else [a]
pageItems
        }