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 :: (YesodPersist site, SqlSelect a s,
MonadResource (YesodPersistBackend site (HandlerT site IO)),
From SqlQuery SqlExpr SqlBackend a,
MonadSqlPersist (YesodPersistBackend site (HandlerT site IO)))
=> PageConfig site
-> HandlerT site IO (Page (Route site) s)
paginate c = paginateWith c return
paginateWith :: (YesodPersist site, SqlSelect a s,
MonadResource (YesodPersistBackend site (HandlerT site IO)),
From SqlQuery SqlExpr SqlBackend q,
MonadSqlPersist (YesodPersistBackend site (HandlerT site IO)))
=> PageConfig site
-> (q -> SqlQuery a)
-> HandlerT site IO (Page (Route site) s)
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
pp | cp == 1 = Nothing
| cp == 2 = Just (firstPageRoute c)
| otherwise = Just (route $ cp 1)
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 = pp
}