From e505b04dc04e4d527a8cf83a9aab9a88d574acef Mon Sep 17 00:00:00 2001 From: candifloss Date: Fri, 24 Apr 2026 16:34:11 +0530 Subject: [PATCH] Pagination --- src/db.rs | 45 +++++++++++++++++++++++++++++++++++++++ src/routes.rs | 50 +++++++++++++++++++++++++++++++++++--------- templates/table.html | 29 +++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 10 deletions(-) diff --git a/src/db.rs b/src/db.rs index a74415e..363a1de 100644 --- a/src/db.rs +++ b/src/db.rs @@ -78,6 +78,51 @@ impl SqliteDb { Ok((column_names, rows)) } + pub fn fetch_table_page( + &self, + table_name: &str, + limit: usize, + offset: usize, + ) -> Result<(Vec, Vec>)> { + let conn = self.lock_conn(); + + let query = format!("SELECT * FROM {table_name} LIMIT {limit} OFFSET {offset}"); + + let mut stmt = conn.prepare(&query)?; + + let column_names = stmt + .column_names() + .iter() + .map(|s| s.to_string()) + .collect::>(); + + let col_count = stmt.column_count(); + + let rows_iter = stmt.query_map([], move |row| { + let mut values = Vec::with_capacity(col_count); + + for i in 0..col_count { + let value: Value = row.get(i)?; + + let cell = match value { + Value::Null => "".to_string(), + Value::Integer(i) => i.to_string(), + Value::Real(f) => f.to_string(), + Value::Text(t) => t, + Value::Blob(b) => format!("", b.len()), + }; + + values.push(cell); + } + + Ok(values) + })?; + + let rows = rows_iter.collect::>>()?; + + Ok((column_names, rows)) + } + /// List all tables in the database. pub fn list_tables(&self) -> Result> { let conn = self.lock_conn(); diff --git a/src/routes.rs b/src/routes.rs index 460d6ff..dcffd7e 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -31,6 +31,12 @@ pub struct TableTemplate { pub schema: Option, pub row_count: Option, pub columns_info: Option>, // (name, type, pk) + + pub page: usize, + pub total_pages: usize, + pub total_rows: i64, + pub start: usize, + pub end: usize, } /// Query parameters for `/` @@ -38,6 +44,7 @@ pub struct TableTemplate { pub struct TableQuery { pub table: Option, pub view: Option, + pub page: Option, } /// GET / @@ -51,47 +58,70 @@ pub async fn index( State(app_state): State, Query(query): Query, ) -> Html { - // Fetch available tables (for dropdown) + // Tables + selection let tables = app_state.db.list_tables().unwrap(); - // Determine selected table let table_name = query .table .unwrap_or_else(|| tables.first().cloned().unwrap_or_default()); - // Determine active view (default = data) let view = query.view.unwrap_or_else(|| "data".to_string()); + // Pagination + let page_size: usize = 20; + + let page = query.page.unwrap_or(1).max(1); + let offset = (page - 1) * page_size; + + // Always needed for pagination + let total_rows = app_state.db.count_rows(&table_name).unwrap(); + + let total_pages = ((total_rows as usize) + page_size - 1) / page_size; + + let start = if total_rows == 0 { 0 } else { offset + 1 }; + // Data view let (columns, rows) = if view == "data" { - app_state.db.fetch_table(&table_name).unwrap() + app_state + .db + .fetch_table_page(&table_name, page_size, offset) + .unwrap() } else { (Vec::new(), Vec::new()) }; + let end = (offset + rows.len()).min(total_rows as usize); + // Structure view - let (schema, row_count, columns_info) = if view == "structure" { + let (schema, columns_info) = if view == "structure" { ( Some(app_state.db.get_table_schema(&table_name).unwrap()), - Some(app_state.db.count_rows(&table_name).unwrap()), Some(app_state.db.get_table_columns(&table_name).unwrap()), ) } else { - (None, None, None) + (None, None) }; - // Build template context + // Template let template = TableTemplate { tables, table_name, view, + columns, rows, + schema, - row_count, + row_count: Some(total_rows), // reuse + columns_info, + + page, + total_pages, + total_rows, + start, + end, }; - // Render HTML response Html(template.render().unwrap()) } diff --git a/templates/table.html b/templates/table.html index d5e2fbc..060a210 100644 --- a/templates/table.html +++ b/templates/table.html @@ -39,6 +39,35 @@ {% if view == "data" %} + +

+ Showing {{ start }}-{{ end }} of {{ total_rows }} + +    + + Page {{ page }} of {{ total_pages }} + +    + + {% if page > 1 %} + < + {% endif %} + + {% if page < total_pages %} + > + {% endif %} +

+ +
+ + + + Page: + + +
+ +