diff --git a/src/Handler/Utils/Table/Pagination.hs b/src/Handler/Utils/Table/Pagination.hs index f00426e45..28fcb1073 100644 --- a/src/Handler/Utils/Table/Pagination.hs +++ b/src/Handler/Utils/Table/Pagination.hs @@ -8,7 +8,13 @@ , ViewPatterns #-} -module Handler.Utils.Table.Pagination where +module Handler.Utils.Table.Pagination + ( SortColumn(..), SortDirection(..) + , DBTable(..) + , PaginationSettings(..) + , PSValidator(..) + , dbTable + ) where import Import import qualified Database.Esqueleto as E @@ -16,9 +22,12 @@ import qualified Database.Esqueleto.Internal.Sql as E (SqlSelect) import Text.Blaze (Attribute) import qualified Text.Blaze.Html5.Attributes as Html5 +import Data.CaseInsensitive (CI) +import qualified Data.CaseInsensitive as CI + import Control.Monad.RWS hiding ((<>), Foldable(..), mapM_) -import Data.Map (Map) +import Data.Map (Map, (!)) import Colonnade hiding (bool, fromMaybe) import Yesod.Colonnade @@ -29,8 +38,16 @@ import Data.Ratio ((%)) data SortColumn = forall a. PersistField a => SortColumn { getSortColumn :: E.SqlExpr (E.Value a) } + data SortDirection = SortAsc | SortDesc deriving (Eq, Ord, Enum, Show, Read) +instance PathPiece SortDirection where + toPathPiece SortAsc = "asc" + toPathPiece SortDesc = "desc" + fromPathPiece (CI.mk -> t) + | t == "asc" = Just SortAsc + | t == "desc" = Just SortDesc + | otherwise = Nothing sqlSortDirection :: (SortColumn, SortDirection) -> E.SqlExpr E.OrderBy sqlSortDirection (SortColumn e, SortAsc ) = E.asc e @@ -49,7 +66,7 @@ data DBTable = forall a r h i. } data PaginationSettings = PaginationSettings - { psSorting :: [(SortColumn, SortDirection)] + { psSorting :: [(Text, SortDirection)] , psLimit :: Int64 , psPage :: Int64 , psShortcircuit :: Bool @@ -78,16 +95,11 @@ dbTable :: PSValidator -> DBTable -> Handler Widget dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do let sortingOptions = mkOptionList - [ Option t' (c, d) t' - | (t, c) <- mapToList dbtSorting + [ Option t' (t, d) t' + | (t, _) <- mapToList dbtSorting , d <- [SortAsc, SortDesc] - , let t' = t <> "-" <> tshow d + , let t' = t <> "-" <> toPathPiece d ] - sortingField = Field parse (\_ _ _ _ _ -> return ()) UrlEncoded - where - parse optlist _ = case mapM (olReadExternal sortingOptions) optlist of - Nothing -> return $ Left "Error parsing values" - Just res -> return $ Right $ Just res (_, defPS) = runPSValidator Nothing wIdent n | not $ null dbtIdent = dbtIdent <> "-" <> n @@ -97,7 +109,7 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do | otherwise = dbtAttrs psResult <- runInputGetResult $ PaginationSettings - <$> ireq sortingField (wIdent "sorting") + <$> ireq (multiSelectField $ return sortingOptions) (wIdent "sorting") <*> (fromMaybe (psLimit defPS) <$> iopt intField (wIdent "pagesize")) <*> (fromMaybe (psPage defPS) <$> iopt intField (wIdent "page")) <*> ireq checkBoxField (wIdent "table-only") @@ -112,13 +124,14 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do FormSuccess ps -> runPSValidator $ Just ps FormFailure errs -> first (map SomeMessage errs <>) $ runPSValidator Nothing FormMissing -> runPSValidator Nothing + psSorting' = map (first (dbtSorting !)) psSorting sqlQuery' = dbtSQLQuery - <* E.orderBy (map sqlSortDirection psSorting) + <* E.orderBy (map sqlSortDirection psSorting') <* E.limit psLimit <* E.offset (psPage * psLimit) mapM_ (addMessageI "warning") errs - + (rows, [E.Value rowCount]) <- runDB $ (,) <$> E.select sqlQuery' <*> E.select (E.countRows <$ dbtSQLQuery :: E.SqlQuery (E.SqlExpr (E.Value Int64))) bool return (sendResponse <=< tblLayout) psShortcircuit $ do