{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE RecordWildCards #-}

-- |
-- Module      :  Data.Pagination
-- Copyright   :  © 2016–present Mark Karpov
-- License     :  BSD 3 clause
--
-- Maintainer  :  Mark Karpov <markkarpov92@gmail.com>
-- Stability   :  experimental
-- Portability :  portable
--
-- Framework-agnostic pagination boilerplate.
module Data.Pagination
  ( -- * Pagination settings
    Pagination,
    mkPagination,
    pageSize,
    pageIndex,

    -- * Paginated data
    Paginated,
    paginate,
    paginatedItems,
    paginatedPagination,
    paginatedPagesTotal,
    paginatedItemsTotal,
    hasOtherPages,
    pageRange,
    hasPrevPage,
    hasNextPage,
    backwardEllip,
    forwardEllip,

    -- * Exceptions
    PaginationException (..),
  )
where

import Control.DeepSeq
import Control.Monad.Catch
import Data.Data (Data)
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Typeable (Typeable)
import GHC.Generics
import Numeric.Natural

----------------------------------------------------------------------------
-- Pagination settings

-- | Settings that are required to organize data in paginated form.
data Pagination = Pagination Natural Natural
  deriving (Pagination -> Pagination -> Bool
(Pagination -> Pagination -> Bool)
-> (Pagination -> Pagination -> Bool) -> Eq Pagination
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Pagination -> Pagination -> Bool
$c/= :: Pagination -> Pagination -> Bool
== :: Pagination -> Pagination -> Bool
$c== :: Pagination -> Pagination -> Bool
Eq, Int -> Pagination -> ShowS
[Pagination] -> ShowS
Pagination -> String
(Int -> Pagination -> ShowS)
-> (Pagination -> String)
-> ([Pagination] -> ShowS)
-> Show Pagination
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pagination] -> ShowS
$cshowList :: [Pagination] -> ShowS
show :: Pagination -> String
$cshow :: Pagination -> String
showsPrec :: Int -> Pagination -> ShowS
$cshowsPrec :: Int -> Pagination -> ShowS
Show, Typeable Pagination
DataType
Constr
Typeable Pagination
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Pagination -> c Pagination)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Pagination)
-> (Pagination -> Constr)
-> (Pagination -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Pagination))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c Pagination))
-> ((forall b. Data b => b -> b) -> Pagination -> Pagination)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> Pagination -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> Pagination -> r)
-> (forall u. (forall d. Data d => d -> u) -> Pagination -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> Pagination -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Pagination -> m Pagination)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Pagination -> m Pagination)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Pagination -> m Pagination)
-> Data Pagination
Pagination -> DataType
Pagination -> Constr
(forall b. Data b => b -> b) -> Pagination -> Pagination
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Pagination -> c Pagination
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Pagination
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Pagination -> u
forall u. (forall d. Data d => d -> u) -> Pagination -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Pagination -> m Pagination
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Pagination -> m Pagination
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Pagination
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Pagination -> c Pagination
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Pagination)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Pagination)
$cPagination :: Constr
$tPagination :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> Pagination -> m Pagination
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Pagination -> m Pagination
gmapMp :: (forall d. Data d => d -> m d) -> Pagination -> m Pagination
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Pagination -> m Pagination
gmapM :: (forall d. Data d => d -> m d) -> Pagination -> m Pagination
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Pagination -> m Pagination
gmapQi :: Int -> (forall d. Data d => d -> u) -> Pagination -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Pagination -> u
gmapQ :: (forall d. Data d => d -> u) -> Pagination -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Pagination -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Pagination -> r
gmapT :: (forall b. Data b => b -> b) -> Pagination -> Pagination
$cgmapT :: (forall b. Data b => b -> b) -> Pagination -> Pagination
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Pagination)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Pagination)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c Pagination)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Pagination)
dataTypeOf :: Pagination -> DataType
$cdataTypeOf :: Pagination -> DataType
toConstr :: Pagination -> Constr
$ctoConstr :: Pagination -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Pagination
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Pagination
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Pagination -> c Pagination
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Pagination -> c Pagination
$cp1Data :: Typeable Pagination
Data, Typeable, (forall x. Pagination -> Rep Pagination x)
-> (forall x. Rep Pagination x -> Pagination) -> Generic Pagination
forall x. Rep Pagination x -> Pagination
forall x. Pagination -> Rep Pagination x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Pagination x -> Pagination
$cfrom :: forall x. Pagination -> Rep Pagination x
Generic)

