access_json/
query.rs

1use crate::query_executor::{QueryExecErr, QueryExecutor};
2use crate::query_parser::{parse_query, QueryParseErr};
3use crate::AnySerializable;
4use serde::Serialize;
5
6#[derive(Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
7pub enum QueryElement {
8    Field(String),
9    ArrayItem(usize),
10}
11
12impl QueryElement {
13    pub fn field(field: &str) -> Self {
14        Self::Field(field.into())
15    }
16    pub fn array_item(index: usize) -> Self {
17        Self::ArrayItem(index)
18    }
19}
20
21impl std::fmt::Display for QueryElement {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            QueryElement::Field(name) => write!(f, ".{}", name),
25            QueryElement::ArrayItem(index) => write!(f, "[{}]", index),
26        }
27    }
28}
29
30/// This is the main interface to this library.
31/// Create a new JSONQuery by calling parse.
32#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
33pub struct JSONQuery {
34    /// A list of access-elements, field names or array indices.
35    pub elements: Vec<QueryElement>,
36}
37
38/// This is a way to visualize a JSONQuery object as a parse-able string.
39impl std::fmt::Display for JSONQuery {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        for elem in self.elements.iter() {
42            write!(f, "{}", elem)?
43        }
44        Ok(())
45    }
46}
47
48impl JSONQuery {
49    /// Construct a new JSONQuery object from discrete elements.
50    pub(crate) fn new(elements: Vec<QueryElement>) -> Self {
51        Self { elements }
52    }
53
54    /// Construct a new JSONQuery object from an example string.
55    ///
56    /// ```
57    /// use access_json::JSONQuery;
58    /// use access_json::query::QueryElement; // Only needed to validate our parsing.
59    ///
60    /// assert_eq!(
61    ///   JSONQuery::parse(".field.array[8]").unwrap().elements,
62    ///   vec![QueryElement::field("field"),
63    ///        QueryElement::field("array"),
64    ///        QueryElement::array_item(8)]);
65    /// ```
66    pub fn parse(input: &str) -> Result<Self, QueryParseErr> {
67        Ok(Self::new(parse_query(input)?))
68    }
69
70    #[cfg(test)]
71    pub fn single(q: QueryElement) -> Self {
72        Self::new(vec![q])
73    }
74
75    /// Execute a JSONQuery object against any serde-serializable object.
76    ///
77    /// ```
78    /// use access_json::JSONQuery;
79    /// use std::collections::HashMap;
80    /// use serde_json;
81    ///
82    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
83    /// let mut data: HashMap<&str, u32> = HashMap::default();
84    /// data.insert("cat", 9);
85    ///
86    /// let query = JSONQuery::parse(".cat")?;
87    /// let output = query.execute(&data)?;
88    /// let expected = serde_json::to_value(&9)?;
89    ///
90    /// assert_eq!(Some(expected), output);
91    /// # Ok(())
92    /// # }
93    /// ```
94    pub fn execute(
95        &self,
96        target: &dyn AnySerializable,
97    ) -> Result<Option<serde_json::Value>, QueryExecErr> {
98        let mut runner = QueryExecutor::new(self)?;
99        target.serialize(&mut runner)?;
100        Ok(runner.get_result())
101    }
102}