1use std::{
2 ops::{Deref, DerefMut},
3 str::FromStr,
4};
5
6use serde_json::Value;
7
8#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
9pub struct JsonPath(Vec<JsonPathElement>);
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub enum JsonPathElement {
13 Field(String), Index(JsonPathIndex),
15}
16
17impl ToString for JsonPathElement {
18 fn to_string(&self) -> String {
19 match self {
20 JsonPathElement::Field(v) => v.clone(),
21 JsonPathElement::Index(i) => i.to_string(),
22 }
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
27pub enum JsonPathIndex {
28 NthLefth(usize), NthRight(usize), }
31
32impl ToString for JsonPathIndex {
33 fn to_string(&self) -> String {
34 match self {
35 JsonPathIndex::NthLefth(i) => i.to_string(),
36 JsonPathIndex::NthRight(i) => format!("#-{i}"),
37 }
38 }
39}
40
41const ROOT: char = '$';
42const DOT: char = '.';
43const BEGIN_INDEX: char = '[';
44const CLOSE_INDEX: char = ']';
45const BEGIN_REVERSE_INDEX: char = '#';
46
47fn get_right(array: &Vec<Value>, i: usize) -> Option<&Value> {
49 if array.len() < i {
50 None
51 } else {
52 array.get(array.len() - i)
53 }
54}
55
56fn get_right_mut(array: &mut Vec<Value>, i: usize) -> Option<&mut Value> {
58 if array.len() < i {
59 None
60 } else {
61 let i = array.len() - i;
62 array.get_mut(i)
63 }
64}
65
66impl Deref for JsonPath {
67 type Target = Vec<JsonPathElement>;
68
69 #[inline]
70 fn deref(&self) -> &Self::Target {
71 &self.0
72 }
73}
74
75impl DerefMut for JsonPath {
76 fn deref_mut(&mut self) -> &mut Self::Target {
77 &mut self.0
78 }
79}
80
81impl JsonPath {
82 pub fn find<'a>(&self, value: &'a Value) -> Option<&'a Value> {
83 let mut value = value;
84 for e in self.iter() {
85 let sub = match e {
86 JsonPathElement::Field(key) => value.get(key),
87 JsonPathElement::Index(JsonPathIndex::NthLefth(i)) => value.get(i),
88 JsonPathElement::Index(JsonPathIndex::NthRight(i)) => {
89 value.as_array().and_then(|a| get_right(a, *i))
90 }
91 };
92 if let Some(sub) = sub {
93 value = sub;
94 } else {
95 return None;
96 }
97 }
98 Some(value)
99 }
100
101 pub fn find_mut<'a>(&self, value: &'a mut Value) -> Option<&'a mut Value> {
102 let mut value = value;
103 for e in self.iter() {
104 let sub = match e {
105 JsonPathElement::Field(key) => value.get_mut(key),
106 JsonPathElement::Index(JsonPathIndex::NthLefth(i)) => value.get_mut(i),
107 JsonPathElement::Index(JsonPathIndex::NthRight(i)) => {
108 value.as_array_mut().and_then(|a| get_right_mut(a, *i))
109 }
110 };
111 if let Some(sub) = sub {
112 value = sub;
113 } else {
114 return None;
115 }
116 }
117 Some(value)
118 }
119
120 pub fn insert<'a>(&self, value: &'a mut Value, v: Value) -> Option<&'a Value> {
121 match self.find_last_mut(value) {
122 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthLefth(i)))) => {
123 let i = *i;
124 if i <= target.len() {
125 target.insert(i, v);
126 Some(value)
127 } else {
128 None
129 }
130 }
131 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthRight(i)))) => {
132 if target.len() < *i {
133 return None;
134 }
135 let i = target.len() - i;
136 if i <= target.len() {
137 target.insert(i, v);
138 Some(value)
139 } else {
140 None
141 }
142 }
143 Some((Value::Object(target), JsonPathElement::Field(key))) => {
144 if target.contains_key(key) {
145 None
146 } else {
147 target.insert(key.clone(), v);
148 Some(value)
149 }
150 }
151 _ => None,
152 }
153 }
154
155 pub fn replace<'a>(&self, value: &'a mut Value, v: Value) -> Option<&'a Value> {
156 if let Some(target) = self.find_mut(value) {
157 *target = v;
158 Some(value)
159 } else {
160 None
161 }
162 }
163
164 pub fn set<'a>(&self, value: &'a mut Value, v: Value) -> Option<&'a Value> {
165 match self.find_last_mut(value) {
166 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthLefth(i)))) => {
167 if let Some(target) = target.get_mut(*i) {
168 *target = v;
169 Some(value)
170 } else {
171 None
172 }
173 }
174 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthRight(i)))) => {
175 if let Some(target) = get_right_mut(target, *i) {
176 *target = v;
177 Some(value)
178 } else {
179 None
180 }
181 }
182 Some((Value::Object(target), JsonPathElement::Field(key))) => {
183 target.insert(key.clone(), v);
184 Some(value)
185 }
186 _ => None,
187 }
188 }
189
190 pub fn remove<'a>(&self, value: &'a mut Value) -> Option<&'a Value> {
191 match self.find_last_mut(value) {
192 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthLefth(i)))) => {
193 if target.len() < *i {
194 None
195 } else {
196 target.remove(*i);
197 Some(value)
198 }
199 }
200 Some((Value::Array(target), JsonPathElement::Index(JsonPathIndex::NthRight(i)))) => {
201 if target.len() < *i {
202 None
203 } else {
204 let i = target.len() - i;
205 target.remove(i);
206 Some(value)
207 }
208 }
209 Some((Value::Object(target), JsonPathElement::Field(key))) => {
210 if target.remove(key).is_some() {
211 Some(value)
212 } else {
213 None
214 }
215 }
216 _ => None,
217 }
218 }
219
220 fn find_last_mut<'a>(&self, value: &'a mut Value) -> Option<(&'a mut Value, &JsonPathElement)> {
221 self.split_last().and_then(|(last, rest)| {
222 JsonPath(rest.to_vec())
223 .find_mut(value)
224 .map(|target| (target, last))
225 })
226 }
227}
228
229impl FromStr for JsonPath {
230 type Err = &'static str;
231 fn from_str(value: &str) -> Result<Self, Self::Err> {
232 let mut iter = value.chars().peekable();
233
234 match iter.peek() {
235 Some(&ROOT) => _ = iter.next(),
236 Some(v) if v.is_numeric() => {
237 let mut field = String::new();
238 while let Some(c) = iter.next_if(|c| c.is_numeric()) {
239 field.push(c);
240 }
241 let index =
242 JsonPathElement::Index(JsonPathIndex::NthLefth(field.parse().unwrap_or(0)));
243 return Ok(JsonPath(vec![index]));
244 }
245 _ => return Err("expected $ or numeric"),
246 };
247
248 let mut path: Vec<JsonPathElement> = Vec::new();
249 loop {
250 match iter.next() {
251 Some(DOT) => {
252 let mut field: String = String::new();
253 while let Some(c) = iter.next_if(|c| c.is_alphabetic()) {
254 field.push(c);
255 }
256 path.push(JsonPathElement::Field(field));
257 }
258 Some(BEGIN_INDEX) => {
259 let index = if iter.next_if_eq(&BEGIN_REVERSE_INDEX).is_some() {
260 iter.next_if_eq(&'-');
261 JsonPathIndex::NthRight(0)
262 } else {
263 JsonPathIndex::NthLefth(0)
264 };
265
266 let mut field: String = String::new();
267 while let Some(c) = iter.next_if(|c| c.is_numeric()) {
268 field.push(c);
269 }
270 if iter.next_if_eq(&CLOSE_INDEX).is_none() {
271 return Err("expected ]");
272 }
273 let index = match index {
274 JsonPathIndex::NthLefth(_) => {
275 JsonPathIndex::NthLefth(field.parse().unwrap_or(0))
276 }
277 JsonPathIndex::NthRight(_) => {
278 JsonPathIndex::NthRight(field.parse().unwrap_or(0))
279 }
280 };
281 path.push(JsonPathElement::Index(index));
282 }
283 None => return Ok(JsonPath(path)),
284 _ => return Err("expected . or ["),
285 }
286 }
287 }
288}
289
290impl TryFrom<&str> for JsonPath {
291 type Error = &'static str;
292
293 #[inline]
294 fn try_from(value: &str) -> Result<Self, Self::Error> {
295 JsonPath::from_str(value)
296 }
297}
298
299pub trait JsonPathQuery<'a> {
300 fn path(&'a self, query: &str) -> Result<&'a Value, &'static str>;
301 fn path_mut(&'a mut self, query: &str) -> Result<&'a mut Value, &'static str>;
302}
303
304impl<'a> JsonPathQuery<'a> for Value {
305 #[inline]
306 fn path(&'a self, query: &str) -> Result<&'a Value, &'static str> {
307 let path = JsonPath::try_from(query)?;
308 path.find(self).ok_or("unable to find path to value")
309 }
310
311 #[inline]
312 fn path_mut(&'a mut self, query: &str) -> Result<&'a mut Value, &'static str> {
313 let path = JsonPath::try_from(query)?;
314 path.find_mut(self).ok_or("unable to find path to value")
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use serde_json::json;
321
322 use super::*;
323
324 #[test]
325 fn try_from() {
326 let tests = vec![
327 ("$", Ok(JsonPath(vec![]))),
328 (
329 "3",
330 Ok(JsonPath(vec![JsonPathElement::Index(
331 JsonPathIndex::NthLefth(3),
332 )])),
333 ),
334 (
335 "$.a",
336 Ok(JsonPath(vec![JsonPathElement::Field("a".to_string())])),
337 ),
338 (
339 "$.a.b",
340 Ok(JsonPath(vec![
341 JsonPathElement::Field("a".to_string()),
342 JsonPathElement::Field("b".to_string()),
343 ])),
344 ),
345 (
346 "$.abc.bc.cbc",
347 Ok(JsonPath(vec![
348 JsonPathElement::Field("abc".to_string()),
349 JsonPathElement::Field("bc".to_string()),
350 JsonPathElement::Field("cbc".to_string()),
351 ])),
352 ),
353 (
354 "$[4]",
355 Ok(JsonPath(vec![JsonPathElement::Index(
356 JsonPathIndex::NthLefth(4),
357 )])),
358 ),
359 (
360 "$[4][3]",
361 Ok(JsonPath(vec![
362 JsonPathElement::Index(JsonPathIndex::NthLefth(4)),
363 JsonPathElement::Index(JsonPathIndex::NthLefth(3)),
364 ])),
365 ),
366 (
367 "$.a[4].b[3]",
368 Ok(JsonPath(vec![
369 JsonPathElement::Field("a".to_string()),
370 JsonPathElement::Index(JsonPathIndex::NthLefth(4)),
371 JsonPathElement::Field("b".to_string()),
372 JsonPathElement::Index(JsonPathIndex::NthLefth(3)),
373 ])),
374 ),
375 (
376 "$.a[#-4].b[3]",
377 Ok(JsonPath(vec![
378 JsonPathElement::Field("a".to_string()),
379 JsonPathElement::Index(JsonPathIndex::NthRight(4)),
380 JsonPathElement::Field("b".to_string()),
381 JsonPathElement::Index(JsonPathIndex::NthLefth(3)),
382 ])),
383 ),
384 (
385 "$.a[#]",
386 Ok(JsonPath(vec![
387 JsonPathElement::Field("a".to_string()),
388 JsonPathElement::Index(JsonPathIndex::NthRight(0)),
389 ])),
390 ),
391 (".a", Err("expected $ or numeric")),
393 ("a", Err("expected $ or numeric")),
394 ("[0]", Err("expected $ or numeric")),
395 ("$0]", Err("expected . or [")),
396 ];
397 for (path, expected) in tests {
398 assert_eq!(
399 path.try_into(),
400 expected,
401 "expected {} to be {:?}",
402 path,
403 expected
404 );
405 }
406 }
407
408 #[test]
409 fn path() {
410 let tests: Vec<(&str, serde_json::Value, Result<serde_json::Value, _>)> = vec![
411 ("$", json!({}), Ok(json!({}))),
412 ("$.a", json!({"a":"example"}), Ok(json!("example"))),
413 ("$[0]", json!([0, 1, 2, 3]), Ok(json!(0))),
414 ("$[#-1]", json!([0, 1, 2, 3]), Ok(json!(3))),
415 (
416 "$.a[#-1].b[0].test",
417 json!({"a": [
418 {
419 "b": "invalid"
420 },
421 {
422 "b": [{ "test": "example"}, { "test": "invalid" }]
423 }
424 ],
425 "b": "invalid"
426 }),
427 Ok(json!("example")),
428 ),
429 ("1", json!([1, 2, 4]), Ok(json!(2))),
430 ("$[2]", json!([1]), Err("unable to find path to value")),
431 (
432 "$.a[#-2]",
433 json!({ "b": [1] }),
434 Err("unable to find path to value"),
435 ),
436 ];
437
438 for (path, value, expected) in tests {
439 assert_eq!(
440 value.path(path).cloned(),
441 expected,
442 "expected {} from {} to be {:?}",
443 value,
444 path,
445 expected
446 );
447 let mut value = value;
448 assert_eq!(
449 value.path_mut(path).cloned(),
450 expected,
451 "expected {} from {} to be {:?}",
452 value,
453 path,
454 expected
455 );
456 }
457 }
458
459 #[test]
460 fn insert() {
461 let tests: Vec<(
462 JsonPath,
463 serde_json::Value,
464 serde_json::Value,
465 Option<serde_json::Value>,
466 )> = vec![
467 (
468 "$.a".try_into().unwrap(),
469 json!({}),
470 json!("test"),
471 Some(json!({ "a": "test"})),
472 ),
473 (
474 "$.a.b[1]".try_into().unwrap(),
475 json!({"a": { "b": [1,2,4] }}),
476 json!("test"),
477 Some(json!({ "a": { "b": [1, "test", 2, 4]}})),
478 ),
479 (
480 "$.a.b[#]".try_into().unwrap(),
481 json!({"a": { "b": [1,2,4] }}),
482 json!("test"),
483 Some(json!({ "a": { "b": [1, 2, 4, "test"]}})),
484 ),
485 (
486 "$.a.b[#-3]".try_into().unwrap(),
487 json!({"a": { "b": [1,2,4] }}),
488 json!("test"),
489 Some(json!({ "a": { "b": ["test", 1, 2, 4 ]}})),
490 ),
491 (
492 "$.a".try_into().unwrap(),
493 json!({"a": 10.0}),
494 json!("test"),
495 None,
496 ),
497 (
498 "$.a[1]".try_into().unwrap(),
499 json!({"a": []}),
500 json!("test"),
501 None,
502 ),
503 (
504 "$.a[#-3]".try_into().unwrap(),
505 json!({"a": []}),
506 json!("test"),
507 None,
508 ),
509 ];
510
511 for (path, mut value, extra, expected) in tests {
512 let value = path.insert(&mut value, extra);
513 assert_eq!(
514 value,
515 expected.as_ref(),
516 "expected {:?} to be {:?}",
517 value,
518 expected
519 );
520 }
521 }
522
523 #[test]
524 fn replace() {
525 let tests: Vec<(
526 JsonPath,
527 serde_json::Value,
528 serde_json::Value,
529 Option<serde_json::Value>,
530 )> = vec![
531 ("$.a".try_into().unwrap(), json!({}), json!("test"), None),
532 (
533 "$.a.b[1]".try_into().unwrap(),
534 json!({"a": { "b": [1,2,4] }}),
535 json!("test"),
536 Some(json!({ "a": { "b": [1, "test", 4]}})),
537 ),
538 (
539 "$.a.b[#-2]".try_into().unwrap(),
540 json!({"a": { "b": [1,2,4] }}),
541 json!("test"),
542 Some(json!({ "a": { "b": [1, "test", 4 ]}})),
543 ),
544 (
545 "$.a".try_into().unwrap(),
546 json!({"a": 10.0}),
547 json!("test"),
548 Some(json!({"a": "test"})),
549 ),
550 (
551 "$.a[1]".try_into().unwrap(),
552 json!({"a": []}),
553 json!("test"),
554 None,
555 ),
556 (
557 "$.a[#-3]".try_into().unwrap(),
558 json!({"a": []}),
559 json!("test"),
560 None,
561 ),
562 ];
563
564 for (path, mut value, extra, expected) in tests {
565 let value = path.replace(&mut value, extra);
566 assert_eq!(
567 value,
568 expected.as_ref(),
569 "expected {:?} to be {:?}",
570 value,
571 expected
572 );
573 }
574 }
575
576 #[test]
577 fn set() {
578 let tests: Vec<(
579 JsonPath,
580 serde_json::Value,
581 serde_json::Value,
582 Option<serde_json::Value>,
583 )> = vec![
584 (
585 "$.a".try_into().unwrap(),
586 json!({}),
587 json!("test"),
588 Some(json!({ "a": "test" })),
589 ),
590 (
591 "$.a.b[1]".try_into().unwrap(),
592 json!({"a": { "b": [1,2,4] }}),
593 json!("test"),
594 Some(json!({ "a": { "b": [1, "test", 4]}})),
595 ),
596 (
597 "$.a.b[#-2]".try_into().unwrap(),
598 json!({"a": { "b": [1,2,4] }}),
599 json!("test"),
600 Some(json!({ "a": { "b": [1, "test", 4 ]}})),
601 ),
602 (
603 "$.a".try_into().unwrap(),
604 json!({"a": 10.0}),
605 json!("test"),
606 Some(json!({"a": "test"})),
607 ),
608 (
609 "$.a[1]".try_into().unwrap(),
610 json!({"a": []}),
611 json!("test"),
612 None,
613 ),
614 (
615 "$.a[#-3]".try_into().unwrap(),
616 json!({"a": []}),
617 json!("test"),
618 None,
619 ),
620 ];
621
622 for (path, mut value, extra, expected) in tests {
623 let value = path.set(&mut value, extra);
624 assert_eq!(
625 value,
626 expected.as_ref(),
627 "expected {:?} to be {:?}",
628 value,
629 expected
630 );
631 }
632 }
633
634 #[test]
635 fn remove() {
636 let tests: Vec<(JsonPath, serde_json::Value, Option<serde_json::Value>)> = vec![
637 ("$.a".try_into().unwrap(), json!({}), None),
638 (
639 "$.a.b[1]".try_into().unwrap(),
640 json!({"a": { "b": [1,2,8] }}),
641 Some(json!({ "a": { "b": [1, 8]}})),
642 ),
643 (
644 "$.a.b[#-2]".try_into().unwrap(),
645 json!({"a": { "b": [1,2,4] }}),
646 Some(json!({ "a": { "b": [1, 4 ]}})),
647 ),
648 (
649 "$.a".try_into().unwrap(),
650 json!({"a": 10.0}),
651 Some(json!({})),
652 ),
653 ("$.a[1]".try_into().unwrap(), json!({"a": []}), None),
654 ("$.a[#-3]".try_into().unwrap(), json!({"a": []}), None),
655 ];
656
657 for (path, mut value, expected) in tests {
658 let value = path.remove(&mut value);
659 assert_eq!(
660 value,
661 expected.as_ref(),
662 "expected {:?} to be {:?}",
663 value,
664 expected
665 );
666 }
667 }
668}