instance NFData Pagination

-- | Create a 'Pagination' value. May throw 'PaginationException'.
mkPagination ::
  MonadThrow m =>
  -- | Page size
  Natural ->
  -- | Page index
  Natural ->
  -- | The pagination settings
  m Pagination
mkPagination :: Natural -> Natural -> m Pagination
mkPagination Natural
size Natural
index
  | Natural
size Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
0 = PaginationException -> m Pagination
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM PaginationException
ZeroPageSize
  | Natural
index Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
0 = PaginationException -> m Pagination
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM PaginationException
ZeroPageIndex
  | Bool
otherwise = Pagination -> m Pagination
forall (m :: * -> *) a. Monad m => a -> m a
return (Natural -> Natural -> Pagination
Pagination Natural
size Natural
index)

-- | Get page size (maximum number of items on a page) from a 'Pagination'.
pageSize :: Pagination -> Natural
pageSize :: Pagination -> Natural
pageSize (Pagination Natural
size Natural
_) = Natural
size

-- | Get page index from a 'Pagination'.
pageIndex :: Pagination -> Natural
pageIndex :: Pagination -> Natural
pageIndex (Pagination Natural
_ Natural
index) = Natural
index

----------------------------------------------------------------------------
-- Paginated data

-- | Data in the paginated form.
data Paginated a = Paginated
  { Paginated a -> [a]
pgItems :: [a],
    Paginated a -> Pagination
pgPagination :: Pagination,
    Paginated a -> Natural
pgPagesTotal :: Natural,
    Paginated a -> Natural
pgItemsTotal :: Natural
  }
  deriving (Paginated a -> Paginated a -> Bool
(Paginated a -> Paginated a -> Bool)
-> (Paginated a -> Paginated a -> Bool) -> Eq (Paginated a)
forall a. Eq a => Paginated a -> Paginated a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Paginated a -> Paginated a -> Bool
$c/= :: forall a. Eq a => Paginated a -> Paginated a -> Bool
== :: Paginated a -> Paginated a -> Bool
$c== :: forall a. Eq a => Paginated a -> Paginated a -> Bool
Eq, Int -> Paginated a -> ShowS
[Paginated a] -> ShowS
Paginated a -> String
(Int -> Paginated a -> ShowS)
-> (Paginated a -> String)
-> ([Paginated a] -> ShowS)
-> Show (Paginated a)
forall a. Show a => Int -> Paginated a -> ShowS
forall a. Show a => [Paginated a] -> ShowS
forall a. Show a => Paginated a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Paginated a] -> ShowS
$cshowList :: forall a. Show a => [Paginated a] -> ShowS
show :: Paginated a -> String
$cshow :: forall a. Show a => Paginated a -> String
showsPrec :: Int -> Paginated a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Paginated a -> ShowS
Show, Typeable (Paginated a)
DataType
Constr
Typeable (Paginated a)
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Paginated a -> c (Paginated a))
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c (Paginated a))
-> (Paginated a -> Constr)
-> (Paginated a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c (Paginated a)))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c (Paginated a)))
-> ((forall b. Data b => b -> b) -> Paginated a -> Paginated a)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> Paginated a -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> Paginated a -> r)
-> (forall u. (forall d. Data d => d -> u) -> Paginated a -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> Paginated a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a))
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a))
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a))
-> Data (Paginated a)
Paginated a -> DataType
Paginated a -> Constr
(forall d. Data d => c (t d)) -> Maybe (c (Paginated a))
(forall b. Data b => b -> b) -> Paginated a -> Paginated a
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Paginated a -> c (Paginated a)
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Paginated a)
forall a. Data a => Typeable (Paginated a)
forall a. Data a => Paginated a -> DataType
forall a. Data a => Paginated a -> Constr
forall a.
Data a =>
(forall b. Data b => b -> b) -> Paginated a -> Paginated a
forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> Paginated a -> u
forall a u.
Data a =>
(forall d. Data d => d -> u) -> Paginated a -> [u]
forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
forall a (m :: * -> *).
(Data a, Monad m) =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
forall a (c :: * -> *).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Paginated a)
forall a (c :: * -> *).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Paginated a -> c (Paginated a)
forall a (t :: * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (Paginated a))
forall a (t :: * -> * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Paginated a))
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Paginated a -> u
forall u. (forall d. Data d => d -> u) -> Paginated a -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Paginated a)
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Paginated a -> c (Paginated a)
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c (Paginated a))
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Paginated a))
$cPaginated :: Constr
$tPaginated :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
$cgmapMo :: forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
gmapMp :: (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
$cgmapMp :: forall a (m :: * -> *).
(Data a, MonadPlus m) =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
gmapM :: (forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
$cgmapM :: forall a (m :: * -> *).
(Data a, Monad m) =>
(forall d. Data d => d -> m d) -> Paginated a -> m (Paginated a)
gmapQi :: Int -> (forall d. Data d => d -> u) -> Paginated a -> u
$cgmapQi :: forall a u.
Data a =>
Int -> (forall d. Data d => d -> u) -> Paginated a -> u
gmapQ :: (forall d. Data d => d -> u) -> Paginated a -> [u]
$cgmapQ :: forall a u.
Data a =>
(forall d. Data d => d -> u) -> Paginated a -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
$cgmapQr :: forall a r r'.
Data a =>
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
$cgmapQl :: forall a r r'.
Data a =>
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> Paginated a -> r
gmapT :: (forall b. Data b => b -> b) -> Paginated a -> Paginated a
$cgmapT :: forall a.
Data a =>
(forall b. Data b => b -> b) -> Paginated a -> Paginated a
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Paginated a))
$cdataCast2 :: forall a (t :: * -> * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Paginated a))
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c (Paginated a))
$cdataCast1 :: forall a (t :: * -> *) (c :: * -> *).
(Data a, Typeable t) =>
(forall d. Data d => c (t d)) -> Maybe (c (Paginated a))
dataTypeOf :: Paginated a -> DataType
$cdataTypeOf :: forall a. Data a => Paginated a -> DataType
toConstr :: Paginated a -> Constr
$ctoConstr :: forall a. Data a => Paginated a -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Paginated a)
$cgunfold :: forall a (c :: * -> *).
Data a =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Paginated a)
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Paginated a -> c (Paginated a)
$cgfoldl :: forall a (c :: * -> *).
Data a =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Paginated a -> c (Paginated a)
$cp1Data :: forall a. Data a => Typeable (Paginated a)
Data, Typeable, (forall x. Paginated a -> Rep (Paginated a) x)
-> (forall x. Rep (Paginated a) x -> Paginated a)
-> Generic (Paginated a)
forall x. Rep (Paginated a) x -> Paginated a
forall x. Paginated a -> Rep (Paginated a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (Paginated a) x -> Paginated a
forall a x. Paginated a -> Rep (Paginated a) x
$cto :: forall a x. Rep (Paginated a) x -> Paginated a
$cfrom :: forall a x. Paginated a -> Rep (Paginated a) x
Generic, a -> Paginated b -> Paginated a
(a -> b) -> Paginated a -> Paginated b
(forall a b. (a -> b) -> Paginated a -> Paginated b)
-> (forall a b. a -> Paginated b -> Paginated a)
-> Functor Paginated
forall a b. a -> Paginated b -> Paginated a
forall a b. (a -> b) -> Paginated a -> Paginated b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Paginated b -> Paginated a
$c<$ :: forall a b. a -> Paginated b -> Paginated a
fmap :: (a -> b) -> Paginated a -> Paginated b
$cfmap :: forall a b. (a -> b) -> Paginated a -> Paginated b
Functor)

