From 1e100934eda6ec7ffb1aad767106cd5c514b8179 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, 19 insertions(+), 21 deletions(-) diff --git a/IHP/Pagination/ControllerFunctions.hs b/IHP/Pagination/ControllerFunctions.hs index a1299b164..360fd0d0f 100644 --- a/IHP/Pagination/ControllerFunctions.hs +++ b/IHP/Pagination/ControllerFunctions.hs @@ -15,18 +15,14 @@ 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.Types (Only(Only), Query(Query), (:.)(..)) +import qualified Database.PostgreSQL.Simple.FromRow as PG +import qualified Database.PostgreSQL.Simple.ToRow as PG -- | Paginate a query, with the following default options: -- @@ -173,18 +169,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 + . ( PG.FromRow r + , PG.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,22 +190,23 @@ 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 + . ( PG.FromRow r + , PG.ToRow q , ?context :: ControllerContext , ?modelContext :: ModelContext ) - => Options -> ByteString -> [Action] -> IO ([model], Pagination) -paginatedSqlQueryWithOptions options sql placeholders = do + => Options -> Query -> q -> IO ([r], Pagination) +paginatedSqlQueryWithOptions options (Query sql) placeholders = do count :: Int <- sqlQueryScalar (Query $ "SELECT count(subquery.*) FROM (" <> sql <> ") as subquery") placeholders let pageSize = pageSize' options @@ -219,9 +217,9 @@ paginatedSqlQueryWithOptions options sql placeholders = do , window = windowSize options } - results :: [model] <- sqlQuery + results :: [r] <- sqlQuery (Query $ "SELECT subquery.* FROM (" <> sql <> ") as subquery LIMIT ? OFFSET ?") - (placeholders ++ map toField [pageSize, offset' pageSize page]) + (placeholders :. Only pageSize :. Only (offset' pageSize page)) pure (results, pagination)