gluesql_core/data/value/
selector.rs

1use {
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}