instance NFData a => NFData (Paginated a)

instance Foldable Paginated where
  foldr :: (a -> b -> b) -> b -> Paginated a -> b
foldr a -> b -> b
f b
x = (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr a -> b -> b
f b
x ([a] -> b) -> (Paginated a -> [a]) -> Paginated a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Paginated a -> [a]
forall a. Paginated a -> [a]
pgItems

instance Traversable Paginated where
  traverse :: (a -> f b) -> Paginated a -> f (Paginated b)
traverse a -> f b
f Paginated a
p =
    let g :: Paginated a -> [a] -> Paginated a
g Paginated a
p' [a]
xs = Paginated a
p' {pgItems :: [a]
pgItems = [a]
xs}
     in Paginated a -> [b] -> Paginated b
forall a a. Paginated a -> [a] -> Paginated a
g Paginated a
p ([b] -> Paginated b) -> f [b] -> f (Paginated b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (a -> f b) -> [a] -> f [b]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse a -> f b
f (Paginated a -> [a]
forall a. Paginated a -> [a]
pgItems Paginated a
p)

-- | Create paginated data.
paginate ::
  (Functor m, Integral n) =>
  -- | Pagination options
  Pagination ->
  -- | Total number of items
  Natural ->
  -- | The element producing callback. The function takes arguments:
  -- offset and limit.
  (n -> n -> m [a]) ->
  -- | The paginated data
  m (Paginated a)
paginate :: Pagination -> Natural -> (n -> n -> m [a]) -> m (Paginated a)
paginate (Pagination Natural
size Natural
index') Natural
totalItems n -> n -> m [a]
f =
  [a] -> Paginated a
forall a. [a] -> Paginated a
r ([a] -> Paginated a) -> m [a] -> m (Paginated a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> n -> n -> m [a]
f (Natural -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
offset) (Natural -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
size)
  where
    r :: [a] -> Paginated a
r [a]
xs =
      Paginated :: forall a. [a] -> Pagination -> Natural -> Natural -> Paginated a
Paginated
        { pgItems :: [a]
pgItems = [a]
xs,
          pgPagination :: Pagination
pgPagination = Natural -> Natural -> Pagination
Pagination Natural
size Natural
index,
          pgPagesTotal :: Natural
pgPagesTotal = Natural
totalPages,
          pgItemsTotal :: Natural
pgItemsTotal = Natural
totalItems
        }
    (Natural
whole, Natural
rems) = Natural
totalItems Natural -> Natural -> (Natural, Natural)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Natural
size
    totalPages :: Natural
totalPages = Natural -> Natural -> Natural
forall a. Ord a => a -> a -> a
max Natural
1 (Natural
whole Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ if Natural
rems Natural -> Natural -> Bool
forall a. Eq a => a -> a -> Bool
== Natural
0 then Natural
0 else Natural
1)
    index :: Natural
index = Natural -> Natural -> Natural
forall a. Ord a => a -> a -> a
min Natural
index' Natural
totalPages
    offset :: Natural
offset = (Natural
index Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
1) Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
size

-- | Get subset of items for current page.
paginatedItems :: Paginated a -> [a]
paginatedItems :: Paginated a -> [a]
paginatedItems = Paginated a -> [a]
forall a. Paginated a -> [a]
pgItems

-- | Get 'Pagination' parameters that were used to create this paginated
-- result.
paginatedPagination :: Paginated a -> Pagination
paginatedPagination :: Paginated a -> Pagination
paginatedPagination = Paginated a -> Pagination
forall a. Paginated a -> Pagination
pgPagination

-- | Get the total number of pages in this collection.
paginatedPagesTotal :: Paginated a -> Natural
paginatedPagesTotal :: Paginated a -> Natural
paginatedPagesTotal = Paginated a -> Natural
forall a. Paginated a -> Natural
pgPagesTotal

-- | Get the total number of items in this collection.
paginatedItemsTotal :: Paginated a -> Natural
paginatedItemsTotal :: Paginated a -> Natural
paginatedItemsTotal = Paginated a -> Natural
forall a. Paginated a -> Natural
pgItemsTotal

-- | Test whether there are other pages.
hasOtherPages :: Paginated a -> Bool
hasOtherPages :: Paginated a -> Bool
hasOtherPages Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} = Natural
pgPagesTotal Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
> Natural
1

-- | Is there previous page?
hasPrevPage :: Paginated a -> Bool
hasPrevPage :: Paginated a -> Bool
hasPrevPage Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} = Pagination -> Natural
pageIndex Pagination
pgPagination Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
> Natural
1

-- | Is there next page?
hasNextPage :: Paginated a -> Bool
hasNextPage :: Paginated a -> Bool
hasNextPage Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} = Pagination -> Natural
pageIndex Pagination
pgPagination Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
pgPagesTotal

