1use odbc_api::Nullability;
2use std::borrow::Cow;
3use std::collections::hash_map::Iter;
4use std::collections::HashMap;
5use std::ops::Deref;
6
7#[derive(Clone, Copy, PartialEq)]
8pub enum Entity {
9 Default, Procedure, Keyword, Function, }
14
15#[derive(Debug, PartialEq)]
16pub struct Payload {
17 pub dtype: String,
18 pub null: Nullability,
19 pub index: usize,
20}
21
22impl Payload {
23 pub fn new(
24 dtype: Cow<str>,
25 null: Nullability,
26 index: usize,
27 ) -> Self {
28 let dtype = dtype.into_owned();
29 Self { dtype, null, index }
30 }
31}
32
33pub struct CaseTree {
34 value: String,
35 entity: Entity,
36 payload: Option<Box<Payload>>,
37 children: Option<HashMap<String, CaseTree>>,
38}
39
40impl CaseTree {
41 pub fn new(value: Cow<str>) -> Self {
42 Self {
43 value: value.into_owned(),
44 entity: Entity::Default,
45 payload: None,
46 children: None,
47 }
48 }
49
50 pub fn set_entity(&mut self, entity: Entity) -> &mut Self {
51 self.entity = entity;
52 self
53 }
54
55 pub fn set_payload(
56 &mut self,
57 dtype: Cow<str>,
58 null: Nullability,
59 index: usize,
60 ) {
61 let payload = Payload::new(dtype, null, index);
62 self.payload = Some(Box::new(payload));
63 }
64
65 pub fn as_str(&self) -> &str {
66 self.value.as_str()
67 }
68
69 pub fn get_payload(&self) -> Option<&Payload> {
70 self.payload.as_ref().map(Box::deref)
71 }
72
73 pub fn insert_child(&mut self, path: &[Cow<str>], value: Cow<str>) -> Option<&mut Self> {
74 let mut path = path;
75 while let [head, tail @ ..] = path {
76 if !head.is_empty() {
77 let child = self.children
78 .get_or_insert_with(HashMap::new)
79 .entry(head.to_lowercase())
80 .or_insert_with(|| Self::new(head.clone()));
81 return child.insert_child(tail, value);
82 }
83 path = tail;
84 }
85 if !value.is_empty() {
86 let child = self.children
87 .get_or_insert_with(HashMap::new)
88 .entry(value.to_lowercase())
89 .or_insert_with(|| Self::new(value));
90 return Some(child);
91 }
92 None
93 }
94
95 pub fn get_child(&self, path: &[&str]) -> Option<&Self> {
96 if let [head, tail @ ..] = path {
97 if head.is_empty() {
98 return self.get_child(tail);
99 }
100 if let Some(children) = &self.children {
101 if let Some(child) = children.get(*head) {
102 return child.get_child(tail);
103 }
104 }
105 None
106 } else {
107 Some(self)
108 }
109 }
110
111 pub fn get_values<'a>(&'a self, path: &[&str]) -> CaseValues<'a> {
112 if let Some(child) = self.get_child(path) {
113 if let Some(children) = &child.children {
114 return CaseValues::new(children);
115 }
116 }
117 CaseValues::default()
118 }
119
120 pub fn get_nodes(&self, entity: Entity) -> CaseNodes<'_> {
121 if let Some(children) = &self.children {
122 return CaseNodes::new(children, entity);
123 }
124 CaseNodes::default()
125 }
126}
127
128pub struct CaseValues<'a> {
129 inner: Iter<'a, String, CaseTree>,
130}
131
132impl<'a> CaseValues<'a> {
133 pub fn new(children: &'a HashMap<String, CaseTree>) -> Self {
134 let inner = children.iter();
135 Self { inner }
136 }
137}
138
139impl<'a> Default for CaseValues<'a> {
140 fn default() -> Self {
141 let inner = Iter::default();
142 Self { inner }
143 }
144}
145
146impl<'a> Iterator for CaseValues<'a> {
147 type Item = (&'a String, (&'a String, Entity));
148
149 fn next(&mut self) -> Option<Self::Item> {
150 if let Some((key, child)) = self.inner.next() {
151 Some((key, (&child.value, child.entity)))
152 } else {
153 None
154 }
155 }
156}
157
158pub struct CaseNodes<'a> {
159 inner: Iter<'a, String, CaseTree>,
160 entity: Entity,
161}
162
163impl<'a> CaseNodes<'a> {
164 pub fn new(children: &'a HashMap<String, CaseTree>, entity: Entity) -> Self {
165 let inner = children.iter();
166 Self { inner, entity }
167 }
168}
169
170impl<'a> Default for CaseNodes<'a> {
171 fn default() -> Self {
172 let inner = Iter::default();
173 let entity = Entity::Default;
174 Self { inner, entity }
175 }
176}
177
178impl<'a> Iterator for CaseNodes<'a> {
179 type Item = (&'a String, &'a CaseTree);
180
181 fn next(&mut self) -> Option<Self::Item> {
182 while let Some((key, child)) = self.inner.next() {
183 if child.entity == self.entity {
184 return Some((key, child));
185 }
186 }
187 None
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use crate::core::case::{CaseTree, Entity};
194 use crate::{cow_arr, cow_str, str_vec};
195 use pretty_assertions::assert_eq;
196 use std::borrow::Cow;
197 use std::collections::BTreeMap;
198
199 #[test]
200 fn test_leaf_not_inserted_with_empty_path_and_empty_value() {
201 let mut tree = CaseTree::new(cow_str!(""));
202 tree.insert_child(&[], cow_str!(""));
203 assert_eq!(get_children(&tree, &[]), None);
204 assert_eq!(get_children(&tree, &["alpha"]), None);
205 assert_eq!(get_children(&tree, &["alpha", "delta"]), None);
206 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
207 }
208
209 #[test]
210 fn test_leaf_is_inserted_with_empty_path_and_valid_value() {
211 let mut tree = CaseTree::new(cow_str!(""));
212 tree.insert_child(&[], cow_str!("Alpha"));
213 assert_eq!(get_children(&tree, &[]), Some(str_vec!["Alpha"]));
214 assert_eq!(get_children(&tree, &["alpha"]), None);
215 assert_eq!(get_children(&tree, &["alpha", "delta"]), None);
216 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
217 }
218
219 #[test]
220 fn test_leaf_not_inserted_with_compact_path_and_empty_value() {
221 let mut tree = CaseTree::new(cow_str!(""));
222 tree.insert_child(cow_arr!["Alpha", "Delta"], cow_str!(""));
223 assert_eq!(get_children(&tree, &[]), Some(str_vec!["Alpha"]));
224 assert_eq!(get_children(&tree, &["alpha"]), Some(str_vec!["Delta"]));
225 assert_eq!(get_children(&tree, &["alpha", "delta"]), None);
226 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
227 }
228
229 #[test]
230 fn test_leaf_is_inserted_with_compact_path_and_valid_value() {
231 let mut tree = CaseTree::new(cow_str!(""));
232 tree.insert_child(cow_arr!["Alpha", "Delta"], cow_str!("Kilo"));
233 assert_eq!(get_children(&tree, &[]), Some(str_vec!["Alpha"]));
234 assert_eq!(get_children(&tree, &["alpha"]), Some(str_vec!["Delta"]));
235 assert_eq!(get_children(&tree, &["alpha", "delta"]), Some(str_vec!["Kilo"]));
236 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
237 }
238
239 #[test]
240 fn test_leaf_not_inserted_with_sparse_path_and_empty_value() {
241 let mut tree = CaseTree::new(cow_str!(""));
242 tree.insert_child(cow_arr!["", "Alpha", "", "Delta", ""], cow_str!(""));
243 assert_eq!(get_children(&tree, &[]), Some(str_vec!["Alpha"]));
244 assert_eq!(get_children(&tree, &["alpha"]), Some(str_vec!["Delta"]));
245 assert_eq!(get_children(&tree, &["alpha", "delta"]), None);
246 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
247 }
248
249 #[test]
250 fn test_leaf_is_inserted_with_sparse_path_and_valid_value() {
251 let mut tree = CaseTree::new(cow_str!(""));
252 tree.insert_child(cow_arr!["", "Alpha", "", "Delta", ""], cow_str!("Kilo"));
253 assert_eq!(get_children(&tree, &[]), Some(str_vec!["Alpha"]));
254 assert_eq!(get_children(&tree, &["alpha"]), Some(str_vec!["Delta"]));
255 assert_eq!(get_children(&tree, &["alpha", "delta"]), Some(str_vec!["Kilo"]));
256 assert_eq!(get_children(&tree, &["alpha", "delta", "kilo"]), None);
257 }
258
259 fn get_children(tree: &CaseTree, path: &[&str]) -> Option<Vec<String>> {
260 let child = tree.get_child(path)?;
261 let children = child.children.as_ref()?;
262 let mut children = children
263 .values()
264 .map(|child| child.value.to_string())
265 .collect::<Vec<_>>();
266 children.sort();
267 Some(children)
268 }
269
270 #[test]
271 fn test_values_are_returned_by_path() {
272 let tree = create_tree();
273 assert_eq!(get_values(&tree, &[]), str_vec![
274 "Alpha",
275 "Bravo",
276 ]);
277 assert_eq!(get_values(&tree, &["bravo"]), str_vec![
278 "Echo",
279 "Foxtrot",
280 "Golf",
281 "Hotel",
282 ]);
283 assert_eq!(get_values(&tree, &["", "alpha", "", "charlie", ""]), str_vec![
284 "India",
285 "Juliet",
286 ]);
287 assert_eq!(get_values(&tree, &["alpha", "delta", "lima"]), str_vec![
288 "Yankee",
289 "Zulu",
290 ]);
291 assert_eq!(get_values(&tree, &["unknown"]).is_empty(), true);
292 assert_eq!(get_values(&tree, &["unknown", "unknown"]).is_empty(), true);
293 assert_eq!(get_values(&tree, &["alpha", "unknown"]).is_empty(), true);
294 }
295
296 #[test]
297 fn test_nodes_are_returned_by_path() {
298 let tree = create_tree();
299 assert_eq!(get_nodes(&tree, &[]), str_vec![
300 "Alpha",
301 "Bravo",
302 ]);
303 assert_eq!(get_nodes(&tree, &["bravo"]), str_vec![
304 "Echo",
305 "Foxtrot",
306 "Golf",
307 "Hotel",
308 ]);
309 assert_eq!(get_nodes(&tree, &["", "alpha", "", "charlie", ""]), str_vec![
310 "India",
311 "Juliet",
312 ]);
313 assert_eq!(get_nodes(&tree, &["alpha", "delta", "lima"]), str_vec![
314 "Yankee",
315 "Zulu",
316 ]);
317 assert_eq!(get_nodes(&tree, &["unknown"]).is_empty(), true);
318 assert_eq!(get_nodes(&tree, &["unknown", "unknown"]).is_empty(), true);
319 assert_eq!(get_nodes(&tree, &["alpha", "unknown"]).is_empty(), true);
320 }
321
322 fn create_tree() -> CaseTree {
323 let mut tree = CaseTree::new(cow_str!(""));
324 tree.insert_child(cow_arr!["Alpha", "Charlie", "India"], cow_str!("Sierra"));
325 tree.insert_child(cow_arr!["Alpha", "Charlie", "India"], cow_str!("Tango"));
326 tree.insert_child(cow_arr!["Alpha", "Charlie", "Juliet"], cow_str!("Uniform"));
327 tree.insert_child(cow_arr!["Alpha", "Charlie", "Juliet"], cow_str!("Victor"));
328 tree.insert_child(cow_arr!["Alpha", "Delta", "Kilo"], cow_str!("Whiskey"));
329 tree.insert_child(cow_arr!["Alpha", "Delta", "Kilo"], cow_str!("Xray"));
330 tree.insert_child(cow_arr!["Alpha", "Delta", "Lima"], cow_str!("Yankee"));
331 tree.insert_child(cow_arr!["Alpha", "Delta", "Lima"], cow_str!("Zulu"));
332 tree.insert_child(cow_arr!["Bravo", "Echo"], cow_str!("Mike"));
333 tree.insert_child(cow_arr!["Bravo", "Echo"], cow_str!("November"));
334 tree.insert_child(cow_arr!["Bravo", "Echo"], cow_str!("Oscar"));
335 tree.insert_child(cow_arr!["Bravo", "Foxtrot"], cow_str!("Papa"));
336 tree.insert_child(cow_arr!["Bravo", "Foxtrot"], cow_str!("Quebec"));
337 tree.insert_child(cow_arr!["Bravo", "Golf"], cow_str!("Romeo"));
338 tree.insert_child(cow_arr!["Bravo"], cow_str!("Hotel"));
339 tree
340 }
341
342 fn get_values<'a>(tree: &'a CaseTree, path: &[&str]) -> Vec<&'a str> {
343 let values = tree
344 .get_values(path)
345 .map(|(key, (value, _))| (key, value.as_ref()))
346 .collect::<BTreeMap<_, _>>();
347 values.into_values().collect()
348 }
349
350 fn get_nodes<'a>(tree: &'a CaseTree, path: &[&str]) -> Vec<&'a str> {
351 if let Some(child) = tree.get_child(path) {
352 let values = child
353 .get_nodes(Entity::Default)
354 .map(|(key, child)| (key, child.as_str()))
355 .collect::<BTreeMap<_, _>>();
356 values.into_values().collect()
357 } else {
358 Vec::new()
359 }
360 }
361}