access_json/
lib.rs

1//! # Query a subset of your Serde-Serializable Data
2//!
3//! This library allows you to execute a simple path-query against any serde-serializable object; returning the result as a ``Option<serde_json::Value>``.
4//!
5//! ```
6//! use access_json::JSONQuery;
7//! use std::collections::HashMap;
8//! use serde_json;
9//!
10//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
11//! let mut data: HashMap<&str, u32> = HashMap::default();
12//! data.insert("cat", 9);
13//!
14//! let query = JSONQuery::parse(".cat")?; // QueryParseErr
15//! let output = query.execute(&data)?; // QueryExecErr
16//! let expected = serde_json::to_value(&9)?; // You must derive Serialize!
17//!
18//! assert_eq!(Some(expected), output);
19//! # Ok(())
20//! # }
21//! ```
22//!
23//! ## A More Complex, Nested Example
24//!
25//!
26//! ```
27//! use access_json::JSONQuery;
28//! use serde_json::{self, Value};
29//!
30//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
31//! let data: Value = serde_json::from_str(r#"{
32//!    "items": [
33//!       {
34//!          "unwanted": 7,
35//!          "wanted": {"x": 3, "y": 7},
36//!          "array": [3,2,1]
37//!       },
38//!       {
39//!          "whatever": true
40//!       }
41//!    ]
42//! }"#)?;
43//!
44//! // We can reference dictionary fields and array indices together:
45//! let output = JSONQuery::parse(".items[1].whatever")?.execute(&data)?;
46//! let expected = serde_json::to_value(&true)?;
47//! assert_eq!(Some(expected), output);
48//!
49//! // We can have results be of any-size sub-tree, e.g., a whole array or vec.
50//! let output = JSONQuery::parse(".items[0].array")?.execute(&data)?;
51//! let expected = serde_json::to_value(&vec![3,2,1])?;
52//! assert_eq!(Some(expected), output);
53//! # Ok(())
54//! # }
55//! ```
56//!
57//! ## Just ``#[derive(Serialize)]`` to query any struct or enum:
58//!
59//! ```
60//! use access_json::JSONQuery;
61//! #[macro_use]
62//! extern crate serde_derive;
63//!
64//! #[derive(Serialize)]
65//! struct Dog {
66//!    name: String,
67//!    age: i32,
68//!    favorites: Vec<String>,
69//! }
70//!
71//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
72//! let data = Dog {
73//!     name: "Buddy".into(),
74//!     age: 14,
75//!     favorites: vec!["walks".into(), "naps".into()],
76//! };
77//!
78//! let found = JSONQuery::parse(".name")?.execute(&data)?.unwrap();
79//! assert_eq!("Buddy", found);
80//! # Ok(())
81//! # }
82//! ```
83//!
84
85#[macro_use]
86extern crate serde_derive;
87
88pub use erased_serde::Serialize as AnySerializable;
89
90pub mod query;
91pub mod query_executor;
92pub mod query_parser;
93
94#[doc(inline)]
95pub use query::JSONQuery;
96#[doc(inline)]
97pub use query_executor::QueryExecErr;
98#[doc(inline)]
99pub use query_parser::QueryParseErr;
100
101#[cfg(test)]
102mod tests {
103    use super::query::*;
104    use serde_json::Value as JV;
105    use std::collections::HashMap;
106
107    #[test]
108    fn test_query_hashmap() {
109        let mut data: HashMap<&str, usize> = HashMap::default();
110        data.insert("hello", 7);
111        data.insert("world", 5);
112        let world_q = JSONQuery::single(QueryElement::field("world"));
113        let found = world_q.execute(&data).unwrap();
114        assert_eq!(found, Some(JV::Number(5.into())));
115
116        let hello_q = JSONQuery::single(QueryElement::field("hello"));
117        let found = hello_q.execute(&data).unwrap();
118        assert_eq!(found, Some(JV::Number(7.into())));
119    }
120
121    #[test]
122    fn test_query_vec() {
123        let data = vec![0, 1, 2, 3, 4, 5];
124
125        for i in 0..data.len() {
126            let elem_q = JSONQuery::single(QueryElement::array_item(i));
127            let found = elem_q.execute(&data).unwrap().unwrap();
128            assert_eq!(found, (JV::Number(i.into())));
129        }
130
131        let missing_q = JSONQuery::single(QueryElement::array_item(17));
132        let found = missing_q.execute(&data).unwrap();
133        assert_eq!(None, found);
134    }
135
136    #[test]
137    fn test_tuple() {
138        let point = (17, 39);
139
140        let first_q = JSONQuery::single(QueryElement::array_item(0));
141        let found = first_q.execute(&point).unwrap().unwrap();
142        assert_eq!(found, (JV::Number(17.into())));
143
144        let second_q = JSONQuery::single(QueryElement::array_item(1));
145        let found = second_q.execute(&point).unwrap().unwrap();
146
147        assert_eq!(found, (JV::Number(39.into())));
148        let missing_q = JSONQuery::single(QueryElement::array_item(3));
149        let found = missing_q.execute(&point).unwrap();
150        assert_eq!(None, found);
151    }
152
153    #[derive(PartialEq, Eq, Clone, Serialize)]
154    struct Example {
155        name: String,
156        age: i32,
157        favorites: Vec<String>,
158    }
159
160    #[test]
161    fn test_example_struct() {
162        let data = Example {
163            name: "Buddy".into(),
164            age: 14,
165            favorites: vec!["walks".into(), "naps".into()],
166        };
167
168        let name_q = JSONQuery::single(QueryElement::field("name"));
169        assert_eq!("Buddy", name_q.execute(&data).unwrap().unwrap());
170        let age_q = JSONQuery::single(QueryElement::field("age"));
171        assert_eq!(14, age_q.execute(&data).unwrap().unwrap());
172
173        let first_favorite_q = JSONQuery::new(vec![
174            QueryElement::field("favorites"),
175            QueryElement::array_item(0),
176        ]);
177        assert_eq!("walks", first_favorite_q.execute(&data).unwrap().unwrap());
178    }
179
180    #[test]
181    fn test_whole_object_results() {
182        let data = Example {
183            name: "Buddy".into(),
184            age: 14,
185            favorites: vec!["walks".into(), "naps".into()],
186        };
187
188        let all_favorites = JSONQuery::single(QueryElement::field("favorites"));
189        let expected: Vec<JV> = vec!["walks".into(), "naps".into()];
190        assert_eq!(
191            Some(&expected),
192            all_favorites.execute(&data).unwrap().unwrap().as_array()
193        );
194    }
195
196    #[derive(Serialize)]
197    struct NestedStructs {
198        dog: Example,
199        truthiness: bool,
200        score: i32,
201    }
202
203    #[test]
204    fn test_nested_structs() {
205        let data = NestedStructs {
206            dog: Example {
207                name: "Buddy".into(),
208                age: 14,
209                favorites: vec!["walks".into(), "naps".into()],
210            },
211            truthiness: false,
212            score: -77,
213        };
214
215        assert_eq!(
216            JSONQuery::parse(".dog.name")
217                .unwrap()
218                .execute(&data)
219                .unwrap()
220                .unwrap(),
221            "Buddy"
222        );
223        assert_eq!(
224            JSONQuery::parse(".truthiness")
225                .unwrap()
226                .execute(&data)
227                .unwrap()
228                .unwrap(),
229            false
230        )
231    }
232
233    #[test]
234    fn test_vec_structs() {
235        let data: Vec<Example> = vec![
236            Example {
237                name: "Buddy".into(),
238                age: 14,
239                favorites: vec![],
240            },
241            Example {
242                name: "Tuukka".into(),
243                age: 6,
244                favorites: vec![],
245            },
246        ];
247        assert_eq!(
248            JSONQuery::parse("[0].name")
249                .unwrap()
250                .execute(&data)
251                .unwrap()
252                .unwrap(),
253            "Buddy"
254        );
255        assert_eq!(
256            JSONQuery::parse("[1].name")
257                .unwrap()
258                .execute(&data)
259                .unwrap()
260                .unwrap(),
261            "Tuukka"
262        )
263    }
264
265    #[derive(Serialize)]
266    enum Pet {
267        Bird,
268        Dog(Example),
269        Cat { lives: u32 },
270        Digits(u32, u32, u32),
271    }
272
273    #[test]
274    fn test_enum_examples() {
275        let buddy = Example {
276            name: "Buddy".into(),
277            age: 14,
278            favorites: vec!["walks".into(), "naps".into()],
279        };
280        let data = vec![
281            Pet::Bird,
282            Pet::Dog(buddy.clone()),
283            Pet::Cat { lives: 9 },
284            Pet::Digits(7, 5, 6),
285        ];
286        // For debugging:
287        //println!("json: {}", serde_json::to_string_pretty(&data).unwrap());
288
289        assert_eq!(
290            "Bird",
291            JSONQuery::parse("[0]")
292                .unwrap()
293                .execute(&data)
294                .unwrap()
295                .unwrap()
296        );
297        assert_eq!(
298            14,
299            JSONQuery::parse("[1].Dog.age")
300                .unwrap()
301                .execute(&data)
302                .unwrap()
303                .unwrap()
304        );
305        assert_eq!(
306            serde_json::to_value(buddy).unwrap(),
307            JSONQuery::parse("[1].Dog")
308                .unwrap()
309                .execute(&data)
310                .unwrap()
311                .unwrap()
312        );
313        assert_eq!(
314            "Bird",
315            JSONQuery::parse("[0]")
316                .unwrap()
317                .execute(&data)
318                .unwrap()
319                .unwrap()
320        );
321        assert_eq!(
322            9,
323            JSONQuery::parse("[2].Cat.lives")
324                .unwrap()
325                .execute(&data)
326                .unwrap()
327                .unwrap()
328        );
329        assert_eq!(
330            serde_json::to_value(vec![7, 5, 6]).unwrap(),
331            JSONQuery::parse("[3].Digits")
332                .unwrap()
333                .execute(&data)
334                .unwrap()
335                .unwrap()
336        );
337    }
338
339    // tuple-struct
340    #[derive(Serialize)]
341    struct Point(u32, u32);
342
343    #[test]
344    fn test_tuple_struct() {
345        let data = vec![Point(1, 2), Point(3, 4)];
346        assert_eq!(
347            serde_json::to_value(vec![1, 2]).unwrap(),
348            JSONQuery::parse("[0]")
349                .unwrap()
350                .execute(&data)
351                .unwrap()
352                .unwrap()
353        );
354        assert_eq!(
355            4,
356            JSONQuery::parse("[1][1]")
357                .unwrap()
358                .execute(&data)
359                .unwrap()
360                .unwrap()
361        );
362    }
363
364    #[test]
365    fn test_list_of_lists() {
366        let data = vec![
367            vec![vec![1, 2, 3], vec![4, 5, 6]],
368            vec![vec![7, 8, 9], vec![10, 11, 12]],
369        ];
370
371        assert_eq!(
372            serde_json::to_value(&vec![vec![1, 2, 3], vec![4, 5, 6]]).unwrap(),
373            JSONQuery::parse("[0]")
374                .unwrap()
375                .execute(&data)
376                .unwrap()
377                .unwrap()
378        )
379    }
380
381    #[derive(Debug, PartialEq, Eq, Serialize)]
382    struct UnitStruct;
383
384    #[test]
385    fn test_unit_struct() {
386        let nothings = vec![UnitStruct, UnitStruct];
387        assert_eq!(
388            serde_json::to_value(&UnitStruct).unwrap(),
389            JSONQuery::parse("[0]")
390                .unwrap()
391                .execute(&nothings)
392                .unwrap()
393                .unwrap()
394        )
395    }
396
397    #[derive(Debug, PartialEq, Eq, Serialize)]
398    struct NewType(i32);
399
400    #[test]
401    fn test_newtype_struct() {
402        let data = vec![NewType(-2), NewType(3)];
403        assert_eq!(
404            -2,
405            JSONQuery::parse("[0]")
406                .unwrap()
407                .execute(&data)
408                .unwrap()
409                .unwrap()
410        );
411        assert_eq!(
412            3,
413            JSONQuery::parse("[1]")
414                .unwrap()
415                .execute(&data)
416                .unwrap()
417                .unwrap()
418        )
419    }
420}