-- | Get range of pages to show before and after the current page. This does
-- not necessarily include the first and the last pages (they are supposed
-- to be shown in all cases). Result of the function is always sorted.
pageRange ::
  -- | Paginated data
  Paginated a ->
  -- | Number of pages to show before and after
  Natural ->
  -- | Page range
  NonEmpty Natural
pageRange :: Paginated a -> Natural -> NonEmpty Natural
pageRange Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} Natural
0 = [Natural] -> NonEmpty Natural
forall a. [a] -> NonEmpty a
NE.fromList [Pagination -> Natural
pageIndex Pagination
pgPagination]
pageRange Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} Natural
n =
  let len :: Natural
len = Natural -> Natural -> Natural
forall a. Ord a => a -> a -> a
min Natural
pgPagesTotal (Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
2 Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
1)
      index :: Natural
index = Pagination -> Natural
pageIndex Pagination
pgPagination
      shift :: Natural
shift
        | Natural
index Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
<= Natural
n = Natural
0
        | Natural
index Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
>= Natural
pgPagesTotal Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
n = Natural
pgPagesTotal Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
len
        | Bool
otherwise = Natural
index Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
n Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
1
   in (Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
shift) (Natural -> Natural) -> NonEmpty Natural -> NonEmpty Natural
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Natural] -> NonEmpty Natural
forall a. [a] -> NonEmpty a
NE.fromList [Natural
1 .. Natural
len]

