diff --git a/database-tree/src/databasetree.rs b/database-tree/src/databasetree.rs index 5fff542..9443b77 100644 --- a/database-tree/src/databasetree.rs +++ b/database-tree/src/databasetree.rs @@ -82,6 +82,7 @@ impl DatabaseTree { DatabaseTreeItemKind::Table { table, database } => { Some((database.clone(), table.clone())) } + DatabaseTreeItemKind::Schema { .. } => None, } }) } @@ -215,7 +216,8 @@ impl DatabaseTree { .unwrap(); if !up - && self.selected_item().unwrap().kind().is_database() + && (self.selected_item().unwrap().kind().is_database() + || self.selected_item().unwrap().kind().is_schema()) && self.selected_item().unwrap() == item { break; @@ -264,6 +266,11 @@ impl DatabaseTree { return Some(current_index); } + if item.kind().is_schema() && !item.kind().is_schema_collapsed() { + self.items.collapse(current_index, false); + return Some(current_index); + } + self.select_parent(current_index) } @@ -278,6 +285,14 @@ impl DatabaseTree { return self.selection_updown(current_selection, false); } + if item.kind().is_schema() { + if item.kind().is_schema_collapsed() { + self.items.expand(current_selection, false); + return Some(current_selection); + } + return self.selection_updown(current_selection, false); + } + None } @@ -292,8 +307,7 @@ impl DatabaseTree { #[cfg(test)] mod test { - use crate::{Database, DatabaseTree, MoveSelection, Table}; - // use pretty_assertions::assert_eq; + use crate::{Database, DatabaseTree, MoveSelection, Schema, Table}; use std::collections::BTreeSet; impl Table { @@ -303,7 +317,17 @@ mod test { create_time: None, update_time: None, engine: None, - table_schema: None, + schema: None, + } + } + + fn new_with_schema(name: String, schema: String) -> Self { + Table { + name, + create_time: None, + update_time: None, + engine: None, + schema: Some(schema), } } } @@ -312,11 +336,31 @@ mod test { fn test_selection() { let items = vec![Database::new( "a".to_string(), - vec![Table::new("b".to_string())], + vec![Table::new("b".to_string()).into()], + )]; + + // a + // b + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + + assert!(tree.move_selection(MoveSelection::Right)); + assert_eq!(tree.selection, Some(0)); + assert!(tree.move_selection(MoveSelection::Down)); + assert_eq!(tree.selection, Some(1)); + + let items = vec![Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new("c".to_string()).into()], + } + .into()], )]; // a // b + // c let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); @@ -324,6 +368,10 @@ mod test { assert_eq!(tree.selection, Some(0)); assert!(tree.move_selection(MoveSelection::Down)); assert_eq!(tree.selection, Some(1)); + assert!(tree.move_selection(MoveSelection::Right)); + assert_eq!(tree.selection, Some(1)); + assert!(tree.move_selection(MoveSelection::Down)); + assert_eq!(tree.selection, Some(2)); } #[test] @@ -331,9 +379,12 @@ mod test { let items = vec![ Database::new( "a".to_string(), - vec![Table::new("b".to_string()), Table::new("c".to_string())], + vec![ + Table::new("b".to_string()).into(), + Table::new("c".to_string()).into(), + ], ), - Database::new("d".to_string(), vec![Table::new("e".to_string())]), + Database::new("d".to_string(), vec![Table::new("e".to_string()).into()]), ]; // a @@ -343,8 +394,38 @@ mod test { // e let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + tree.selection = Some(1); - tree.items.collapse(0, false); + assert!(tree.move_selection(MoveSelection::Down)); + assert_eq!(tree.selection, Some(3)); + + let items = vec![ + Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new("c".to_string()).into()], + } + .into()], + ), + Database::new( + "d".to_string(), + vec![Schema { + name: "e".to_string(), + tables: vec![Table::new("f".to_string()).into()], + } + .into()], + ), + ]; + + // a + // b + // c + // d + // e + // f + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); tree.selection = Some(1); assert!(tree.move_selection(MoveSelection::Down)); @@ -355,7 +436,10 @@ mod test { fn test_selection_left_collapse() { let items = vec![Database::new( "a".to_string(), - vec![Table::new("b".to_string()), Table::new("c".to_string())], + vec![ + Table::new("b".to_string()).into(), + Table::new("c".to_string()).into(), + ], )]; // a @@ -371,13 +455,52 @@ mod test { assert!(tree.items.tree_items[0].kind().is_database_collapsed()); assert!(!tree.items.tree_items[1].info().is_visible()); assert!(!tree.items.tree_items[2].info().is_visible()); + + let items = vec![ + Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new("c".to_string()).into()], + } + .into()], + ), + Database::new( + "d".to_string(), + vec![Schema { + name: "e".to_string(), + tables: vec![Table::new("f".to_string()).into()], + } + .into()], + ), + ]; + + // a + // b + // c + // d + // e + // f + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + tree.selection = Some(0); + tree.items.expand(0, false); + + assert!(tree.move_selection(MoveSelection::Left)); + assert_eq!(tree.selection, Some(0)); + assert!(tree.items.tree_items[0].kind().is_database_collapsed()); + assert!(!tree.items.tree_items[1].info().is_visible()); + assert!(!tree.items.tree_items[2].info().is_visible()); } #[test] fn test_selection_left_parent() { let items = vec![Database::new( "a".to_string(), - vec![Table::new("b".to_string()), Table::new("c".to_string())], + vec![ + Table::new("b".to_string()).into(), + Table::new("c".to_string()).into(), + ], )]; // a @@ -390,13 +513,43 @@ mod test { assert!(tree.move_selection(MoveSelection::Left)); assert_eq!(tree.selection, Some(0)); + + let items = vec![Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()], + } + .into()], + )]; + + // a + // b + // c + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + + tree.selection = Some(2); + tree.items.expand(0, false); + tree.items.expand(1, false); + assert!(tree.move_selection(MoveSelection::Left)); + assert_eq!(tree.selection, Some(1)); + + assert!(tree.move_selection(MoveSelection::Left)); + assert_eq!(tree.selection, Some(1)); + + assert!(tree.move_selection(MoveSelection::Left)); + assert_eq!(tree.selection, Some(0)); } #[test] fn test_selection_right_expand() { let items = vec![Database::new( "a".to_string(), - vec![Table::new("b".to_string()), Table::new("c".to_string())], + vec![ + Table::new("b".to_string()).into(), + Table::new("c".to_string()).into(), + ], )]; // a @@ -404,7 +557,29 @@ mod test { // c let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + tree.selection = Some(0); + assert!(tree.move_selection(MoveSelection::Right)); + assert_eq!(tree.selection, Some(0)); + assert!(!tree.items.tree_items[0].kind().is_database_collapsed()); + + assert!(tree.move_selection(MoveSelection::Right)); + assert_eq!(tree.selection, Some(1)); + + let items = vec![Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()], + } + .into()], + )]; + + // a + // b + // c + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); tree.selection = Some(0); assert!(tree.move_selection(MoveSelection::Right)); @@ -413,6 +588,10 @@ mod test { assert!(tree.move_selection(MoveSelection::Right)); assert_eq!(tree.selection, Some(1)); + + assert!(tree.move_selection(MoveSelection::Right)); + assert_eq!(tree.selection, Some(1)); + assert!(!tree.items.tree_items[0].kind().is_schema_collapsed()); } #[test] @@ -420,9 +599,12 @@ mod test { let items = vec![ Database::new( "a".to_string(), - vec![Table::new("b".to_string()), Table::new("c".to_string())], + vec![ + Table::new("b".to_string()).into(), + Table::new("c".to_string()).into(), + ], ), - Database::new("d".to_string(), vec![Table::new("e".to_string())]), + Database::new("d".to_string(), vec![Table::new("e".to_string()).into()]), ]; // a @@ -438,9 +620,50 @@ mod test { tree.selection = Some(0); assert!(tree.move_selection(MoveSelection::Left)); assert!(tree.move_selection(MoveSelection::Down)); + assert_eq!(tree.selection, Some(3)); let s = tree.visual_selection().unwrap(); assert_eq!(s.count, 3); assert_eq!(s.index, 1); + + let items = vec![ + Database::new( + "a".to_string(), + vec![Schema { + name: "b".to_string(), + tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()], + } + .into()], + ), + Database::new( + "d".to_string(), + vec![Schema { + name: "e".to_string(), + tables: vec![Table::new_with_schema("f".to_string(), "d".to_string()).into()], + } + .into()], + ), + ]; + + // a + // b + // c + // d + // e + // f + + let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap(); + tree.items.expand(0, false); + tree.items.expand(1, false); + tree.items.expand(3, false); + tree.selection = Some(0); + + assert!(tree.move_selection(MoveSelection::Left)); + assert!(tree.move_selection(MoveSelection::Down)); + assert_eq!(tree.selection, Some(3)); + let s = tree.visual_selection().unwrap(); + + assert_eq!(s.count, 4); + assert_eq!(s.index, 1); } } diff --git a/database-tree/src/databasetreeitems.rs b/database-tree/src/databasetreeitems.rs index feeed28..c455526 100644 --- a/database-tree/src/databasetreeitems.rs +++ b/database-tree/src/databasetreeitems.rs @@ -1,6 +1,6 @@ -use crate::Database; use crate::{error::Result, treeitems_iter::TreeItemsIterator}; use crate::{item::DatabaseTreeItemKind, DatabaseTreeItem}; +use crate::{Child, Database}; use std::{ collections::{BTreeSet, HashMap}, usize, @@ -51,8 +51,16 @@ impl DatabaseTreeItems { { Self::push_databases(e, &mut items, &mut items_added, collapsed)?; } - for table in &e.tables { - items.push(DatabaseTreeItem::new_table(e, table)); + for child in &e.children { + match child { + Child::Table(table) => items.push(DatabaseTreeItem::new_table(e, table)), + Child::Schema(schema) => { + items.push(DatabaseTreeItem::new_schema(e, schema, true)); + for table in &schema.tables { + items.push(DatabaseTreeItem::new_table(e, table)) + } + } + } } } @@ -115,13 +123,37 @@ impl DatabaseTreeItems { } } } + + if self.tree_items[index].kind().is_schema() { + self.tree_items[index].collapse_schema(); + + let name = self.tree_items[index].kind().name(); + + for i in index + 1..self.tree_items.len() { + let item = &mut self.tree_items[i]; + + if recursive && item.kind().is_schema() { + item.collapse_schema(); + } + + if let Some(schema) = item.kind().schema_name() { + if schema == name { + item.hide(); + } + } else { + return; + } + } + } } pub fn expand(&mut self, index: usize, recursive: bool) { if self.tree_items[index].kind().is_database() { self.tree_items[index].expand_database(); + let tree_item = self.tree_items[index].clone(); let name = self.tree_items[index].kind().name(); + let kind = tree_item.kind(); if recursive { for i in index + 1..self.tree_items.len() { @@ -139,22 +171,69 @@ impl DatabaseTreeItems { } } - self.update_visibility(&Some(name), index + 1, false); + self.update_visibility(kind, index + 1); + } + + if self.tree_items[index].kind().is_schema() { + self.tree_items[index].expand_schema(); + + let tree_item = self.tree_items[index].clone(); + let name = self.tree_items[index].kind().name(); + let kind = tree_item.kind(); + + if recursive { + for i in index + 1..self.tree_items.len() { + let item = &mut self.tree_items[i]; + + if let Some(schema) = item.kind().schema_name() { + if *schema != name { + break; + } + } + + if item.kind().is_schema() && item.kind().is_schema_collapsed() { + item.expand_schema(); + } + } + } + + self.update_visibility(kind, index + 1); } } - fn update_visibility(&mut self, prefix: &Option, start_idx: usize, set_defaults: bool) { - let mut inner_collapsed: Option = None; + fn update_visibility(&mut self, prefix: &DatabaseTreeItemKind, start_idx: usize) { + let mut inner_collapsed: Option = None; for i in start_idx..self.tree_items.len() { if let Some(ref collapsed_item) = inner_collapsed { - if let Some(db) = self.tree_items[i].kind().database_name().clone() { - if db == *collapsed_item { - if set_defaults { - self.tree_items[i].info_mut().set_visible(false); + match collapsed_item { + DatabaseTreeItemKind::Database { name, .. } => { + if let DatabaseTreeItemKind::Schema { database, .. } = + self.tree_items[i].kind().clone() + { + if database.name == *name { + continue; + } + } + if let DatabaseTreeItemKind::Table { database, .. } = + self.tree_items[i].kind().clone() + { + if database.name == *name { + continue; + } } - continue; } + DatabaseTreeItemKind::Schema { schema, .. } => { + if let DatabaseTreeItemKind::Table { table, .. } = + self.tree_items[i].kind().clone() + { + if matches!(table.schema, Some(table_schema) if schema.name == table_schema) + { + continue; + } + } + } + _ => (), } inner_collapsed = None; } @@ -162,20 +241,35 @@ impl DatabaseTreeItems { let item_kind = self.tree_items[i].kind().clone(); if matches!(item_kind, DatabaseTreeItemKind::Database{ collapsed, .. } if collapsed) { - inner_collapsed = item_kind.database_name().clone(); + inner_collapsed = Some(item_kind.clone()); + } else if matches!(item_kind, DatabaseTreeItemKind::Schema{ collapsed, .. } if collapsed) + { + inner_collapsed = Some(item_kind.clone()); } - if let Some(db) = item_kind.database_name() { - if prefix.as_ref().map_or(true, |prefix| *prefix == *db) { - self.tree_items[i].info_mut().set_visible(true); + match prefix { + DatabaseTreeItemKind::Database { name, .. } => { + if let DatabaseTreeItemKind::Schema { database, .. } = item_kind.clone() { + if *name == database.name { + self.tree_items[i].info_mut().set_visible(true); + } + } + + if let DatabaseTreeItemKind::Table { database, .. } = item_kind { + if *name == database.name { + self.tree_items[i].info_mut().set_visible(true); + } + } } - } else { - // if we do not set defaults we can early out - if set_defaults { - self.tree_items[i].info_mut().set_visible(false); - } else { - return; + DatabaseTreeItemKind::Schema { schema, .. } => { + if let DatabaseTreeItemKind::Table { table, .. } = item_kind { + if matches!(table.schema, Some(table_schema) if schema.name == table_schema) + { + self.tree_items[i].info_mut().set_visible(true); + } + } } + _ => (), } } } diff --git a/database-tree/src/item.rs b/database-tree/src/item.rs index aa8aa37..b1f600d 100644 --- a/database-tree/src/item.rs +++ b/database-tree/src/item.rs @@ -1,4 +1,4 @@ -use crate::{Database, Table}; +use crate::{Database, Schema, Table}; #[derive(Debug, Clone)] pub struct TreeItemInfo { @@ -31,8 +31,19 @@ impl TreeItemInfo { /// `DatabaseTreeItem` can be of two kinds #[derive(PartialEq, Debug, Clone)] pub enum DatabaseTreeItemKind { - Database { name: String, collapsed: bool }, - Table { database: Database, table: Table }, + Database { + name: String, + collapsed: bool, + }, + Table { + database: Database, + table: Table, + }, + Schema { + database: Database, + schema: Schema, + collapsed: bool, + }, } impl DatabaseTreeItemKind { @@ -44,10 +55,23 @@ impl DatabaseTreeItemKind { matches!(self, Self::Table { .. }) } + pub const fn is_schema(&self) -> bool { + matches!(self, Self::Schema { .. }) + } + pub const fn is_database_collapsed(&self) -> bool { match self { Self::Database { collapsed, .. } => *collapsed, Self::Table { .. } => false, + Self::Schema { .. } => false, + } + } + + pub const fn is_schema_collapsed(&self) -> bool { + match self { + Self::Database { .. } => false, + Self::Table { .. } => false, + Self::Schema { collapsed, .. } => *collapsed, } } @@ -55,6 +79,7 @@ impl DatabaseTreeItemKind { match self { Self::Database { name, .. } => name.to_string(), Self::Table { table, .. } => table.name.clone(), + Self::Schema { schema, .. } => schema.name.clone(), } } @@ -62,6 +87,15 @@ impl DatabaseTreeItemKind { match self { Self::Database { .. } => None, Self::Table { database, .. } => Some(database.name.clone()), + Self::Schema { database, .. } => Some(database.name.clone()), + } + } + + pub fn schema_name(&self) -> Option { + match self { + Self::Database { .. } => None, + Self::Table { table, .. } => table.schema.clone(), + Self::Schema { .. } => None, } } } @@ -76,7 +110,7 @@ pub struct DatabaseTreeItem { impl DatabaseTreeItem { pub fn new_table(database: &Database, table: &Table) -> Self { Self { - info: TreeItemInfo::new(1, false), + info: TreeItemInfo::new(if table.schema.is_some() { 2 } else { 1 }, false), kind: DatabaseTreeItemKind::Table { database: database.clone(), table: table.clone(), @@ -84,6 +118,17 @@ impl DatabaseTreeItem { } } + pub fn new_schema(database: &Database, schema: &Schema, _collapsed: bool) -> Self { + Self { + info: TreeItemInfo::new(1, false), + kind: DatabaseTreeItemKind::Schema { + database: database.clone(), + schema: schema.clone(), + collapsed: true, + }, + } + } + pub fn new_database(database: &Database, _collapsed: bool) -> Self { Self { info: TreeItemInfo::new(0, true), @@ -133,6 +178,32 @@ impl DatabaseTreeItem { } } + pub fn collapse_schema(&mut self) { + if let DatabaseTreeItemKind::Schema { + schema, database, .. + } = &self.kind + { + self.kind = DatabaseTreeItemKind::Schema { + database: database.clone(), + schema: schema.clone(), + collapsed: true, + } + } + } + + pub fn expand_schema(&mut self) { + if let DatabaseTreeItemKind::Schema { + schema, database, .. + } = &self.kind + { + self.kind = DatabaseTreeItemKind::Schema { + database: database.clone(), + schema: schema.clone(), + collapsed: false, + }; + } + } + pub fn show(&mut self) { self.info.visible = true; } @@ -145,6 +216,7 @@ impl DatabaseTreeItem { match self.kind.clone() { DatabaseTreeItemKind::Database { name, .. } => name.contains(filter_text), DatabaseTreeItemKind::Table { table, .. } => table.name.contains(filter_text), + DatabaseTreeItemKind::Schema { schema, .. } => schema.name.contains(filter_text), } } diff --git a/database-tree/src/lib.rs b/database-tree/src/lib.rs index bb0a99d..3b9d0b4 100644 --- a/database-tree/src/lib.rs +++ b/database-tree/src/lib.rs @@ -14,18 +14,42 @@ pub use crate::{ #[derive(Clone, PartialEq, Debug)] pub struct Database { pub name: String, - pub tables: Vec, + pub children: Vec, +} + +#[derive(Clone, PartialEq, Debug)] +pub enum Child { + Table(Table), + Schema(Schema), +} + +impl From
for Child { + fn from(t: Table) -> Self { + Child::Table(t) + } +} + +impl From for Child { + fn from(s: Schema) -> Self { + Child::Schema(s) + } } impl Database { - pub fn new(database: String, tables: Vec
) -> Self { + pub fn new(database: String, children: Vec) -> Self { Self { name: database, - tables, + children, } } } +#[derive(Clone, PartialEq, Debug)] +pub struct Schema { + pub name: String, + pub tables: Vec
, +} + #[derive(sqlx::FromRow, Debug, Clone, PartialEq)] pub struct Table { #[sqlx(rename = "Name")] @@ -37,5 +61,5 @@ pub struct Table { #[sqlx(rename = "Engine")] pub engine: Option, #[sqlx(default)] - pub table_schema: Option, + pub schema: Option, } diff --git a/src/components/databases.rs b/src/components/databases.rs index 8335527..a11cf3e 100644 --- a/src/components/databases.rs +++ b/src/components/databases.rs @@ -94,8 +94,8 @@ impl DatabasesComponent { format!("{:w$}", " ", w = (indent as usize) * 2) }; - let arrow = if item.kind().is_database() { - if item.kind().is_database_collapsed() { + let arrow = if item.kind().is_database() || item.kind().is_schema() { + if item.kind().is_database_collapsed() || item.kind().is_schema_collapsed() { FOLDER_ICON_COLLAPSED } else { FOLDER_ICON_EXPANDED @@ -346,7 +346,7 @@ mod test { DatabaseTreeItem::new_database( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, false, ), @@ -366,7 +366,7 @@ mod test { DatabaseTreeItem::new_database( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, false, ), @@ -389,7 +389,7 @@ mod test { DatabaseTreeItem::new_table( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, &Table { name: "bar".to_string(), @@ -415,7 +415,7 @@ mod test { DatabaseTreeItem::new_table( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, &Table { name: "bar".to_string(), @@ -444,7 +444,7 @@ mod test { DatabaseTreeItem::new_table( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, &Table { name: "barbaz".to_string(), @@ -470,7 +470,7 @@ mod test { DatabaseTreeItem::new_table( &Database { name: "foo".to_string(), - tables: Vec::new(), + children: Vec::new(), }, &Table { name: "barbaz".to_string(), diff --git a/src/database/mod.rs b/src/database/mod.rs index eb59209..c3e2572 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -5,14 +5,14 @@ pub use mysql::MySqlPool; pub use postgres::PostgresPool; use async_trait::async_trait; -use database_tree::{Database, Table}; +use database_tree::{Child, Database, Table}; pub const RECORDS_LIMIT_PER_PAGE: u8 = 200; #[async_trait] pub trait Pool { async fn get_databases(&self) -> anyhow::Result>; - async fn get_tables(&self, database: String) -> anyhow::Result>; + async fn get_tables(&self, database: String) -> anyhow::Result>; async fn get_records( &self, database: &Database, diff --git a/src/database/mysql.rs b/src/database/mysql.rs index e642cee..c8a0e28 100644 --- a/src/database/mysql.rs +++ b/src/database/mysql.rs @@ -1,7 +1,7 @@ use super::{Pool, RECORDS_LIMIT_PER_PAGE}; use async_trait::async_trait; use chrono::NaiveDate; -use database_tree::{Database, Table}; +use database_tree::{Child, Database, Table}; use futures::TryStreamExt; use sqlx::mysql::{MySqlColumn, MySqlPool as MPool, MySqlRow}; use sqlx::{Column as _, Row as _, TypeInfo as _}; @@ -31,18 +31,22 @@ impl Pool for MySqlPool { for db in databases { list.push(Database::new( db.clone(), - get_tables(db.clone(), &self.pool).await?, + get_tables(db.clone(), &self.pool) + .await? + .into_iter() + .map(|table| table.into()) + .collect(), )) } Ok(list) } - async fn get_tables(&self, database: String) -> anyhow::Result> { + async fn get_tables(&self, database: String) -> anyhow::Result> { let tables = sqlx::query_as::<_, Table>(format!("SHOW TABLE STATUS FROM `{}`", database).as_str()) .fetch_all(&self.pool) .await?; - Ok(tables) + Ok(tables.into_iter().map(|table| table.into()).collect()) } async fn get_records( diff --git a/src/database/postgres.rs b/src/database/postgres.rs index 476d4a8..0e2e0a0 100644 --- a/src/database/postgres.rs +++ b/src/database/postgres.rs @@ -1,8 +1,9 @@ use super::{Pool, RECORDS_LIMIT_PER_PAGE}; use async_trait::async_trait; use chrono::NaiveDate; -use database_tree::{Database, Table}; +use database_tree::{Child, Database, Schema, Table}; use futures::TryStreamExt; +use itertools::Itertools; use sqlx::postgres::{PgColumn, PgPool, PgRow}; use sqlx::{Column as _, Row as _, TypeInfo as _}; @@ -31,13 +32,28 @@ impl Pool for PostgresPool { for db in databases { list.push(Database::new( db.clone(), - get_tables(db.clone(), &self.pool).await?, + vec![Schema { + name: "schema".to_string(), + tables: vec![Table { + name: "table".to_string(), + create_time: None, + update_time: None, + engine: None, + schema: Some("schema".to_string()), + }], + } + .into()], + // get_tables(db.clone(), &self.pool) + // .await? + // .into_iter() + // .map(|table| table.into()) + // .collect(), )) } Ok(list) } - async fn get_tables(&self, database: String) -> anyhow::Result> { + async fn get_tables(&self, database: String) -> anyhow::Result> { let mut rows = sqlx::query( "SELECT * FROM information_schema.tables WHERE table_schema='public' and table_catalog = $1", ) @@ -50,10 +66,25 @@ impl Pool for PostgresPool { create_time: None, update_time: None, engine: None, - schema: row.get("table_name"), + schema: row.get("table_schema"), }) } - Ok(tables) + let mut schemas = vec![]; + for (key, group) in &tables.iter().group_by(|t| { + t.schema + .as_ref() + .map(|schema| schema.to_string()) + .unwrap_or("".to_string()) + }) { + schemas.push( + Schema { + name: key, + tables: group.map(|g| g.clone()).collect(), + } + .into(), + ) + } + Ok(schemas) } async fn get_records( @@ -137,14 +168,6 @@ impl Pool for PostgresPool { } } -pub async fn get_tables(database: String, pool: &PgPool) -> anyhow::Result> { - let tables = - sqlx::query_as::<_, Table>(format!("SHOW TABLE STATUS FROM `{}`", database).as_str()) - .fetch_all(pool) - .await?; - Ok(tables) -} - fn convert_column_value_to_string(row: &PgRow, column: &PgColumn) -> anyhow::Result { let column_name = column.name(); match column.type_info().clone().name() {