diff --git a/src/app.rs b/src/app.rs index f563293..5e94820 100644 --- a/src/app.rs +++ b/src/app.rs @@ -156,6 +156,7 @@ impl App { self.databases.update(databases.as_slice()).unwrap(); self.focus = Focus::DabataseList; self.record_table.reset(); + self.tab.reset(); } Ok(()) } @@ -167,7 +168,7 @@ impl App { .pool .as_ref() .unwrap() - .get_records(&database.name, &table.name, 0, None) + .get_records(&database, &table, 0, None) .await?; self.record_table .update(records, headers, database.clone(), table.clone()); @@ -176,7 +177,7 @@ impl App { .pool .as_ref() .unwrap() - .get_columns(&database.name, &table.name) + .get_columns(&database, &table) .await?; self.structure_table .update(records, headers, database.clone(), table.clone()); @@ -193,8 +194,8 @@ impl App { .as_ref() .unwrap() .get_records( - &database.name, - &table.name, + &database, + &table, 0, if self.record_table.filter.input.is_empty() { None @@ -285,8 +286,8 @@ impl App { .as_ref() .unwrap() .get_records( - &database.name.clone(), - &table.name, + &database, + &table, index as u16, if self.record_table.filter.input.is_empty() { None diff --git a/src/components/connections.rs b/src/components/connections.rs index 4d87bb5..f1d9ac3 100644 --- a/src/components/connections.rs +++ b/src/components/connections.rs @@ -20,10 +20,14 @@ pub struct ConnectionsComponent { impl ConnectionsComponent { pub fn new(key_config: KeyConfig, connections: Vec) -> Self { + let mut state = ListState::default(); + if !connections.is_empty() { + state.select(Some(0)); + } Self { connections, key_config, - state: ListState::default(), + state, } } @@ -31,7 +35,7 @@ impl ConnectionsComponent { let i = match self.state.selected() { Some(i) => { if i >= self.connections.len() - 1 { - 0 + self.connections.len() - 1 } else { i + 1 } @@ -45,7 +49,7 @@ impl ConnectionsComponent { let i = match self.state.selected() { Some(i) => { if i == 0 { - self.connections.len() - 1 + 0 } else { i - 1 } diff --git a/src/components/databases.rs b/src/components/databases.rs index 25f72b1..8335527 100644 --- a/src/components/databases.rs +++ b/src/components/databases.rs @@ -396,7 +396,7 @@ mod test { create_time: None, update_time: None, engine: None, - table_schema: None + schema: None }, ), false, @@ -422,7 +422,7 @@ mod test { create_time: None, update_time: None, engine: None, - table_schema: None + schema: None }, ), true, @@ -451,7 +451,7 @@ mod test { create_time: None, update_time: None, engine: None, - table_schema: None + schema: None }, ), false, @@ -477,7 +477,7 @@ mod test { create_time: None, update_time: None, engine: None, - table_schema: None + schema: None }, ), true, diff --git a/src/components/tab.rs b/src/components/tab.rs index 4e7d030..d853bc6 100644 --- a/src/components/tab.rs +++ b/src/components/tab.rs @@ -38,6 +38,10 @@ impl TabComponent { } } + pub fn reset(&mut self) { + self.selected_tab = Tab::Records; + } + fn names(&self) -> Vec { vec![ command::tab_records(&self.key_config).name, diff --git a/src/database/mod.rs b/src/database/mod.rs index e24bbe6..eb59209 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -15,15 +15,15 @@ pub trait Pool { async fn get_tables(&self, database: String) -> anyhow::Result>; async fn get_records( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, page: u16, filter: Option, ) -> anyhow::Result<(Vec, Vec>)>; async fn get_columns( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, ) -> anyhow::Result<(Vec, Vec>)>; async fn close(&self); } diff --git a/src/database/mysql.rs b/src/database/mysql.rs index 291b240..e642cee 100644 --- a/src/database/mysql.rs +++ b/src/database/mysql.rs @@ -47,16 +47,16 @@ impl Pool for MySqlPool { async fn get_records( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, page: u16, filter: Option, ) -> anyhow::Result<(Vec, Vec>)> { let query = if let Some(filter) = filter { format!( "SELECT * FROM `{database}`.`{table}` WHERE {filter} LIMIT {page}, {limit}", - database = database, - table = table, + database = database.name, + table = table.name, filter = filter, page = page, limit = RECORDS_LIMIT_PER_PAGE @@ -64,8 +64,8 @@ impl Pool for MySqlPool { } else { format!( "SELECT * FROM `{}`.`{}` limit {page}, {limit}", - database, - table, + database.name, + table.name, page = page, limit = RECORDS_LIMIT_PER_PAGE ) @@ -90,10 +90,13 @@ impl Pool for MySqlPool { async fn get_columns( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, ) -> anyhow::Result<(Vec, Vec>)> { - let query = format!("SHOW FULL COLUMNS FROM `{}`.`{}`", database, table); + let query = format!( + "SHOW FULL COLUMNS FROM `{}`.`{}`", + database.name, table.name + ); let mut rows = sqlx::query(query.as_str()).fetch(&self.pool); let mut headers = vec![]; let mut records = vec![]; diff --git a/src/database/postgres.rs b/src/database/postgres.rs index 4bf7509..476d4a8 100644 --- a/src/database/postgres.rs +++ b/src/database/postgres.rs @@ -50,7 +50,7 @@ impl Pool for PostgresPool { create_time: None, update_time: None, engine: None, - table_schema: row.get("table_name"), + schema: row.get("table_name"), }) } Ok(tables) @@ -58,16 +58,16 @@ impl Pool for PostgresPool { async fn get_records( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, page: u16, filter: Option, ) -> anyhow::Result<(Vec, Vec>)> { let query = if let Some(filter) = filter { format!( r#"SELECT * FROM "{database}""{table_schema}"."{table}" WHERE {filter} LIMIT {page}, {limit}"#, - database = database, - table = table, + database = database.name, + table = table.name, filter = filter, table_schema = "public", page = page, @@ -76,8 +76,8 @@ impl Pool for PostgresPool { } else { format!( r#"SELECT * FROM "{database}"."{table_schema}"."{table}" limit {limit} offset {page}"#, - database = database, - table = table, + database = database.name, + table = table.name, table_schema = "public", page = page, limit = RECORDS_LIMIT_PER_PAGE @@ -103,13 +103,17 @@ impl Pool for PostgresPool { async fn get_columns( &self, - database: &str, - table: &str, + database: &Database, + table: &Table, ) -> anyhow::Result<(Vec, Vec>)> { + let table_schema = table + .schema + .as_ref() + .map_or("public", |schema| schema.as_str()); let mut rows = sqlx::query( - "SELECT * FROM information_schema.columns WHERE table_catalog = $1 AND table_schema = 'public' AND table_name = $2" + "SELECT * FROM information_schema.columns WHERE table_catalog = $1 AND table_schema = $2 AND table_name = $3" ) - .bind(database).bind(table) + .bind(&database.name).bind(table_schema).bind(&table.name) .fetch(&self.pool); let mut headers = vec![]; let mut records = vec![]; @@ -168,6 +172,20 @@ fn convert_column_value_to_string(row: &PgRow, column: &PgColumn) -> anyhow::Res return Ok(value.map_or("NULL".to_string(), |v| v.to_string())); } } + "BYTEA" => { + if let Ok(value) = row.try_get(column_name) { + let value: Option<&[u8]> = value; + return Ok(value.map_or("NULL".to_string(), |values| { + format!( + "\\x{}", + values + .iter() + .map(|v| format!("{:02x}", v)) + .collect::() + ) + })); + } + } "VARCHAR" | "CHAR" | "ENUM" | "TEXT" | "NAME" => { return Ok(row .try_get(column_name)