From 6d30b0010b33d6726b50ff3ea438bd802967ff01 Mon Sep 17 00:00:00 2001 From: Varun Rajput Date: Sun, 22 Dec 2024 02:21:03 +0530 Subject: [PATCH] Refactor pagination SQL queries to use generic parameters Change type signatures to use generic `q` type with `ToRow` constraint instead of `[Action]` --- IHP/Pagination/ControllerFunctions.hs | 40 ++++++++++++--------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/IHP/Pagination/ControllerFunctions.hs b/IHP/Pagination/ControllerFunctions.hs index a1299b164..22efcf57f 100644 --- a/IHP/Pagination/ControllerFunctions.hs +++ b/IHP/Pagination/ControllerFunctions.hs @@ -15,18 +15,12 @@ module IHP.Pagination.ControllerFunctions import IHP.Prelude import IHP.Controller.Context import IHP.Controller.Param ( paramOrDefault, paramOrNothing ) - -import IHP.Pagination.Types - ( Options(..), Pagination(..) ) - -import IHP.QueryBuilder - ( HasQueryBuilder, filterWhereILike, limit, offset ) +import IHP.Pagination.Types ( Options(..), Pagination(..) ) +import IHP.QueryBuilder ( HasQueryBuilder, filterWhereILike, limit, offset ) import IHP.Fetch (fetchCount) - import IHP.ModelSupport (GetModelByTableName, sqlQuery, sqlQueryScalar, Table) -import Database.PostgreSQL.Simple.ToField (toField, Action) -import Database.PostgreSQL.Simple.Types (Query(Query)) +import Database.PostgreSQL.Simple (FromRow, ToRow, Query(..), Only(Only), (:.)(..)) -- | Paginate a query, with the following default options: -- @@ -173,18 +167,19 @@ defaultPaginationOptions = -- -- __Example:__ -- --- > (users, pagination) <- paginatedSqlQuery @User "SELECT id, firstname, lastname FROM users" [] +-- > (users, pagination) <- paginatedSqlQuery "SELECT id, firstname, lastname FROM users" () -- -- Take a look at "IHP.QueryBuilder" for a typesafe approach on building simple queries. -- -- *AutoRefresh:* When using 'paginatedSqlQuery' with AutoRefresh, you need to use 'trackTableRead' to let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query. paginatedSqlQuery - :: forall model - . ( FromRow model + :: forall r q + . ( FromRow r + , ToRow q , ?context :: ControllerContext , ?modelContext :: ModelContext ) - => ByteString -> [Action] -> IO ([model], Pagination) + => Query -> q -> IO ([r], Pagination) paginatedSqlQuery = paginatedSqlQueryWithOptions defaultPaginationOptions -- | Runs a raw sql query and adds pagination to it. @@ -193,23 +188,24 @@ paginatedSqlQuery = paginatedSqlQueryWithOptions defaultPaginationOptions -- -- __Example:__ -- --- > (users, pagination) <- paginatedSqlQueryWithOptions @User +-- > (users, pagination) <- paginatedSqlQueryWithOptions -- > (defaultPaginationOptions |> set #maxItems 10) -- > "SELECT id, firstname, lastname FROM users" --- > [] +-- > () -- -- Take a look at "IHP.QueryBuilder" for a typesafe approach on building simple queries. -- -- *AutoRefresh:* When using 'paginatedSqlQuery' with AutoRefresh, you need to use 'trackTableRead' to let AutoRefresh know that you have accessed a certain table. Otherwise AutoRefresh will not watch table of your custom sql query. paginatedSqlQueryWithOptions - :: forall model - . ( FromRow model + :: forall r q + . ( FromRow r + , ToRow q , ?context :: ControllerContext , ?modelContext :: ModelContext ) - => Options -> ByteString -> [Action] -> IO ([model], Pagination) + => Options -> Query -> q -> IO ([r], Pagination) paginatedSqlQueryWithOptions options sql placeholders = do - count :: Int <- sqlQueryScalar (Query $ "SELECT count(subquery.*) FROM (" <> sql <> ") as subquery") placeholders + count :: Int <- sqlQueryScalar ("SELECT count(subquery.*) FROM (" <> sql <> ") as subquery") placeholders let pageSize = pageSize' options pagination = Pagination @@ -219,9 +215,9 @@ paginatedSqlQueryWithOptions options sql placeholders = do , window = windowSize options } - results :: [model] <- sqlQuery - (Query $ "SELECT subquery.* FROM (" <> sql <> ") as subquery LIMIT ? OFFSET ?") - (placeholders ++ map toField [pageSize, offset' pageSize page]) + results :: [r] <- sqlQuery + ("SELECT subquery.* FROM (" <> sql <> ") as subquery LIMIT ? OFFSET ?") + (placeholders :. Only pageSize :. Only (offset' pageSize page)) pure (results, pagination)