-- | Backward ellipsis appears when page range (pages around current page to
-- jump to) has gap between its beginning and the first page.
backwardEllip ::
  -- | Paginated data
  Paginated a ->
  -- | Number of pages to show before and after
  Natural ->
  Bool
backwardEllip :: Paginated a -> Natural -> Bool
backwardEllip Paginated a
p Natural
n = NonEmpty Natural -> Natural
forall a. NonEmpty a -> a
NE.head (Paginated a -> Natural -> NonEmpty Natural
forall a. Paginated a -> Natural -> NonEmpty Natural
pageRange Paginated a
p Natural
n) Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
> Natural
2

-- | Forward ellipsis appears when page range (pages around current page to
-- jump to) has gap between its end and the last page.
forwardEllip ::
  -- | Paginated data
  Paginated a ->
  -- | Number of pages to show before and after
  Natural ->
  -- | Do we have forward ellipsis?
  Bool
forwardEllip :: Paginated a -> Natural -> Bool
forwardEllip p :: Paginated a
p@Paginated {Natural
[a]
Pagination
pgItemsTotal :: Natural
pgPagesTotal :: Natural
pgPagination :: Pagination
pgItems :: [a]
pgItemsTotal :: forall a. Paginated a -> Natural
pgPagesTotal :: forall a. Paginated a -> Natural
pgPagination :: forall a. Paginated a -> Pagination
pgItems :: forall a. Paginated a -> [a]
..} Natural
n = NonEmpty Natural -> Natural
forall a. NonEmpty a -> a
NE.last (Paginated a -> Natural -> NonEmpty Natural
forall a. Paginated a -> Natural -> NonEmpty Natural
pageRange Paginated a
p Natural
n) Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural -> Natural
forall a. Enum a => a -> a
pred Natural
pgPagesTotal

----------------------------------------------------------------------------
-- Exceptions

