Skip to content

Commit

Permalink
feat(pagination): add paginate function to calculate offset, limit, a…
Browse files Browse the repository at this point in the history
…nd total pages in `get_table` handler (#26)

* feat(pagination): add paginate function to calculate offset, limit, and total pages in `get_table` handler

* move more work into the `Pagination` struct

---------

Co-authored-by: Jacob Heider <[email protected]>
  • Loading branch information
Yunnie-pin and jhheider authored Nov 20, 2024
1 parent 4a5f4e9 commit da445c5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 15 deletions.
28 changes: 13 additions & 15 deletions api/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i64>,
limit: Option<i64>,
pub struct PaginationParams {
pub page: Option<i64>,
pub limit: Option<i64>,
}

#[derive(Serialize)]
Expand Down Expand Up @@ -59,29 +59,27 @@ 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 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 pagination = Pagination::new(query, total_count);

match client.query(&data_query, &[&limit, &offset]).await {
let data_query = format!("SELECT * FROM {} LIMIT $1 OFFSET $2", table);
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,
};
Expand Down
27 changes: 27 additions & 0 deletions api/src/utils.rs
Original file line number Diff line number Diff line change
@@ -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<String> {
if let Some(row) = rows.first() {
row.columns()
Expand Down Expand Up @@ -55,3 +58,27 @@ pub fn rows_to_json(rows: &[Row]) -> Vec<Value> {
})
.collect()
}

pub struct Pagination {
pub page: i64,
pub limit: i64,
pub offset: i64,
pub total_pages: i64,
}

impl Pagination {
pub fn new(query: Query<PaginationParams>, 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,
}
}
}

0 comments on commit da445c5

Please sign in to comment.