streamson_lib/handler/
analyser.rs

1//! Handler which stores matched paths
2
3use std::{any::Any, collections::HashMap, str::FromStr};
4
5use super::Handler;
6use crate::{
7    error,
8    path::{Element, Path},
9    streamer::Token,
10};
11
12#[derive(Debug, Default)]
13pub struct Analyser {
14    /// Stored paths with counts
15    paths: HashMap<String, usize>,
16}
17
18/// Converts Path to string reducing arrays to "[]"
19/// e.g. {"users"}[0]{"name"} => {"users"}[]{"name"}
20fn to_recuded_array_str(path: &Path) -> String {
21    path.get_path()
22        .iter()
23        .map(|e| match e {
24            Element::Key(key) => format!(r#"{{"{}"}}"#, key),
25            Element::Index(_) => "[]".to_string(),
26        })
27        .collect()
28}
29
30impl Handler for Analyser {
31    fn start(
32        &mut self,
33        path: &Path,
34        _matcher_idx: usize,
35        _token: Token,
36    ) -> Result<Option<Vec<u8>>, error::Handler> {
37        *self.paths.entry(to_recuded_array_str(path)).or_insert(0) += 1;
38        Ok(None)
39    }
40
41    fn as_any(&self) -> &dyn Any {
42        self
43    }
44}
45
46impl FromStr for Analyser {
47    type Err = error::Handler;
48    fn from_str(input: &str) -> Result<Self, Self::Err> {
49        if input.is_empty() {
50            Ok(Self::new())
51        } else {
52            Err(error::Handler::new("Analyser handler accepts no argument"))
53        }
54    }
55}
56
57impl Analyser {
58    /// Creates a new handler analyser
59    /// Which stores paths to analyse the structure of the JSON
60    pub fn new() -> Self {
61        Self::default()
62    }
63
64    /// Results of analysis
65    pub fn results(&self) -> Vec<(String, usize)> {
66        let mut res: Vec<(String, usize)> = self
67            .paths
68            .iter()
69            .map(|(path, count)| (path.to_string(), *count))
70            .collect();
71        res.sort_by(|(a_path, _), (b_path, _)| a_path.cmp(b_path));
72        res
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::Analyser;
79    use crate::strategy::{All, Strategy};
80    use std::sync::{Arc, Mutex};
81
82    #[test]
83    fn analyser_handler() {
84        let mut all = All::new();
85
86        let analyser_handler = Arc::new(Mutex::new(Analyser::new()));
87
88        all.add_handler(analyser_handler.clone());
89
90        all.process(br#"{"elements": [1, 2, 3, [41, 42, {"sub1": {"subsub": 1}, "sub2": null}]], "after": true, "last": [{"aaa": 1, "cc": "dd"}, {"aaa": 2, "extra": false}]}"#).unwrap();
91
92        // Test analyser handler
93        let results = analyser_handler.lock().unwrap().results();
94        assert_eq!(results.len(), 13);
95        assert_eq!(results[0], ("".to_string(), 1));
96        assert_eq!(results[1], (r#"{"after"}"#.to_string(), 1));
97        assert_eq!(results[2], (r#"{"elements"}"#.to_string(), 1));
98        assert_eq!(results[3], (r#"{"elements"}[]"#.to_string(), 4));
99        assert_eq!(results[4], (r#"{"elements"}[][]"#.to_string(), 3));
100        assert_eq!(results[5], (r#"{"elements"}[][]{"sub1"}"#.to_string(), 1));
101        assert_eq!(
102            results[6],
103            (r#"{"elements"}[][]{"sub1"}{"subsub"}"#.to_string(), 1)
104        );
105        assert_eq!(results[7], (r#"{"elements"}[][]{"sub2"}"#.to_string(), 1));
106        assert_eq!(results[8], (r#"{"last"}"#.to_string(), 1));
107        assert_eq!(results[9], (r#"{"last"}[]"#.to_string(), 2));
108        assert_eq!(results[10], (r#"{"last"}[]{"aaa"}"#.to_string(), 2));
109        assert_eq!(results[11], (r#"{"last"}[]{"cc"}"#.to_string(), 1));
110        assert_eq!(results[12], (r#"{"last"}[]{"extra"}"#.to_string(), 1));
111    }
112}