gluesql_core/data/value/
selector.rs1use {
2 super::{Value, ValueError},
3 crate::result::Result,
4 std::{
5 collections::BTreeMap,
6 ops::ControlFlow::{Break, Continue},
7 },
8};
9
10enum Selectable<'a> {
11 Map(&'a BTreeMap<String, Value>),
12 List(&'a Vec<Value>),
13 Other(&'a Value),
14}
15
16impl Value {
17 pub fn selector(&self, selector: &str) -> Result<Value> {
18 let selectable = match self {
19 Value::Map(v) => Selectable::Map(v),
20 Value::List(v) => Selectable::List(v),
21 _ => return Err(ValueError::SelectorRequiresMapOrListTypes.into()),
22 };
23
24 let result = selector.split('.').try_fold(selectable, |selectable, key| {
25 let value = match selectable {
26 Selectable::Map(map) => map.get(key),
27 Selectable::List(list) => key.parse::<usize>().ok().and_then(|i| list.get(i)),
28 Selectable::Other(_) => return Break(()),
29 };
30
31 match value {
32 Some(Value::Map(map)) => Continue(Selectable::Map(map)),
33 Some(Value::List(list)) => Continue(Selectable::List(list)),
34 Some(value) => Continue(Selectable::Other(value)),
35 None => Break(()),
36 }
37 });
38
39 let value = match result {
40 Continue(Selectable::Map(map)) => Value::Map(map.clone()),
41 Continue(Selectable::List(list)) => Value::List(list.clone()),
42 Continue(Selectable::Other(value)) => value.clone(),
43 Break(()) => Value::Null,
44 };
45
46 Ok(value)
47 }
48
49 pub fn selector_by_index(&self, selector: &[Value]) -> Result<Value> {
50 selector
51 .iter()
52 .map(String::from)
53 .try_fold(self, |selectable, key| {
54 selectable.get_value_from_compound_type(&key)
55 })
56 .cloned()
57 }
58
59 fn get_value_from_compound_type(&self, key: &str) -> Result<&Value> {
60 let value = match self {
61 Value::Map(map) => map.get(key),
62 Value::List(list) => key.parse::<usize>().ok().and_then(|i| list.get(i)),
63 _ => return Err(ValueError::SelectorRequiresMapOrListTypes.into()),
64 };
65
66 Ok(value.unwrap_or(&Value::Null))
67 }
68}