From bd044c00ef50f4c87c0f93b22c78a3ecc2b2edaf Mon Sep 17 00:00:00 2001 From: Arifin Yunianta <72777947+Yunnie-pin@users.noreply.github.com> Date: Fri, 15 Nov 2024 07:46:00 +0700 Subject: [PATCH 1/2] feat(pagination): add paginate function to calculate offset, limit, and total pages in `get_table` handler --- api/src/handlers.rs | 10 ++++------ api/src/utils.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/src/handlers.rs b/api/src/handlers.rs index fad1928..f9abe0e 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -59,19 +59,17 @@ pub async fn get_table( })); } - let page = query.page.unwrap_or(1).max(1); - let limit = query.limit.unwrap_or(200).clamp(1, 1000); - let offset = (page - 1) * limit; + let page = query.page.unwrap_or(1); + let limit = query.limit.unwrap_or(200); let count_query = format!("SELECT COUNT(*) FROM {}", table); - let data_query = format!("SELECT * FROM {} LIMIT $1 OFFSET $2", table); - match data.pool.get().await { Ok(client) => match client.query_one(&count_query, &[]).await { Ok(count_row) => { let total_count: i64 = count_row.get(0); - let total_pages = (total_count as f64 / limit as f64).ceil() as i64; + let (offset, limit, total_pages) = paginate(page, limit, total_count); + let data_query = format!("SELECT * FROM {} LIMIT $1 OFFSET $2", table); match client.query(&data_query, &[&limit, &offset]).await { Ok(rows) => { let columns = get_column_names(&rows); diff --git a/api/src/utils.rs b/api/src/utils.rs index d2a5cf2..119bd53 100644 --- a/api/src/utils.rs +++ b/api/src/utils.rs @@ -55,3 +55,11 @@ pub fn rows_to_json(rows: &[Row]) -> Vec { }) .collect() } + +pub fn paginate(page: i64, limit: i64, total_count: i64) -> (i64, i64, i64) { + let page = page.max(1); + let limit = limit.clamp(1, 1000); + let offset = (page - 1) * limit; + let total_pages = (total_count as f64 / limit as f64).ceil() as i64; + (offset, limit, total_pages) +} \ No newline at end of file From 3b3835bc0bb73928382866c48e091c23976aee27 Mon Sep 17 00:00:00 2001 From: Jacob Heider Date: Wed, 20 Nov 2024 15:02:06 -0500 Subject: [PATCH 2/2] move more work into the `Pagination` struct --- api/src/handlers.rs | 24 ++++++++++++------------ api/src/utils.rs | 33 ++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/api/src/handlers.rs b/api/src/handlers.rs index f9abe0e..cf64f3a 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -5,12 +5,12 @@ use tokio_postgres::error::SqlState; use uuid::Uuid; use crate::app_state::AppState; -use crate::utils::{get_column_names, rows_to_json}; +use crate::utils::{get_column_names, rows_to_json, Pagination}; #[derive(Deserialize)] -struct PaginationParams { - page: Option, - limit: Option, +pub struct PaginationParams { + pub page: Option, + pub limit: Option, } #[derive(Serialize)] @@ -59,27 +59,27 @@ pub async fn get_table( })); } - let page = query.page.unwrap_or(1); - let limit = query.limit.unwrap_or(200); - let count_query = format!("SELECT COUNT(*) FROM {}", table); match data.pool.get().await { Ok(client) => match client.query_one(&count_query, &[]).await { Ok(count_row) => { let total_count: i64 = count_row.get(0); - let (offset, limit, total_pages) = paginate(page, limit, total_count); + let pagination = Pagination::new(query, total_count); let data_query = format!("SELECT * FROM {} LIMIT $1 OFFSET $2", table); - match client.query(&data_query, &[&limit, &offset]).await { + match client + .query(&data_query, &[&pagination.limit, &pagination.offset]) + .await + { Ok(rows) => { let columns = get_column_names(&rows); let data = rows_to_json(&rows); let response = PaginatedResponse { table, total_count, - page, - limit, - total_pages, + page: pagination.page, + limit: pagination.limit, + total_pages: pagination.total_pages, columns, data, }; diff --git a/api/src/utils.rs b/api/src/utils.rs index 119bd53..2c48ac1 100644 --- a/api/src/utils.rs +++ b/api/src/utils.rs @@ -1,8 +1,11 @@ +use actix_web::web::Query; use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc}; use serde_json::{json, Value}; use tokio_postgres::{types::Type, Row}; use uuid::Uuid; +use crate::handlers::PaginationParams; + pub fn get_column_names(rows: &[Row]) -> Vec { if let Some(row) = rows.first() { row.columns() @@ -56,10 +59,26 @@ pub fn rows_to_json(rows: &[Row]) -> Vec { .collect() } -pub fn paginate(page: i64, limit: i64, total_count: i64) -> (i64, i64, i64) { - let page = page.max(1); - let limit = limit.clamp(1, 1000); - let offset = (page - 1) * limit; - let total_pages = (total_count as f64 / limit as f64).ceil() as i64; - (offset, limit, total_pages) -} \ No newline at end of file +pub struct Pagination { + pub page: i64, + pub limit: i64, + pub offset: i64, + pub total_pages: i64, +} + +impl Pagination { + pub fn new(query: Query, total_count: i64) -> Self { + let limit = query.limit.unwrap_or(200).clamp(1, 1000); + let total_pages = (total_count as f64 / limit as f64).ceil() as i64; + + let page = query.page.unwrap_or(1).clamp(1, total_pages); + + let offset = (page - 1) * limit; + Self { + page, + limit, + offset, + total_pages, + } + } +}