module Yesod.Paginate (
paginate, paginateWith,
PageConfig (..),
Page (..)
) where
import Control.Monad
import Data.Int
import Data.Maybe
import Database.Esqueleto
import Database.Esqueleto.Internal.Language
import Database.Esqueleto.Internal.Sql
import Prelude
import Yesod hiding (Value)
data PageConfig app = PageConfig
{ pageSize :: Int
, currentPage :: Int
, firstPageRoute :: Route app
, pageRoute :: Int -> Route app
}
data Page route r = Page
{ pageResults :: [r]
, firstPage :: Maybe route
, nextPage :: Maybe route
, previousPage :: Maybe route
} deriving (Eq, Read, Show)
paginate :: ( From SqlQuery SqlExpr SqlBackend a
, SqlSelect a a1, YesodPersist site
, YesodPersistBackend site ~ Connection)
=> PageConfig app -> HandlerT site IO (Page (Route app) a1)
paginate c = paginateWith c return
paginateWith :: ( From SqlQuery SqlExpr SqlBackend a1, SqlSelect a a2
, YesodPersist site, YesodPersistBackend site ~ Connection
)
=> PageConfig app
-> (a1 -> SqlQuery a)
-> HandlerT site IO (Page (Route app) a2)
paginateWith c sel = do
let cp = max 1 $ fromIntegral (currentPage c)
es <- runDB $ select $ from $ \ u -> do
limit (fromIntegral (pageSize c) + 1)
offset $ max 0 $ fromIntegral (pageSize c) * (cp 1)
sel u
let route = pageRoute c . fromIntegral
return Page { pageResults = take (fromIntegral $ pageSize c) es
, firstPage = if cp >= 2 then Just (firstPageRoute c) else Nothing
, nextPage = if fromIntegral (length es) == pageSize c + 1
then Just (route $ cp + 1)
else Nothing
, previousPage = if cp == 1 then Nothing else Just (route $ cp 1)
}