{-# LANGUAGE OverloadedStrings #-}
module Network.JSONApi.Pagination (
Pagination (..)
, PageIndex (..)
, PageSize (..)
, ResourceCount (..)
, Strategy (..)
, mkPaginationLinks
) where
import Network.JSONApi.Link (Links, Rel, mkLinks)
import Network.URL (URL, add_param)
data Pagination = Pagination {
getPaginationPageIndex :: PageIndex
, getPaginationPageSize :: PageSize
, getPaginationResourceCount :: ResourceCount
}
newtype PageSize = PageSize {
getPageSize :: Word
} deriving Show
newtype PageIndex = PageIndex {
getPageIndex :: Word
} deriving Show
newtype ResourceCount = ResourceCount {
getResourceCount :: Word
} deriving Show
data Strategy = PageStrategy | OffsetStrategy
mkPaginationLinks :: Strategy -> URL -> Pagination -> Links
mkPaginationLinks strategy baseUrl page =
mkLinks (baseLinks ++ nextLinks ++ prevLinks)
where
pgIndex = getPageIndex $ getPaginationPageIndex page
pgSize = getPageSize $ getPaginationPageSize page
baseLinks = [mkPaginationLink strategy "first" baseUrl (firstPageIndex strategy) pgSize
, mkPaginationLink strategy "last" baseUrl (lastPageIndex strategy page) pgSize]
nextLinks = [mkPaginationLink strategy "next" baseUrl (pgIndex + 1) pgSize | shouldGenNextLink strategy page]
prevLinks = [mkPaginationLink strategy "prev" baseUrl (pgIndex - 1) pgSize | shouldGenPrevLink strategy page]
shouldGenNextLink :: Strategy -> Pagination -> Bool
shouldGenNextLink PageStrategy pagination =
(getPageIndex . getPaginationPageIndex) pagination < numberOfPagesInPageList pagination
shouldGenNextLink OffsetStrategy pagination =
(getPageIndex . getPaginationPageIndex) pagination < numberOfPagesInPageList pagination - 1
shouldGenPrevLink :: Strategy -> Pagination -> Bool
shouldGenPrevLink strategy pagination =
(getPageIndex . getPaginationPageIndex) pagination > firstPageIndex strategy
numberOfPagesInPageList :: Pagination -> Word
numberOfPagesInPageList (Pagination _ pageSize resourceCount) =
if resCount `mod` pgSize == 0
then resCount `quot` pgSize
else (resCount `quot` pgSize) + 1
where
pgSize = getPageSize pageSize
resCount = getResourceCount resourceCount
mkPaginationLink :: Strategy -> Rel -> URL -> Word -> Word -> (Rel, URL)
mkPaginationLink strategy key baseUrl pageNo pageSize =
(key, link)
where
pageNoUrl = add_param baseUrl (strategyToQueryStringNumberKey strategy, show pageNo)
link = add_param pageNoUrl (strategyToQueryStringSizeKey strategy, show pageSize)
firstPageIndex :: Strategy -> Word
firstPageIndex PageStrategy = 1
firstPageIndex OffsetStrategy = 0
lastPageIndex :: Strategy -> Pagination -> Word
lastPageIndex PageStrategy page = numberOfPagesInPageList page
lastPageIndex OffsetStrategy page = numberOfPagesInPageList page - 1
strategyToQueryStringNumberKey :: Strategy -> String
strategyToQueryStringNumberKey PageStrategy = "page[number]"
strategyToQueryStringNumberKey OffsetStrategy = "page[offset]"
strategyToQueryStringSizeKey :: Strategy -> String
strategyToQueryStringSizeKey PageStrategy = "page[size]"
strategyToQueryStringSizeKey OffsetStrategy = "page[limit]"