rs_jsonpath/
lib.rs

1extern crate serde_json;
2extern crate regex;
3
4mod tokenizer;
5mod requests;
6
7use serde_json::Value;
8
9use tokenizer::*;
10use requests::*;
11
12pub fn lookup(json: String, json_path: String) -> Result<String, String> {
13    serde_json::from_str(json.as_str())
14        .map_err(|_| s("Unable to parse json"))
15        .and_then(|v| look(&v, &v, json_path))
16}
17
18pub fn look(root: &Value, json: &Value, json_path: String) -> Result<String,String>  {
19    let tokens = tokenize(json_path);
20    tokens.and_then(|token_list| {
21        token_list.iter().fold(Ok(json.clone()), |value, token| {
22            value.and_then(|v| {
23                let operation = parse_token(token.clone());
24                operation.and_then(|op| request_json(&root, &v, &op))
25            })
26        })
27    })
28    .and_then(|res| {
29        serde_json::to_string(&res).map_err(|_| s("Unable to convert result"))
30    })
31}
32
33pub fn find_filter(root: &Value, json: &Value, args: &Vec<String>) -> Result<Value,String> {
34    let res_values = args.iter().map(|arg| {
35        let filter = parse_filter(arg.to_string());
36        let res: Result<Vec<Value>, String> = filter.and_then(|parsed_filter| {
37            let values: Result<Vec<Value>, String> = json.as_array()
38                .map(|array| {
39                    array.iter().filter(|value| {
40                        println!("{:?}", serde_json::to_string(value).unwrap());
41                        let left = eval_expression(root, value, parsed_filter.left.clone());
42                        let right = eval_expression(root, value, parsed_filter.right.clone());
43                        if let (Ok(l),Ok(r)) = (left,right) {
44                            eval_filter(l.as_str(), parsed_filter.op.as_str(), r.as_str())
45                        } else {
46                            false
47                        }                        
48                    })
49                    .map(|value| value.clone())
50                    .collect::<Vec<Value>>()
51                })
52                .ok_or(s("Unable to filter json"));
53                values
54        });
55        println!("res: {:?}", res);
56        res
57    })
58    .collect::<Result<Vec<Vec<Value>>, String>>();
59    res_values.map(|arg| {
60        arg.into_iter().flat_map(|arg| { arg.into_iter() }).collect::<Vec<Value>>()
61    }).map(|value| Value::Array(value))
62}
63
64pub fn eval_expression(root: &Value, json: &Value, expression: String) -> Result<String,String> {
65    if !expression.contains("$") && !expression.contains("@") {
66        Ok(expression)
67    } else {
68        look(root, json, expression)
69    }
70}
71
72pub fn request_json(root: &Value, json: &Value, operation: &ParsedJsonPath) -> Result<Value,String> {
73    match operation.op.as_str() {
74        "root" => Ok(root.clone()),
75        "child" => Ok(json.clone()),
76        "key" => Ok(find_key(json, operation.key.as_str())),
77        "scan" => {
78            let res = search_key(json, operation.key.as_str(), &vec![]);
79            println!("filter: {:?}", res);
80            Ok(Value::Array(res))
81        }
82        "idx" => find_indexes(json, &operation.args),
83        "range" => find_range(json, &operation.args),
84        "filter" => {
85            let res = find_filter(root, json, &operation.args);
86            println!("filter: {:?}", res);
87            res
88        }
89        _ => Err(s("Unable to parse JsonPath expression")),
90    }
91}
92
93#[cfg(test)]
94mod tests {
95
96    use tokenizer::s;
97    use super::*;
98
99    #[test]
100    fn it_lookup() {
101        let data = r#" 
102        {
103            "firstName": "John",
104            "lastName" : "doe",
105            "age"      : 26,
106            "address"  : {
107                "streetAddress": "naist street",
108                "city"         : "Nara",
109                "type"   : "630-0192"
110            },
111            "phoneNumbers": [
112                {
113                "type"  : {"name": "iPhone", "type":"test"},
114                "number": "0123-4567-8888"
115                },
116                {
117                "type"  : "home",
118                "number": "0123-4567-8910"
119                }
120            ]
121        }
122        "#;
123        let jsonpath = "$..type[*].name";
124        let res = lookup(s(data), s(jsonpath)).unwrap();
125        let expected = r#"["iPhone"]"#;
126        assert_eq!(res, expected);
127    }
128
129    #[test]
130    fn it_lookup_with_filter() {
131        let data = r#" 
132        {
133            "firstName": "John",
134            "lastName" : "doe",
135            "age"      : 26,
136            "address"  : {
137                "streetAddress": "naist street",
138                "city"         : "Nara",
139                "type"   : "630-0192"
140            },
141            "phoneNumbers": [
142                {
143                "type"  : {"name": "iPhone", "type":"test"},
144                "number": "0123-4567-8888"
145                },
146                {
147                "type"  : "home",
148                "number": "0123-4567-8910"
149                }
150            ]
151        }
152        "#;
153        let jsonpath = r#"$.phoneNumbers[?(@.number == "0123-4567-8910")].type"#;
154        let res = lookup(s(data), s(jsonpath)).unwrap();
155        let expected = r#"["home"]"#;
156        assert_eq!(res, expected);
157    }
158}