-- | Exception indicating various problems when working with paginated data.
data PaginationException
  = -- | Page size (number of items per page) was zero
    ZeroPageSize
  | -- | Page index was zero (they start from one)
    ZeroPageIndex
  deriving (PaginationException -> PaginationException -> Bool
(PaginationException -> PaginationException -> Bool)
-> (PaginationException -> PaginationException -> Bool)
-> Eq PaginationException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PaginationException -> PaginationException -> Bool
$c/= :: PaginationException -> PaginationException -> Bool
== :: PaginationException -> PaginationException -> Bool
$c== :: PaginationException -> PaginationException -> Bool
Eq, Int -> PaginationException -> ShowS
[PaginationException] -> ShowS
PaginationException -> String
(Int -> PaginationException -> ShowS)
-> (PaginationException -> String)
-> ([PaginationException] -> ShowS)
-> Show PaginationException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PaginationException] -> ShowS
$cshowList :: [PaginationException] -> ShowS
show :: PaginationException -> String
$cshow :: PaginationException -> String
showsPrec :: Int -> PaginationException -> ShowS
$cshowsPrec :: Int -> PaginationException -> ShowS
Show, Typeable PaginationException
DataType
Constr
Typeable PaginationException
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g)
    -> PaginationException
    -> c PaginationException)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c PaginationException)
-> (PaginationException -> Constr)
-> (PaginationException -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c PaginationException))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e))
    -> Maybe (c PaginationException))
-> ((forall b. Data b => b -> b)
    -> PaginationException -> PaginationException)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> PaginationException -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> PaginationException -> r)
-> (forall u.
    (forall d. Data d => d -> u) -> PaginationException -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> PaginationException -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d)
    -> PaginationException -> m PaginationException)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> PaginationException -> m PaginationException)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d)
    -> PaginationException -> m PaginationException)
-> Data PaginationException
PaginationException -> DataType
PaginationException -> Constr
(forall b. Data b => b -> b)
-> PaginationException -> PaginationException
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> PaginationException
-> c PaginationException
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c PaginationException
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u.
Int -> (forall d. Data d => d -> u) -> PaginationException -> u
forall u.
(forall d. Data d => d -> u) -> PaginationException -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c PaginationException
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> PaginationException
-> c PaginationException
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c PaginationException)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c PaginationException)
$cZeroPageIndex :: Constr
$cZeroPageSize :: Constr
$tPaginationException :: DataType
gmapMo :: (forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
gmapMp :: (forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
gmapM :: (forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> PaginationException -> m PaginationException
gmapQi :: Int -> (forall d. Data d => d -> u) -> PaginationException -> u
$cgmapQi :: forall u.
Int -> (forall d. Data d => d -> u) -> PaginationException -> u
gmapQ :: (forall d. Data d => d -> u) -> PaginationException -> [u]
$cgmapQ :: forall u.
(forall d. Data d => d -> u) -> PaginationException -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> PaginationException -> r
gmapT :: (forall b. Data b => b -> b)
-> PaginationException -> PaginationException
$cgmapT :: (forall b. Data b => b -> b)
-> PaginationException -> PaginationException
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c PaginationException)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c PaginationException)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c PaginationException)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c PaginationException)
dataTypeOf :: PaginationException -> DataType
$cdataTypeOf :: PaginationException -> DataType
toConstr :: PaginationException -> Constr
$ctoConstr :: PaginationException -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c PaginationException
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c PaginationException
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> PaginationException
-> c PaginationException
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> PaginationException
-> c PaginationException
$cp1Data :: Typeable PaginationException
Data, Typeable, (forall x. PaginationException -> Rep PaginationException x)
-> (forall x. Rep PaginationException x -> PaginationException)
-> Generic PaginationException
forall x. Rep PaginationException x -> PaginationException
forall x. PaginationException -> Rep PaginationException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep PaginationException x -> PaginationException
$cfrom :: forall x. PaginationException -> Rep PaginationException x
Generic)

instance NFData PaginationException

instance Exception PaginationException