1 | mod atom;
|
2 | mod comparable;
|
3 | mod comparison;
|
4 | mod filter;
|
5 | mod jp_query;
|
6 | pub mod queryable;
|
7 | mod segment;
|
8 | mod selector;
|
9 | pub mod state;
|
10 | mod test;
|
11 | mod test_function;
|
12 |
|
13 | use crate::parser::errors::JsonPathError;
|
14 | use crate::parser::parse_json_path;
|
15 | use crate::query::queryable::Queryable;
|
16 | use crate::query::state::{Data, Pointer};
|
17 | use state::State;
|
18 | use std::borrow::Cow;
|
19 |
|
20 | /// A type that can be queried with JSONPath, typically string
|
21 | pub type QueryPath = String;
|
22 |
|
23 | /// A type that can be queried with JSONPath, typically Result
|
24 | pub type Queried<T> = Result<T, JsonPathError>;
|
25 |
|
26 | /// Main internal trait to implement the logic of processing jsonpath.
|
27 | pub trait Query {
|
28 | fn process<'a, T: Queryable>(&self, state: State<'a, T>) -> State<'a, T>;
|
29 | }
|
30 |
|
31 | /// The resulting type of JSONPath query.
|
32 | /// It can either be a value or a reference to a value with its path.
|
33 | #[derive (Debug, Clone, PartialEq)]
|
34 | pub struct QueryRef<'a, T: Queryable>(&'a T, QueryPath);
|
35 |
|
36 | impl<'a, T: Queryable> From<(&'a T, QueryPath)> for QueryRef<'a, T> {
|
37 | fn from((inner: &'a T, path: String): (&'a T, QueryPath)) -> Self {
|
38 | QueryRef(inner, path)
|
39 | }
|
40 | }
|
41 | impl<'a, T: Queryable> From<(&'a T, &str)> for QueryRef<'a, T> {
|
42 | fn from((inner: &'a T, path: &str): (&'a T, &str)) -> Self {
|
43 | QueryRef(inner, path.to_string())
|
44 | }
|
45 | }
|
46 |
|
47 | impl<'a, T: Queryable> QueryRef<'a, T> {
|
48 | pub fn val(self) -> &'a T {
|
49 | self.0
|
50 | }
|
51 | pub fn path(self) -> QueryPath {
|
52 | self.1
|
53 | }
|
54 | }
|
55 |
|
56 | impl<'a, T: Queryable> From<Pointer<'a, T>> for QueryRef<'a, T> {
|
57 | fn from(pointer: Pointer<'a, T>) -> Self {
|
58 | QueryRef(pointer.inner, pointer.path)
|
59 | }
|
60 | }
|
61 |
|
62 | /// The main function to process a JSONPath query.
|
63 | /// It takes a path and a value, and returns a vector of `QueryResult` thus values + paths.
|
64 | pub fn js_path<'a, T: Queryable>(path: &str, value: &'a T) -> Queried<Vec<QueryRef<'a, T>>> {
|
65 | match parse_json_path(jp_str:path)?.process(State::root(value)).data {
|
66 | Data::Ref(p: Pointer<'_, T>) => Ok(vec![p.into()]),
|
67 | Data::Refs(refs: Vec>) => Ok(refs.into_iter().map(Into::into).collect()),
|
68 | Data::Value(v: T) => Err(v.into()),
|
69 | Data::Nothing => Ok(vec![]),
|
70 | }
|
71 | }
|
72 |
|
73 | /// A convenience function to process a JSONPath query and return a vector of values, omitting the path.
|
74 | pub fn js_path_vals<'a, T: Queryable>(path: &str, value: &'a T) -> Queried<Vec<&'a T>> {
|
75 | Ok(js_pathimpl Iterator (path, value)?
|
76 | .into_iter()
|
77 | .map(|r: QueryRef<'_, T>| r.val())
|
78 | .collect::<Vec<_>>())
|
79 | }
|
80 |
|
81 | /// A convenience function to process a JSONPath query and return a vector of paths, omitting the values.
|
82 | pub fn js_path_path<T: Queryable>(path: &str, value: &T) -> Queried<Vec<QueryPath>> {
|
83 | Ok(js_pathimpl Iterator (path, value)?
|
84 | .into_iter()
|
85 | .map(|r: QueryRef<'_, T>| r.path())
|
86 | .collect::<Vec<_>>())
|
87 | }
|
88 |
|
89 | #[cfg (test)]
|
90 | mod tests {
|
91 | use crate::parser::errors::JsonPathError;
|
92 | use crate::parser::Parsed;
|
93 | use crate::query::queryable::Queryable;
|
94 | use crate::query::{js_path, Queried, QueryRef};
|
95 | use crate::JsonPath;
|
96 | use serde_json::{json, Value};
|
97 |
|
98 | fn test<'a, R>(json: &'a str, path: &str, expected: Vec<R>) -> Parsed<()>
|
99 | where
|
100 | R: Into<QueryRef<'a, Value>>,
|
101 | {
|
102 | let json: Value = serde_json::from_str(json).map_err(|v| JsonPathError::NoRulePath)?;
|
103 | let expected: Vec<QueryRef<'a, Value>> = expected.into_iter().map(|v| v.into()).collect();
|
104 | assert_eq!(json.query_with_path(path)?, expected);
|
105 |
|
106 | Ok(())
|
107 | }
|
108 |
|
109 | fn template_json<'a>() -> &'a str {
|
110 | r#" {"store": { "book": [
|
111 | {
|
112 | "category": "reference",
|
113 | "author": "Nigel Rees",
|
114 | "title": "Sayings of the Century",
|
115 | "price": 8.95
|
116 | },
|
117 | {
|
118 | "category": "fiction",
|
119 | "author": "Evelyn Waugh",
|
120 | "title": "Sword of Honour",
|
121 | "price": 12.99
|
122 | },
|
123 | {
|
124 | "category": "fiction",
|
125 | "author": "Herman Melville",
|
126 | "title": "Moby Dick",
|
127 | "isbn": "0-553-21311-3",
|
128 | "price": 8.99
|
129 | },
|
130 | {
|
131 | "category": "fiction",
|
132 | "author": "J. R. R. Tolkien",
|
133 | "title": "The Lord of the Rings",
|
134 | "isbn": "0-395-19395-8",
|
135 | "price": 22.99
|
136 | }
|
137 | ],
|
138 | "bicycle": {
|
139 | "color": "red",
|
140 | "price": 19.95
|
141 | }
|
142 | },
|
143 | "array":[0,1,2,3,4,5,6,7,8,9],
|
144 | "orders":[
|
145 | {
|
146 | "ref":[1,2,3],
|
147 | "id":1,
|
148 | "filled": true
|
149 | },
|
150 | {
|
151 | "ref":[4,5,6],
|
152 | "id":2,
|
153 | "filled": false
|
154 | },
|
155 | {
|
156 | "ref":[7,8,9],
|
157 | "id":3,
|
158 | "filled": null
|
159 | }
|
160 | ],
|
161 | "expensive": 10 }"#
|
162 | }
|
163 | fn update_by_path_test() -> Queried<()> {
|
164 | let mut json = json!([
|
165 | {"verb" : "RUN" ,"distance" :[1]},
|
166 | {"verb" : "TEST" },
|
167 | {"verb" : "DO NOT RUN" }
|
168 | ]);
|
169 |
|
170 | let path = json.query_only_path("$.[?(@.verb == 'RUN')]" )?;
|
171 | let elem = path.first().cloned().unwrap_or_default();
|
172 |
|
173 | if let Some(v) = json
|
174 | .reference_mut(elem)
|
175 | .and_then(|v| v.as_object_mut())
|
176 | .and_then(|v| v.get_mut("distance" ))
|
177 | .and_then(|v| v.as_array_mut())
|
178 | {
|
179 | v.push(json!(2))
|
180 | }
|
181 |
|
182 | assert_eq!(
|
183 | json,
|
184 | json!([
|
185 | {"verb" : "RUN" ,"distance" :[1,2]},
|
186 | {"verb" : "TEST" },
|
187 | {"verb" : "DO NOT RUN" }
|
188 | ])
|
189 | );
|
190 |
|
191 | Ok(())
|
192 | }
|
193 |
|
194 | #[test ]
|
195 | fn simple_test() {
|
196 | let j1 = json!(2);
|
197 | let _ = test("[1,2,3]" , "$[1]" , vec![(&j1, "$[1]" .to_string())]);
|
198 | }
|
199 |
|
200 | #[test ]
|
201 | fn root_test() {
|
202 | let js = serde_json::from_str(template_json()).unwrap();
|
203 | let _ = test(template_json(), "$" , vec![(&js, "$" )]);
|
204 | }
|
205 |
|
206 | #[test ]
|
207 | fn descent_test() {
|
208 | let v1 = json!("reference" );
|
209 | let v2 = json!("fiction" );
|
210 | let _ = test(
|
211 | template_json(),
|
212 | "$..category" ,
|
213 | vec![
|
214 | (&v1, "$['store']['book'][0]['category']" ),
|
215 | (&v2, "$['store']['book'][1]['category']" ),
|
216 | (&v2, "$['store']['book'][2]['category']" ),
|
217 | (&v2, "$['store']['book'][3]['category']" ),
|
218 | ],
|
219 | );
|
220 | let js1 = json!(19.95);
|
221 | let js2 = json!(8.95);
|
222 | let js3 = json!(12.99);
|
223 | let js4 = json!(8.99);
|
224 | let js5 = json!(22.99);
|
225 | let _ = test(
|
226 | template_json(),
|
227 | "$.store..price" ,
|
228 | vec![
|
229 | (&js1, "$['store']['bicycle']['price']" ),
|
230 | (&js2, "$['store']['book'][0]['price']" ),
|
231 | (&js3, "$['store']['book'][1]['price']" ),
|
232 | (&js4, "$['store']['book'][2]['price']" ),
|
233 | (&js5, "$['store']['book'][3]['price']" ),
|
234 | ],
|
235 | );
|
236 | let js1 = json!("Nigel Rees" );
|
237 | let js2 = json!("Evelyn Waugh" );
|
238 | let js3 = json!("Herman Melville" );
|
239 | let js4 = json!("J. R. R. Tolkien" );
|
240 | let _ = test(
|
241 | template_json(),
|
242 | "$..author" ,
|
243 | vec![
|
244 | (&js1, "$['store']['book'][0]['author']" ),
|
245 | (&js2, "$['store']['book'][1]['author']" ),
|
246 | (&js3, "$['store']['book'][2]['author']" ),
|
247 | (&js4, "$['store']['book'][3]['author']" ),
|
248 | ],
|
249 | );
|
250 | }
|
251 |
|
252 | #[test ]
|
253 | fn wildcard_test() {
|
254 | let js1 = json!("reference" );
|
255 | let js2 = json!("fiction" );
|
256 | let _ = test(
|
257 | template_json(),
|
258 | "$..book.[*].category" ,
|
259 | vec![
|
260 | (&js1, "$['store']['book'][0].['category']" ),
|
261 | (&js2, "$['store']['book'][1].['category']" ),
|
262 | (&js2, "$['store']['book'][2].['category']" ),
|
263 | (&js2, "$['store']['book'][3].['category']" ),
|
264 | ],
|
265 | );
|
266 | let js1 = json!("Nigel Rees" );
|
267 | let js2 = json!("Evelyn Waugh" );
|
268 | let js3 = json!("Herman Melville" );
|
269 | let js4 = json!("J. R. R. Tolkien" );
|
270 | let _ = test(
|
271 | template_json(),
|
272 | "$.store.book[*].author" ,
|
273 | vec![
|
274 | (&js1, "$['store']['book'][0]['author']" ),
|
275 | (&js2, "$['store']['book'][1]['author']" ),
|
276 | (&js3, "$['store']['book'][2]['author']" ),
|
277 | (&js4, "$['store']['book'][3]['author']" ),
|
278 | ],
|
279 | );
|
280 | }
|
281 |
|
282 | #[test ]
|
283 | fn descendent_wildcard_test() {
|
284 | let js1 = json!("0-553-21311-3" );
|
285 | let js2 = json!("0-395-19395-8" );
|
286 | let _ = test(
|
287 | template_json(),
|
288 | "$..*.[?@].isbn" ,
|
289 | vec![
|
290 | (&js1, "$['store']['book'][2]['isbn']" ),
|
291 | (&js2, "$['store']['book'][3]['isbn']" ),
|
292 | ],
|
293 | );
|
294 | }
|
295 |
|
296 | #[test ]
|
297 | fn field_test() {
|
298 | let value = json!({"active" :1});
|
299 | let _ = test(
|
300 | r#"{"field":{"field":[{"active":1},{"passive":1}]}}"# ,
|
301 | "$.field.field[?@.active]" ,
|
302 | vec![(&value, "$['field']['field'][0]" )],
|
303 | );
|
304 | }
|
305 |
|
306 | #[test ]
|
307 | fn index_index_test() {
|
308 | let value = json!("0-553-21311-3" );
|
309 | let _ = test(
|
310 | template_json(),
|
311 | "$..book[2].isbn" ,
|
312 | vec![(&value, "$['store']['book'][2]['isbn']" )],
|
313 | );
|
314 | }
|
315 |
|
316 | #[test ]
|
317 | fn index_unit_index_test() {
|
318 | let value = json!("0-553-21311-3" );
|
319 | let _ = test(
|
320 | template_json(),
|
321 | "$..book[2,4].isbn" ,
|
322 | vec![(&value, "$['store']['book'][2]['isbn']" )],
|
323 | );
|
324 | let value1 = json!("0-395-19395-8" );
|
325 | let _ = test(
|
326 | template_json(),
|
327 | "$..book[2,3].isbn" ,
|
328 | vec![
|
329 | (&value, "$['store']['book'][2]['isbn']" ),
|
330 | (&value1, "$['store']['book'][3]['isbn']" ),
|
331 | ],
|
332 | );
|
333 | }
|
334 |
|
335 | #[test ]
|
336 | fn index_unit_keys_test() {
|
337 | let js1 = json!("Moby Dick" );
|
338 | let js2 = json!(8.99);
|
339 | let js3 = json!("The Lord of the Rings" );
|
340 | let js4 = json!(22.99);
|
341 | let _ = test(
|
342 | template_json(),
|
343 | "$..book[2,3]['title','price']" ,
|
344 | vec![
|
345 | (&js1, "$['store']['book'][2]['title']" ),
|
346 | (&js3, "$['store']['book'][3]['title']" ),
|
347 | (&js2, "$['store']['book'][2]['price']" ),
|
348 | (&js4, "$['store']['book'][3]['price']" ),
|
349 | ],
|
350 | );
|
351 | }
|
352 |
|
353 | #[test ]
|
354 | fn index_slice_test() -> Parsed<()> {
|
355 | let i0 = "$['array'][0]" ;
|
356 | let i1 = "$['array'][1]" ;
|
357 | let i2 = "$['array'][2]" ;
|
358 | let i3 = "$['array'][3]" ;
|
359 | let i4 = "$['array'][4]" ;
|
360 | let i5 = "$['array'][5]" ;
|
361 | let i6 = "$['array'][6]" ;
|
362 | let i7 = "$['array'][7]" ;
|
363 | let i8 = "$['array'][8]" ;
|
364 | let i9 = "$['array'][9]" ;
|
365 |
|
366 | let j0 = json!(0);
|
367 | let j1 = json!(1);
|
368 | let j2 = json!(2);
|
369 | let j3 = json!(3);
|
370 | let j4 = json!(4);
|
371 | let j5 = json!(5);
|
372 | let j6 = json!(6);
|
373 | let j7 = json!(7);
|
374 | let j8 = json!(8);
|
375 | let j9 = json!(9);
|
376 | test(
|
377 | template_json(),
|
378 | "$.array[:]" ,
|
379 | vec![
|
380 | (&j0, i0),
|
381 | (&j1, i1),
|
382 | (&j2, i2),
|
383 | (&j3, i3),
|
384 | (&j4, i4),
|
385 | (&j5, i5),
|
386 | (&j6, i6),
|
387 | (&j7, i7),
|
388 | (&j8, i8),
|
389 | (&j9, i9),
|
390 | ],
|
391 | )?;
|
392 | test(
|
393 | template_json(),
|
394 | "$.array[1:4:2]" ,
|
395 | vec![(&j1, i1), (&j3, i3)],
|
396 | )?;
|
397 | test(
|
398 | template_json(),
|
399 | "$.array[::3]" ,
|
400 | vec![(&j0, i0), (&j3, i3), (&j6, i6), (&j9, i9)],
|
401 | )?;
|
402 | test(template_json(), "$.array[-1:]" , vec![(&j9, i9)])?;
|
403 | test(template_json(), "$.array[-2:-1]" , vec![(&j8, i8)])?;
|
404 |
|
405 | Ok(())
|
406 | }
|
407 |
|
408 | #[test ]
|
409 | fn index_filter_test() -> Parsed<()> {
|
410 | let moby = json!("Moby Dick" );
|
411 | let rings = json!("The Lord of the Rings" );
|
412 | test(
|
413 | template_json(),
|
414 | "$..book[?@.isbn].title" ,
|
415 | vec![
|
416 | (&moby, "$['store']['book'][2]['title']" ),
|
417 | (&rings, "$['store']['book'][3]['title']" ),
|
418 | ],
|
419 | )?;
|
420 | let sword = json!("Sword of Honour" );
|
421 | test(
|
422 | template_json(),
|
423 | "$..book[?(@.price != 8.95)].title" ,
|
424 | vec![
|
425 | (&sword, "$['store']['book'][1]['title']" ),
|
426 | (&moby, "$['store']['book'][2]['title']" ),
|
427 | (&rings, "$['store']['book'][3]['title']" ),
|
428 | ],
|
429 | )?;
|
430 | let sayings = json!("Sayings of the Century" );
|
431 | test(
|
432 | template_json(),
|
433 | "$..book[?(@.price == 8.95)].title" ,
|
434 | vec![(&sayings, "$['store']['book'][0]['title']" )],
|
435 | )?;
|
436 |
|
437 | let js12 = json!(12.99);
|
438 | let js899 = json!(8.99);
|
439 | let js2299 = json!(22.99);
|
440 | test(
|
441 | template_json(),
|
442 | "$..book[?@.price >= 8.99].price" ,
|
443 | vec![
|
444 | (&js12, "$['store']['book'][1]['price']" ),
|
445 | (&js899, "$['store']['book'][2]['price']" ),
|
446 | (&js2299, "$['store']['book'][3]['price']" ),
|
447 | ],
|
448 | )?;
|
449 |
|
450 | test(
|
451 | template_json(),
|
452 | "$..book[?(@.price >= $.expensive)].price" ,
|
453 | vec![
|
454 | (&js12, "$['store']['book'][1]['price']" ),
|
455 | (&js2299, "$['store']['book'][3]['price']" ),
|
456 | ],
|
457 | )?;
|
458 | Ok(())
|
459 | }
|
460 |
|
461 | #[test ]
|
462 | fn union_quotes() -> Queried<()> {
|
463 | let json = json!({
|
464 | "a" : "ab" ,
|
465 | "b" : "bc"
|
466 | });
|
467 |
|
468 | let vec = js_path("$['a', \r'b']" , &json)?;
|
469 |
|
470 | assert_eq!(
|
471 | vec,
|
472 | vec![
|
473 | (&json!("ab" ), "$['a']" .to_string()).into(),
|
474 | (&json!("bc" ), "$['b']" .to_string()).into(),
|
475 | ]
|
476 | );
|
477 |
|
478 | Ok(())
|
479 | }
|
480 |
|
481 | #[test ]
|
482 | fn space_between_selectors() -> Queried<()> {
|
483 | let json = json!({
|
484 | "a" : {
|
485 | "b" : "ab"
|
486 | }
|
487 | });
|
488 |
|
489 | let vec = js_path("$['a'] \r['b']" , &json)?;
|
490 |
|
491 | assert_eq!(vec, vec![(&json!("ab" ), "$['a']['b']" .to_string()).into(),]);
|
492 |
|
493 | Ok(())
|
494 | }
|
495 | #[test ]
|
496 | fn space_in_search() -> Queried<()> {
|
497 | let json = json!(["foo" , "123" ]);
|
498 |
|
499 | let vec = js_path("$[?search(@ \n,'[a-z]+')]" , &json)?;
|
500 |
|
501 | assert_eq!(vec, vec![(&json!("foo" ), "$[0]" .to_string()).into(),]);
|
502 |
|
503 | Ok(())
|
504 | }
|
505 | #[test ]
|
506 | fn filter_key() -> Queried<()> {
|
507 | let json = json!([
|
508 | {
|
509 | "a" : "b" ,
|
510 | "d" : "e"
|
511 | },
|
512 | {
|
513 | "a" : 1,
|
514 | "d" : "f"
|
515 | }
|
516 | ]);
|
517 |
|
518 | let vec = js_path("$[?@.a!= \"b \"]" , &json)?;
|
519 |
|
520 | assert_eq!(
|
521 | vec,
|
522 | vec![(&json!({"a" :1, "d" :"f" }), "$[1]" .to_string()).into(),]
|
523 | );
|
524 |
|
525 | Ok(())
|
526 | }
|
527 |
|
528 | #[test ]
|
529 | fn regex_key() -> Queried<()> {
|
530 | let json = json!({
|
531 | "regex" : "b.?b" ,
|
532 | "values" : [
|
533 | "abc" ,
|
534 | "bcd" ,
|
535 | "bab" ,
|
536 | "bba" ,
|
537 | "bbab" ,
|
538 | "b" ,
|
539 | true,
|
540 | [],
|
541 | {}
|
542 | ]
|
543 | });
|
544 |
|
545 | let vec = js_path("$.values[?match(@, $.regex)]" , &json)?;
|
546 |
|
547 | assert_eq!(
|
548 | vec,
|
549 | vec![(&json!("bab" ), "$['values'][2]" .to_string()).into(),]
|
550 | );
|
551 |
|
552 | Ok(())
|
553 | }
|
554 | #[test ]
|
555 | fn name_sel() -> Queried<()> {
|
556 | let json = json!({
|
557 | "/" : "A"
|
558 | });
|
559 |
|
560 | let vec = js_path("$[' \\/']" , &json)?;
|
561 |
|
562 | assert_eq!(vec, vec![(&json!("A" ), "$[' \\/']" .to_string()).into(),]);
|
563 |
|
564 | Ok(())
|
565 | }
|
566 | #[test ]
|
567 | fn unicode_fns() -> Queried<()> {
|
568 | let json = json!(["ж" , "Ж" , "1" , "жЖ" , true, [], {}]);
|
569 |
|
570 | let vec = js_path("$[?match(@, ' \\\\p{Lu}')]" , &json)?;
|
571 |
|
572 | assert_eq!(vec, vec![(&json!("Ж" ), "$[1]" .to_string()).into(),]);
|
573 |
|
574 | Ok(())
|
575 | }
|
576 | #[test ]
|
577 | fn fn_res_can_not_compare() -> Queried<()> {
|
578 | let json = json!({});
|
579 |
|
580 | let vec = js_path("$[?match(@.a, 'a.*')==true]" , &json);
|
581 |
|
582 | assert!(vec.is_err());
|
583 |
|
584 | Ok(())
|
585 | }
|
586 | #[test ]
|
587 | fn too_small() -> Queried<()> {
|
588 | let json = json!({});
|
589 |
|
590 | let vec = js_path("$[-9007199254740992]" , &json);
|
591 |
|
592 | assert!(vec.is_err());
|
593 |
|
594 | Ok(())
|
595 | }
|
596 | #[test ]
|
597 | fn filter_data() -> Queried<()> {
|
598 | let json = json!({
|
599 | "a" : 1,
|
600 | "b" : 2,
|
601 | "c" : 3
|
602 | });
|
603 |
|
604 | let vec: Vec<String> = json.query_only_path("$[?@<3]" )?.into_iter().collect();
|
605 |
|
606 | assert_eq!(vec, vec!["$['a']" .to_string(), "$['b']" .to_string()]);
|
607 |
|
608 | Ok(())
|
609 | }
|
610 | #[test ]
|
611 | fn exp_no_error() -> Queried<()> {
|
612 | let json = json!([
|
613 | {
|
614 | "a" : 100,
|
615 | "d" : "e"
|
616 | },
|
617 | {
|
618 | "a" : 100.1,
|
619 | "d" : "f"
|
620 | },
|
621 | {
|
622 | "a" : "100" ,
|
623 | "d" : "g"
|
624 | }
|
625 | ]);
|
626 |
|
627 | let vec: Vec<&Value> = json.query("$[?@.a==1E2]" )?;
|
628 | assert_eq!(vec, vec![&json!({"a" :100, "d" :"e" })]);
|
629 |
|
630 | Ok(())
|
631 | }
|
632 | #[test ]
|
633 | fn single_quote() -> Queried<()> {
|
634 | let json = json!({
|
635 | "a'" : "A" ,
|
636 | "b" : "B"
|
637 | });
|
638 |
|
639 | let vec = js_path("$[ \"a' \"]" , &json)?;
|
640 | assert_eq!(vec, vec![(&json!("A" ), "$[' \"a \'\"']" .to_string()).into(),]);
|
641 |
|
642 | Ok(())
|
643 | }
|
644 | #[test ]
|
645 | fn union() -> Queried<()> {
|
646 | let json = json!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
647 |
|
648 | let vec: Vec<QueryRef<Value>> = json.query_with_path("$[1,5:7]" )?;
|
649 | assert_eq!(
|
650 | vec,
|
651 | vec![
|
652 | (&json!(1), "$[1]" .to_string()).into(),
|
653 | (&json!(5), "$[5]" .to_string()).into(),
|
654 | (&json!(6), "$[6]" .to_string()).into(),
|
655 | ]
|
656 | );
|
657 |
|
658 | Ok(())
|
659 | }
|
660 |
|
661 | #[test ]
|
662 | fn basic_descendent() -> Queried<()> {
|
663 | let json = json!({
|
664 | "o" : [
|
665 | 0,
|
666 | 1,
|
667 | [
|
668 | 2,
|
669 | 3
|
670 | ]
|
671 | ]
|
672 | });
|
673 |
|
674 | let vec = js_path("$..[1]" , &json)?;
|
675 | assert_eq!(
|
676 | vec,
|
677 | vec![
|
678 | (&json!(1), "$['o'][1]" .to_string()).into(),
|
679 | (&json!(3), "$['o'][2][1]" .to_string()).into(),
|
680 | ]
|
681 | );
|
682 |
|
683 | Ok(())
|
684 | }
|
685 | #[test ]
|
686 | fn filter_absent() -> Queried<()> {
|
687 | let json = json!([
|
688 | {
|
689 | "list" : [
|
690 | 1
|
691 | ]
|
692 | }
|
693 | ]);
|
694 |
|
695 | let vec = js_path("$[?@.absent==@.list[9]]" , &json)?;
|
696 | assert_eq!(
|
697 | vec,
|
698 | vec![(&json!({"list" : [1]}), "$[0]" .to_string()).into(),]
|
699 | );
|
700 |
|
701 | Ok(())
|
702 | }
|
703 |
|
704 | #[test ]
|
705 | fn filter_star() -> Queried<()> {
|
706 | let json = json!([1,[],[2],{},{"a" : 3}]);
|
707 |
|
708 | let vec = json.query_with_path("$[?@.*]" )?;
|
709 | assert_eq!(
|
710 | vec,
|
711 | vec![
|
712 | (&json!([2]), "$[2]" .to_string()).into(),
|
713 | (&json!({"a" : 3}), "$[4]" .to_string()).into(),
|
714 | ]
|
715 | );
|
716 |
|
717 | Ok(())
|
718 | }
|
719 |
|
720 | #[test ]
|
721 | fn space_test() -> Queried<()> {
|
722 | let json = json!({ " " : "A" });
|
723 |
|
724 | let vec = json.query_with_path("$[' ']" )?;
|
725 | assert_eq!(vec, vec![(&json!("A" ), "$[ \' \']" .to_string()).into(),]);
|
726 |
|
727 | Ok(())
|
728 | }
|
729 | #[test ]
|
730 | fn neg_idx() -> Queried<()> {
|
731 | let json = json!(["first" , "second" ]);
|
732 |
|
733 | let vec = json.query_with_path("$[-2]" )?;
|
734 | assert_eq!(vec, vec![(&json!("first" ), "$[0]" .to_string()).into(),]);
|
735 |
|
736 | Ok(())
|
737 | }
|
738 |
|
739 | #[test ]
|
740 | fn filter_slice() -> Queried<()> {
|
741 | let json = json!([
|
742 | 1,
|
743 | [],
|
744 | [
|
745 | 2
|
746 | ],
|
747 | [
|
748 | 2,
|
749 | 3,
|
750 | 4
|
751 | ],
|
752 | {},
|
753 | {
|
754 | "a" : 3
|
755 | }
|
756 | ]);
|
757 |
|
758 | let vec = json.query_with_path("$[?@[0:2]]" )?;
|
759 | assert_eq!(
|
760 | vec,
|
761 | vec![
|
762 | (&json!([2]), "$[2]" ).into(),
|
763 | (&json!([2, 3, 4]), "$[3]" ).into(),
|
764 | ]
|
765 | );
|
766 |
|
767 | Ok(())
|
768 | }
|
769 |
|
770 | #[test ]
|
771 | fn surr_pairs() -> Queried<()> {
|
772 | let json = json!({
|
773 | "𝄞" : "A"
|
774 | });
|
775 | let vec = json.query_with_path("$['𝄞']" )?;
|
776 | assert_eq!(vec, vec![(&json!("A" ), "$['𝄞']" .to_string()).into()]);
|
777 |
|
778 | Ok(())
|
779 | }
|
780 | #[test ]
|
781 | fn tab_key() -> Queried<()> {
|
782 | let json = json!({
|
783 | " \\t" : "A"
|
784 | });
|
785 | let vec = json.query_with_path("$[' \\t']" )?;
|
786 | assert_eq!(vec, vec![(&json!("A" ), "$[' \\t']" .to_string()).into()]);
|
787 |
|
788 | Ok(())
|
789 | }
|
790 | #[test ]
|
791 | fn escaped_up_hex() -> Queried<()> {
|
792 | let json = json!({
|
793 | "☺" : "A"
|
794 | });
|
795 | let vec = json.query_with_path("$['☺']" )?;
|
796 | assert_eq!(vec, vec![(&json!("A" ), "$['☺']" .to_string()).into()]);
|
797 |
|
798 | Ok(())
|
799 | }
|
800 | #[test ]
|
801 | fn carr_return() -> Queried<()> {
|
802 | let json = json!({
|
803 | " \\r" : "A"
|
804 | });
|
805 | let vec = json.query_with_path("$[' \\r']" )?;
|
806 | assert_eq!(vec, vec![(&json!("A" ), "$[' \\r']" .to_string()).into()]);
|
807 |
|
808 | Ok(())
|
809 | }
|
810 | }
|
811 | |