database_tree/
item.rs

1use crate::{Database, Schema, Table};
2
3#[derive(Debug, Clone)]
4pub struct TreeItemInfo {
5    indent: u8,
6    visible: bool,
7}
8
9impl TreeItemInfo {
10    pub const fn new(indent: u8, visible: bool) -> Self {
11        Self { indent, visible }
12    }
13
14    pub const fn is_visible(&self) -> bool {
15        self.visible
16    }
17
18    pub const fn indent(&self) -> u8 {
19        self.indent
20    }
21
22    pub fn unindent(&mut self) {
23        self.indent = self.indent.saturating_sub(1);
24    }
25
26    pub fn set_visible(&mut self, visible: bool) {
27        self.visible = visible;
28    }
29}
30
31/// `DatabaseTreeItem` can be of two kinds
32#[derive(PartialEq, Debug, Clone)]
33pub enum DatabaseTreeItemKind {
34    Database {
35        name: String,
36        collapsed: bool,
37    },
38    Table {
39        database: Database,
40        table: Table,
41    },
42    Schema {
43        database: Database,
44        schema: Schema,
45        collapsed: bool,
46    },
47}
48
49impl DatabaseTreeItemKind {
50    pub const fn is_database(&self) -> bool {
51        matches!(self, Self::Database { .. })
52    }
53
54    pub const fn is_table(&self) -> bool {
55        matches!(self, Self::Table { .. })
56    }
57
58    pub const fn is_schema(&self) -> bool {
59        matches!(self, Self::Schema { .. })
60    }
61
62    pub const fn is_database_collapsed(&self) -> bool {
63        match self {
64            Self::Database { collapsed, .. } => *collapsed,
65            Self::Table { .. } => false,
66            Self::Schema { .. } => false,
67        }
68    }
69
70    pub const fn is_schema_collapsed(&self) -> bool {
71        match self {
72            Self::Database { .. } => false,
73            Self::Table { .. } => false,
74            Self::Schema { collapsed, .. } => *collapsed,
75        }
76    }
77
78    pub fn name(&self) -> String {
79        match self {
80            Self::Database { name, .. } => name.to_string(),
81            Self::Table { table, .. } => table.name.clone(),
82            Self::Schema { schema, .. } => schema.name.clone(),
83        }
84    }
85
86    pub fn database_name(&self) -> Option<String> {
87        match self {
88            Self::Database { .. } => None,
89            Self::Table { database, .. } => Some(database.name.clone()),
90            Self::Schema { database, .. } => Some(database.name.clone()),
91        }
92    }
93
94    pub fn schema_name(&self) -> Option<String> {
95        match self {
96            Self::Database { .. } => None,
97            Self::Table { table, .. } => table.schema.clone(),
98            Self::Schema { .. } => None,
99        }
100    }
101}
102
103/// `DatabaseTreeItem` can be of two kinds: see `DatabaseTreeItem` but shares an info
104#[derive(Debug, Clone)]
105pub struct DatabaseTreeItem {
106    info: TreeItemInfo,
107    kind: DatabaseTreeItemKind,
108}
109
110impl DatabaseTreeItem {
111    pub fn new_table(database: &Database, table: &Table) -> Self {
112        Self {
113            info: TreeItemInfo::new(if table.schema.is_some() { 2 } else { 1 }, false),
114            kind: DatabaseTreeItemKind::Table {
115                database: database.clone(),
116                table: table.clone(),
117            },
118        }
119    }
120
121    pub fn new_schema(database: &Database, schema: &Schema, _collapsed: bool) -> Self {
122        Self {
123            info: TreeItemInfo::new(1, false),
124            kind: DatabaseTreeItemKind::Schema {
125                database: database.clone(),
126                schema: schema.clone(),
127                collapsed: true,
128            },
129        }
130    }
131
132    pub fn new_database(database: &Database, _collapsed: bool) -> Self {
133        Self {
134            info: TreeItemInfo::new(0, true),
135            kind: DatabaseTreeItemKind::Database {
136                name: database.name.to_string(),
137                collapsed: true,
138            },
139        }
140    }
141
142    pub fn set_collapsed(&mut self, collapsed: bool) {
143        if let DatabaseTreeItemKind::Database { name, .. } = self.kind() {
144            self.kind = DatabaseTreeItemKind::Database {
145                name: name.to_string(),
146                collapsed,
147            }
148        }
149    }
150
151    pub const fn info(&self) -> &TreeItemInfo {
152        &self.info
153    }
154
155    pub fn info_mut(&mut self) -> &mut TreeItemInfo {
156        &mut self.info
157    }
158
159    pub const fn kind(&self) -> &DatabaseTreeItemKind {
160        &self.kind
161    }
162
163    pub fn collapse_database(&mut self) {
164        if let DatabaseTreeItemKind::Database { name, .. } = &self.kind {
165            self.kind = DatabaseTreeItemKind::Database {
166                name: name.to_string(),
167                collapsed: true,
168            }
169        }
170    }
171
172    pub fn expand_database(&mut self) {
173        if let DatabaseTreeItemKind::Database { name, .. } = &self.kind {
174            self.kind = DatabaseTreeItemKind::Database {
175                name: name.to_string(),
176                collapsed: false,
177            };
178        }
179    }
180
181    pub fn collapse_schema(&mut self) {
182        if let DatabaseTreeItemKind::Schema {
183            schema, database, ..
184        } = &self.kind
185        {
186            self.kind = DatabaseTreeItemKind::Schema {
187                database: database.clone(),
188                schema: schema.clone(),
189                collapsed: true,
190            }
191        }
192    }
193
194    pub fn expand_schema(&mut self) {
195        if let DatabaseTreeItemKind::Schema {
196            schema, database, ..
197        } = &self.kind
198        {
199            self.kind = DatabaseTreeItemKind::Schema {
200                database: database.clone(),
201                schema: schema.clone(),
202                collapsed: false,
203            };
204        }
205    }
206
207    pub fn show(&mut self) {
208        self.info.visible = true;
209    }
210
211    pub fn hide(&mut self) {
212        self.info.visible = false;
213    }
214
215    pub fn is_match(&self, filter_text: &str) -> bool {
216        match self.kind.clone() {
217            DatabaseTreeItemKind::Database { name, .. } => name.contains(filter_text),
218            DatabaseTreeItemKind::Table { table, .. } => table.name.contains(filter_text),
219            DatabaseTreeItemKind::Schema { schema, .. } => schema.name.contains(filter_text),
220        }
221    }
222
223    pub fn is_database(&self) -> bool {
224        self.kind.is_database()
225    }
226}
227
228impl Eq for DatabaseTreeItem {}
229
230impl PartialEq for DatabaseTreeItem {
231    fn eq(&self, other: &Self) -> bool {
232        if self.kind.is_database() && other.kind().is_database() {
233            return self.kind.name().eq(&other.kind.name());
234        }
235        if !self.kind.is_database() && !other.kind.is_database() {
236            return self.kind.name().eq(&other.kind.name());
237        }
238        false
239    }
240}
241
242impl PartialOrd for DatabaseTreeItem {
243    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
244        self.kind.name().partial_cmp(&other.kind.name())
245    }
246}
247
248impl Ord for DatabaseTreeItem {
249    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
250        self.kind.name().cmp(&other.kind.name())
251    }
252}