From 79624f8a2390eccc2e4ee1ca1561f84d71d7ad41 Mon Sep 17 00:00:00 2001 From: kyoto7250 <50972773+kyoto7250@users.noreply.github.com> Date: Tue, 18 Jun 2024 00:48:33 +0900 Subject: [PATCH] show total row counts --- src/app.rs | 22 ++++++++++++++++++++++ src/components/properties.rs | 4 ++++ src/components/record_table.rs | 11 +++++++++-- src/components/sql_editor.rs | 4 +++- src/components/table.rs | 5 +++++ src/components/table_status.rs | 10 ++++++++-- src/database/mod.rs | 6 ++++++ src/database/mysql.rs | 24 ++++++++++++++++++++++++ src/database/postgres.rs | 26 ++++++++++++++++++++++++++ src/database/sqlite.rs | 19 +++++++++++++++++++ 10 files changed, 126 insertions(+), 5 deletions(-) diff --git a/src/app.rs b/src/app.rs index 25cd003..1945c62 100644 --- a/src/app.rs +++ b/src/app.rs @@ -188,8 +188,23 @@ impl App { orders, ) .await?; + let total_row_count = self + .pool + .as_ref() + .unwrap() + .get_total_row_count( + &database, + &table, + if self.record_table.filter.input_str().is_empty() { + None + } else { + Some(self.record_table.filter.input_str()) + }, + ) + .await?; self.record_table.update( records, + Some(total_row_count), self.concat_headers(headers, header_icons), database.clone(), table.clone(), @@ -246,8 +261,15 @@ impl App { .unwrap() .get_records(&database, &table, 0, None, None) .await?; + let total_row_count = self + .pool + .as_ref() + .unwrap() + .get_total_row_count(&database, &table, None) + .await?; self.record_table.update( records, + Some(total_row_count), headers, database.clone(), table.clone(), diff --git a/src/components/properties.rs b/src/components/properties.rs index b67907a..7c937e6 100644 --- a/src/components/properties.rs +++ b/src/components/properties.rs @@ -73,6 +73,7 @@ impl PropertiesComponent { .iter() .map(|c| c.columns()) .collect::>>(), + None, columns.first().unwrap().fields(), database.clone(), table.clone(), @@ -87,6 +88,7 @@ impl PropertiesComponent { .iter() .map(|c| c.columns()) .collect::>>(), + None, constraints.first().unwrap().fields(), database.clone(), table.clone(), @@ -101,6 +103,7 @@ impl PropertiesComponent { .iter() .map(|c| c.columns()) .collect::>>(), + None, foreign_keys.first().unwrap().fields(), database.clone(), table.clone(), @@ -115,6 +118,7 @@ impl PropertiesComponent { .iter() .map(|c| c.columns()) .collect::>>(), + None, indexes.first().unwrap().fields(), database.clone(), table.clone(), diff --git a/src/components/record_table.rs b/src/components/record_table.rs index ae8108a..eea3dfb 100644 --- a/src/components/record_table.rs +++ b/src/components/record_table.rs @@ -36,13 +36,20 @@ impl RecordTableComponent { pub fn update( &mut self, rows: Vec>, + total_row_count: Option, headers: Vec, database: Database, table: DTable, hold_cursor_position: bool, ) { - self.table - .update(rows, headers, database, table.clone(), hold_cursor_position); + self.table.update( + rows, + total_row_count, + headers, + database, + table.clone(), + hold_cursor_position, + ); self.filter.table = Some(table); } diff --git a/src/components/sql_editor.rs b/src/components/sql_editor.rs index f2205ea..f156683 100644 --- a/src/components/sql_editor.rs +++ b/src/components/sql_editor.rs @@ -268,7 +268,9 @@ impl Component for SqlEditorComponent { database, table, } => { - self.table.update(rows, headers, database, table, false); + let count = Some(rows.len()); + self.table + .update(rows, count, headers, database, table, false); self.focus = Focus::Table; self.query_result = None; } diff --git a/src/components/table.rs b/src/components/table.rs index 2b3775c..eca28ce 100644 --- a/src/components/table.rs +++ b/src/components/table.rs @@ -100,6 +100,7 @@ impl OrderManager { pub struct TableComponent { pub headers: Vec, pub rows: Vec>, + pub total_row_count: Option, pub eod: bool, pub selected_row: TableState, orders: OrderManager, @@ -117,6 +118,7 @@ impl TableComponent { selected_row: TableState::default(), headers: vec![], rows: vec![], + total_row_count: None, orders: OrderManager::new(), table: None, selected_column: 0, @@ -137,6 +139,7 @@ impl TableComponent { pub fn update( &mut self, rows: Vec>, + total_row_count: Option, headers: Vec, database: Database, table: DTable, @@ -148,6 +151,7 @@ impl TableComponent { } self.headers = headers; self.rows = rows; + self.total_row_count = total_row_count; self.selected_column = if hold_cusor_position { self.selected_column } else { @@ -627,6 +631,7 @@ impl StatefulDrawableComponent for TableComponent { } else { Some(self.rows.len()) }, + self.total_row_count, if self.headers.is_empty() { None } else { diff --git a/src/components/table_status.rs b/src/components/table_status.rs index 7d50f9c..3e1cd8f 100644 --- a/src/components/table_status.rs +++ b/src/components/table_status.rs @@ -14,6 +14,7 @@ use ratatui::{ pub struct TableStatusComponent { column_count: Option, row_count: Option, + total_row_count: Option, table: Option, } @@ -21,6 +22,7 @@ impl Default for TableStatusComponent { fn default() -> Self { Self { row_count: None, + total_row_count: None, column_count: None, table: None, } @@ -30,11 +32,13 @@ impl Default for TableStatusComponent { impl TableStatusComponent { pub fn new( row_count: Option, + total_row_count: Option, column_count: Option, table: Option
, ) -> Self { Self { row_count, + total_row_count, column_count, table, } @@ -45,8 +49,10 @@ impl DrawableComponent for TableStatusComponent { fn draw(&self, f: &mut Frame, area: Rect, focused: bool) -> Result<()> { let status = Paragraph::new(Line::from(vec![ Span::from(format!( - "rows: {}, ", - self.row_count.map_or("-".to_string(), |c| c.to_string()) + "rows: {} / {}, ", + self.row_count.map_or("-".to_string(), |c| c.to_string()), + self.total_row_count + .map_or("-".to_string(), |c| c.to_string()), )), Span::from(format!( "columns: {}, ", diff --git a/src/database/mod.rs b/src/database/mod.rs index a13499c..7e5a986 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -29,6 +29,12 @@ pub trait Pool: Send + Sync { database: &Database, table: &Table, ) -> anyhow::Result>>; + async fn get_total_row_count( + &self, + database: &Database, + table: &Table, + filter: Option, + ) -> anyhow::Result; async fn get_constraints( &self, database: &Database, diff --git a/src/database/mysql.rs b/src/database/mysql.rs index c7fb663..5e21d94 100644 --- a/src/database/mysql.rs +++ b/src/database/mysql.rs @@ -285,6 +285,30 @@ impl Pool for MySqlPool { Ok((headers, records)) } + async fn get_total_row_count( + &self, + database: &Database, + table: &Table, + filter: Option, + ) -> anyhow::Result { + let query = if let Some(filter) = &filter { + format!( + "SELECT COUNT(*) FROM `{database}`.`{table}` WHERE {filter}", + database = database.name, + table = table.name, + filter = filter + ) + } else { + format!( + "SELECT COUNT(*) FROM `{database}`.`{table}`", + database = database.name, + table = table.name, + ) + }; + let res = sqlx::query(query.as_str()).fetch_one(&self.pool).await?; + Ok(res.get::(0) as usize) + } + async fn get_columns( &self, database: &Database, diff --git a/src/database/postgres.rs b/src/database/postgres.rs index 526248c..f7b5f7a 100644 --- a/src/database/postgres.rs +++ b/src/database/postgres.rs @@ -346,6 +346,32 @@ impl Pool for PostgresPool { Ok((headers, records)) } + async fn get_total_row_count( + &self, + database: &Database, + table: &Table, + filter: Option, + ) -> anyhow::Result { + let query = if let Some(filter) = &filter { + format!( + r#"SELECT COUNT(*) FROM "{database}"."{table_schema}"."{table}" WHERE {filter}"#, + database = database.name, + table = table.name, + filter = filter, + table_schema = table.schema.clone().unwrap_or_else(|| "public".to_string()), + ) + } else { + format!( + r#"SELECT COUNT(*) FROM "{database}"."{table_schema}"."{table}"#, + database = database.name, + table = table.name, + table_schema = table.schema.clone().unwrap_or_else(|| "public".to_string()), + ) + }; + let res = sqlx::query(query.as_str()).fetch_one(&self.pool).await?; + Ok(res.get::(0) as usize) + } + async fn get_columns( &self, database: &Database, diff --git a/src/database/sqlite.rs b/src/database/sqlite.rs index 8cf7ab3..73e8650 100644 --- a/src/database/sqlite.rs +++ b/src/database/sqlite.rs @@ -283,6 +283,25 @@ impl Pool for SqlitePool { Ok((headers, records)) } + async fn get_total_row_count( + &self, + _database: &Database, + table: &Table, + filter: Option, + ) -> anyhow::Result { + let query = if let Some(filter) = &filter { + format!( + "SELECT COUNT(*) FROM `{table}` WHERE {filter}", + table = table.name, + filter = filter, + ) + } else { + format!("SELECT COUNT(*) FROM `{table}`", table = table.name,) + }; + let res = sqlx::query(query.as_str()).fetch_one(&self.pool).await?; + Ok(res.get::(0) as usize) + } + async fn get_columns( &self, _database: &Database,