database_tree/
databasetreeitems.rs

1use crate::{error::Result, treeitems_iter::TreeItemsIterator};
2use crate::{item::DatabaseTreeItemKind, DatabaseTreeItem};
3use crate::{Child, Database};
4use std::{
5    collections::{BTreeSet, HashMap},
6    usize,
7};
8
9#[derive(Default)]
10pub struct DatabaseTreeItems {
11    pub tree_items: Vec<DatabaseTreeItem>,
12}
13
14impl DatabaseTreeItems {
15    ///
16    pub fn new(list: &[Database], collapsed: &BTreeSet<&String>) -> Result<Self> {
17        Ok(Self {
18            tree_items: Self::create_items(list, collapsed)?,
19        })
20    }
21
22    pub fn filter(&self, filter_text: String) -> Self {
23        Self {
24            tree_items: self
25                .tree_items
26                .iter()
27                .filter(|item| {
28                    item.is_database() || item.kind().is_schema() || item.is_match(&filter_text)
29                })
30                .map(|item| {
31                    let mut item = item.clone();
32                    if item.is_database() {
33                        item.set_collapsed(false);
34                        item
35                    } else {
36                        let mut item = item;
37                        item.show();
38                        item
39                    }
40                })
41                .collect::<Vec<DatabaseTreeItem>>(),
42        }
43    }
44
45    fn create_items(
46        list: &[Database],
47        collapsed: &BTreeSet<&String>,
48    ) -> Result<Vec<DatabaseTreeItem>> {
49        let mut items = Vec::with_capacity(list.len());
50        let mut items_added: HashMap<String, usize> = HashMap::with_capacity(list.len());
51
52        for e in list {
53            {
54                Self::push_databases(e, &mut items, &mut items_added, collapsed)?;
55            }
56            for child in &e.children {
57                match child {
58                    Child::Table(table) => items.push(DatabaseTreeItem::new_table(e, table)),
59                    Child::Schema(schema) => {
60                        items.push(DatabaseTreeItem::new_schema(e, schema, true));
61                        for table in &schema.tables {
62                            items.push(DatabaseTreeItem::new_table(e, table))
63                        }
64                    }
65                }
66            }
67        }
68
69        Ok(items)
70    }
71
72    /// how many individual items are in the list
73    pub fn len(&self) -> usize {
74        self.tree_items.len()
75    }
76
77    /// iterates visible elements
78    pub const fn iterate(&self, start: usize, max_amount: usize) -> TreeItemsIterator<'_> {
79        TreeItemsIterator::new(self, start, max_amount)
80    }
81
82    fn push_databases<'a>(
83        database: &'a Database,
84        nodes: &mut Vec<DatabaseTreeItem>,
85        items_added: &mut HashMap<String, usize>,
86        collapsed: &BTreeSet<&String>,
87    ) -> Result<()> {
88        let c = database.name.clone();
89        if !items_added.contains_key(&c) {
90            // add node and set count to have no children
91            items_added.insert(c.clone(), 0);
92
93            // increase the number of children in the parent node count
94            *items_added.entry(database.name.clone()).or_insert(0) += 1;
95
96            let is_collapsed = collapsed.contains(&c);
97            nodes.push(DatabaseTreeItem::new_database(database, is_collapsed));
98        }
99
100        // increase child count in parent node (the above ancenstor ignores the leaf component)
101        *items_added.entry(database.name.clone()).or_insert(0) += 1;
102
103        Ok(())
104    }
105
106    pub fn collapse(&mut self, index: usize, recursive: bool) {
107        if self.tree_items[index].kind().is_database() {
108            self.tree_items[index].collapse_database();
109
110            let name = self.tree_items[index].kind().name();
111
112            for i in index + 1..self.tree_items.len() {
113                let item = &mut self.tree_items[i];
114
115                if recursive && item.kind().is_database() {
116                    item.collapse_database();
117                }
118
119                if let Some(db) = item.kind().database_name() {
120                    if db == name {
121                        item.hide();
122                    }
123                } else {
124                    return;
125                }
126            }
127        }
128
129        if self.tree_items[index].kind().is_schema() {
130            self.tree_items[index].collapse_schema();
131
132            let name = self.tree_items[index].kind().name();
133
134            for i in index + 1..self.tree_items.len() {
135                let item = &mut self.tree_items[i];
136
137                if recursive && item.kind().is_schema() {
138                    item.collapse_schema();
139                }
140
141                if let Some(schema) = item.kind().schema_name() {
142                    if schema == name {
143                        item.hide();
144                    }
145                } else {
146                    return;
147                }
148            }
149        }
150    }
151
152    pub fn expand(&mut self, index: usize, recursive: bool) {
153        if self.tree_items[index].kind().is_database() {
154            self.tree_items[index].expand_database();
155
156            let tree_item = self.tree_items[index].clone();
157            let name = self.tree_items[index].kind().name();
158            let kind = tree_item.kind();
159
160            if recursive {
161                for i in index + 1..self.tree_items.len() {
162                    let item = &mut self.tree_items[i];
163
164                    if let Some(db) = item.kind().database_name() {
165                        if *db != name {
166                            break;
167                        }
168                    }
169
170                    if item.kind().is_database() && item.kind().is_database_collapsed() {
171                        item.expand_database();
172                    }
173                }
174            }
175
176            self.update_visibility(kind, index + 1);
177        }
178
179        if self.tree_items[index].kind().is_schema() {
180            self.tree_items[index].expand_schema();
181
182            let tree_item = self.tree_items[index].clone();
183            let name = self.tree_items[index].kind().name();
184            let kind = tree_item.kind();
185
186            if recursive {
187                for i in index + 1..self.tree_items.len() {
188                    let item = &mut self.tree_items[i];
189
190                    if let Some(schema) = item.kind().schema_name() {
191                        if *schema != name {
192                            break;
193                        }
194                    }
195
196                    if item.kind().is_schema() && item.kind().is_schema_collapsed() {
197                        item.expand_schema();
198                    }
199                }
200            }
201
202            self.update_visibility(kind, index + 1);
203        }
204    }
205
206    fn update_visibility(&mut self, prefix: &DatabaseTreeItemKind, start_idx: usize) {
207        let mut inner_collapsed: Option<DatabaseTreeItemKind> = None;
208
209        for i in start_idx..self.tree_items.len() {
210            if let Some(ref collapsed_item) = inner_collapsed {
211                match collapsed_item {
212                    DatabaseTreeItemKind::Database { name, .. } => {
213                        if let DatabaseTreeItemKind::Schema { database, .. } =
214                            self.tree_items[i].kind().clone()
215                        {
216                            if database.name == *name {
217                                continue;
218                            }
219                        }
220                        if let DatabaseTreeItemKind::Table { database, .. } =
221                            self.tree_items[i].kind().clone()
222                        {
223                            if database.name == *name {
224                                continue;
225                            }
226                        }
227                    }
228                    DatabaseTreeItemKind::Schema { schema, .. } => {
229                        if let DatabaseTreeItemKind::Table { table, .. } =
230                            self.tree_items[i].kind().clone()
231                        {
232                            if matches!(table.schema, Some(table_schema) if schema.name == table_schema)
233                            {
234                                continue;
235                            }
236                        }
237                    }
238                    _ => (),
239                }
240                inner_collapsed = None;
241            }
242
243            let item_kind = self.tree_items[i].kind().clone();
244
245            if matches!(item_kind, DatabaseTreeItemKind::Database{ collapsed, .. } if collapsed)
246                || matches!(item_kind, DatabaseTreeItemKind::Schema{ collapsed, .. } if collapsed)
247            {
248                inner_collapsed = Some(item_kind.clone());
249            }
250
251            match prefix {
252                DatabaseTreeItemKind::Database { name, .. } => {
253                    if let DatabaseTreeItemKind::Schema { database, .. } = item_kind.clone() {
254                        if *name == database.name {
255                            self.tree_items[i].info_mut().set_visible(true);
256                        }
257                    }
258
259                    if let DatabaseTreeItemKind::Table { database, .. } = item_kind {
260                        if *name == database.name {
261                            self.tree_items[i].info_mut().set_visible(true);
262                        }
263                    }
264                }
265                DatabaseTreeItemKind::Schema { schema, .. } => {
266                    if let DatabaseTreeItemKind::Table { table, .. } = item_kind {
267                        if matches!(table.schema, Some(table_schema) if schema.name == table_schema)
268                        {
269                            self.tree_items[i].info_mut().set_visible(true);
270                        }
271                    }
272                }
273                _ => (),
274            }
275        }
276    }
277}