1use crate::parser::errors::JsonPathError;
2use crate::parser::model::{JpQuery, Segment, Selector};
3use crate::parser::{parse_json_path, Parsed};
4use crate::query::{Queried, QueryPath};
5use crate::JsonPath;
6use serde_json::Value;
7use std::borrow::Cow;
8use std::fmt::Debug;
9
10pub trait Queryable
55where
56 Self: Default
57 + Clone
58 + Debug
59 + for<'a> From<&'a str>
60 + From<bool>
61 + From<i64>
62 + From<f64>
63 + From<Vec<Self>>
64 + From<String>
65 + PartialEq,
66{
67 fn get(&self, key: &str) -> Option<&Self>;
71
72 fn as_array(&self) -> Option<&Vec<Self>>;
73
74 fn as_object(&self) -> Option<Vec<(&str, &Self)>>;
75
76 fn as_str(&self) -> Option<&str>;
77
78 fn as_i64(&self) -> Option<i64>;
79 fn as_f64(&self) -> Option<f64>;
80 fn as_bool(&self) -> Option<bool>;
81
82 fn null() -> Self;
84
85 fn extension_custom(_name: &str, _args: Vec<Cow<Self>>) -> Self {
86 Self::null()
87 }
88
89 fn reference<T>(&self, _path: T) -> Option<&Self>
95 where
96 T: Into<QueryPath>,
97 {
98 None
99 }
100
101 fn reference_mut<T>(&mut self, _path: T) -> Option<&mut Self>
137 where
138 T: Into<QueryPath>,
139 {
140 None
141 }
142
143 fn delete_by_path(&mut self, _path: &str) -> Queried<usize> {
171 Err(JsonPathError::InvalidJsonPath(
172 "Deletion not supported".to_string(),
173 ))
174 }
175}
176
177impl Queryable for Value {
178 fn get(&self, key: &str) -> Option<&Self> {
179 self.get(key)
180 }
181
182 fn as_array(&self) -> Option<&Vec<Self>> {
183 self.as_array()
184 }
185
186 fn as_object(&self) -> Option<Vec<(&str, &Self)>> {
187 self.as_object()
188 .map(|v| v.into_iter().map(|(k, v)| (k.as_str(), v)).collect())
189 }
190
191 fn as_str(&self) -> Option<&str> {
192 self.as_str()
193 }
194
195 fn as_i64(&self) -> Option<i64> {
196 self.as_i64()
197 }
198
199 fn as_f64(&self) -> Option<f64> {
200 self.as_f64()
201 }
202
203 fn as_bool(&self) -> Option<bool> {
204 self.as_bool()
205 }
206
207 fn null() -> Self {
208 Value::Null
209 }
210
211 fn extension_custom(name: &str, args: Vec<Cow<Self>>) -> Self {
243 match name {
244 "in" => match args.as_slice() {
245 [lhs, rhs] => match rhs.as_array() {
246 Some(elements) => elements.iter().any(|item| item == lhs.as_ref()).into(),
247 None => Self::null(),
248 },
249 _ => Self::null(),
250 },
251 "nin" => match args.as_slice() {
252 [lhs, rhs] => match rhs.as_array() {
253 Some(elements) => (!elements.iter().any(|item| item == lhs.as_ref())).into(),
254 None => Self::null(),
255 },
256 _ => Self::null(),
257 },
258 "none_of" => match args.as_slice() {
259 [lhs, rhs] => match (lhs.as_array(), rhs.as_array()) {
260 (Some(lhs_arr), Some(rhs_arr)) => lhs_arr
261 .iter()
262 .all(|lhs| !rhs_arr.iter().any(|rhs| lhs == rhs))
263 .into(),
264 _ => Self::null(),
265 },
266 _ => Self::null(),
267 },
268 "any_of" => match args.as_slice() {
269 [lhs, rhs] => match (lhs.as_array(), rhs.as_array()) {
270 (Some(lhs_arr), Some(rhs_arr)) => lhs_arr
271 .iter()
272 .any(|lhs| rhs_arr.iter().any(|rhs| lhs == rhs))
273 .into(),
274 _ => Self::null(),
275 },
276 _ => Self::null(),
277 },
278 "subset_of" => match args.as_slice() {
279 [lhs, rhs] => match (lhs.as_array(), rhs.as_array()) {
280 (Some(lhs_arr), Some(rhs_arr)) => lhs_arr
281 .iter()
282 .all(|lhs| rhs_arr.iter().any(|rhs| lhs == rhs))
283 .into(),
284 _ => Self::null(),
285 },
286 _ => Self::null(),
287 },
288 _ => Self::null(),
289 }
290 }
291
292 fn reference<T>(&self, path: T) -> Option<&Self>
293 where
294 T: Into<QueryPath>,
295 {
296 convert_js_path(&path.into())
297 .ok()
298 .and_then(|p| self.pointer(p.as_str()))
299 }
300
301 fn reference_mut<T>(&mut self, path: T) -> Option<&mut Self>
302 where
303 T: Into<QueryPath>,
304 {
305 convert_js_path(&path.into())
306 .ok()
307 .and_then(|p| self.pointer_mut(p.as_str()))
308 }
309
310 fn delete_by_path(&mut self, path: &str) -> Queried<usize> {
311 let mut deletions = Vec::new();
312 for query_path in &self.query_only_path(path)? {
313 if let Some(deletion_info) = parse_deletion_path(query_path)? {
314 deletions.push(deletion_info);
315 }
316 }
317
318 deletions.sort_by(|a, b| {
320 b.path_depth()
321 .cmp(&a.path_depth())
322 .then_with(|| match (a, b) {
323 (
324 DeletionInfo::ArrayIndex { index: idx_a, .. },
325 DeletionInfo::ArrayIndex { index: idx_b, .. },
326 ) => idx_b.cmp(idx_a),
327 _ => std::cmp::Ordering::Equal,
328 })
329 });
330
331 let deleted_count = deletions.iter().try_fold(0, |c, d| {
333 execute_deletion(self, d).map(|deleted| if deleted { c + 1 } else { c })
334 })?;
335
336 Ok(deleted_count)
337 }
338}
339
340#[derive(Debug, Clone)]
341enum DeletionInfo {
342 ObjectField {
343 parent_path: String,
344 field_name: String,
345 },
346 ArrayIndex {
347 parent_path: String,
348 index: usize,
349 },
350 Root,
351}
352
353impl DeletionInfo {
354 fn path_depth(&self) -> usize {
355 match self {
356 DeletionInfo::Root => 0,
357 DeletionInfo::ObjectField { parent_path, .. }
358 | DeletionInfo::ArrayIndex { parent_path, .. } => parent_path.matches('/').count(),
359 }
360 }
361}
362
363fn pointer_token(name: &str) -> String {
365 name.replace('~', "~0").replace('/', "~1")
366}
367
368fn parse_deletion_path(query_path: &str) -> Result<Option<DeletionInfo>, JsonPathError> {
369 if query_path == "$" {
370 return Ok(Some(DeletionInfo::Root));
371 }
372
373 let JpQuery { segments } = parse_json_path(query_path)?;
374
375 if segments.is_empty() {
376 return Ok(None);
377 }
378
379 let mut parent_path = String::new();
380 let mut segments_iter = segments.iter().peekable();
381
382 while let Some(segment) = segments_iter.next() {
383 if segments_iter.peek().is_some() {
384 match segment {
386 Segment::Selector(Selector::Name(name)) => {
387 parent_path.push_str(&format!("/{}", pointer_token(name)));
388 }
389 Segment::Selector(Selector::Index(index)) => {
390 parent_path.push_str(&format!("/{}", index));
391 }
392 e => {
393 return Err(JsonPathError::InvalidJsonPath(format!(
394 "Unsupported segment to be deleted: {:?}",
395 e
396 )));
397 }
398 }
399 } else {
400 match segment {
401 Segment::Selector(Selector::Name(name)) => {
402 let field_name = name.to_string();
403 return Ok(Some(DeletionInfo::ObjectField {
404 parent_path,
405 field_name,
406 }));
407 }
408 Segment::Selector(Selector::Index(index)) => {
409 return Ok(Some(DeletionInfo::ArrayIndex {
410 parent_path,
411 index: *index as usize,
412 }));
413 }
414 e => {
415 return Err(JsonPathError::InvalidJsonPath(format!(
416 "Unsupported segment to be deleted: {:?}",
417 e
418 )));
419 }
420 }
421 }
422 }
423
424 Ok(None)
425}
426
427fn execute_deletion(value: &mut Value, deletion: &DeletionInfo) -> Queried<bool> {
428 match deletion {
429 DeletionInfo::Root => {
430 *value = Value::Null;
431 Ok(true)
432 }
433 DeletionInfo::ObjectField {
434 parent_path,
435 field_name,
436 } => {
437 let parent = if parent_path.is_empty() {
438 value
439 } else {
440 value.pointer_mut(parent_path).ok_or_else(|| {
441 JsonPathError::InvalidJsonPath("Parent path not found".to_string())
442 })?
443 };
444
445 if let Some(obj) = parent.as_object_mut() {
446 Ok(obj.remove(field_name).is_some())
447 } else {
448 Err(JsonPathError::InvalidJsonPath(
449 "Parent is not an object".to_string(),
450 ))
451 }
452 }
453 DeletionInfo::ArrayIndex { parent_path, index } => {
454 let parent = if parent_path.is_empty() {
455 value
456 } else {
457 value.pointer_mut(parent_path).ok_or_else(|| {
458 JsonPathError::InvalidJsonPath("Parent path not found".to_string())
459 })?
460 };
461
462 if let Some(arr) = parent.as_array_mut() {
463 if *index < arr.len() {
464 arr.remove(*index);
465 Ok(true)
466 } else {
467 Ok(false) }
469 } else {
470 Err(JsonPathError::InvalidJsonPath(
471 "Parent is not an array".to_string(),
472 ))
473 }
474 }
475 }
476}
477
478fn convert_js_path(path: &str) -> Parsed<String> {
479 let JpQuery { segments } = parse_json_path(path)?;
480
481 let mut path = String::new();
482 for segment in segments {
483 match segment {
484 Segment::Selector(Selector::Name(name)) => {
485 path.push_str(&format!("/{}", pointer_token(&name)));
486 }
487 Segment::Selector(Selector::Index(index)) => {
488 path.push_str(&format!("/{}", index));
489 }
490 s => {
491 return Err(JsonPathError::InvalidJsonPath(format!(
492 "Invalid segment: {:?}",
493 s
494 )));
495 }
496 }
497 }
498 Ok(path)
499}
500
501#[cfg(test)]
502mod tests {
503 use crate::parser::Parsed;
504 use crate::query::queryable::{convert_js_path, Queryable};
505 use crate::query::Queried;
506 use crate::JsonPath;
507 use serde_json::{json, Value};
508
509 #[test]
510 fn in_smoke() -> Queried<()> {
511 let json = json!({
512 "elems": ["test", "t1", "t2"],
513 "list": ["test", "test2", "test3"],
514 });
515
516 let res = json.query("$.elems[?in(@, $.list)]")?;
517
518 assert_eq!(res, [&json!("test")]);
519
520 Ok(())
521 }
522 #[test]
523 fn nin_smoke() -> Queried<()> {
524 let json = json!({
525 "elems": ["test", "t1", "t2"],
526 "list": ["test", "test2", "test3"],
527 });
528
529 let res = json.query("$.elems[?nin(@, $.list)]")?;
530
531 assert_eq!(res, [&json!("t1"), &json!("t2")]);
532
533 Ok(())
534 }
535 #[test]
536 fn none_of_smoke() -> Queried<()> {
537 let json = json!({
538 "elems": [ ["t1", "_"], ["t2", "t5"], ["t4"]],
539 "list": ["t1","t2", "t3"],
540 });
541
542 let res = json.query("$.elems[?none_of(@, $.list)]")?;
543
544 assert_eq!(res, [&json!(["t4"])]);
545
546 Ok(())
547 }
548 #[test]
549 fn any_of_smoke() -> Queried<()> {
550 let json = json!({
551 "elems": [ ["t1", "_"], ["t4", "t5"], ["t4"]],
552 "list": ["t1","t2", "t3"],
553 });
554
555 let res = json.query("$.elems[?any_of(@, $.list)]")?;
556
557 assert_eq!(res, [&json!(["t1", "_"])]);
558
559 Ok(())
560 }
561 #[test]
562 fn subset_of_smoke() -> Queried<()> {
563 let json = json!({
564 "elems": [ ["t1", "t2"], ["t4", "t5"], ["t6"]],
565 "list": ["t1","t2", "t3"],
566 });
567
568 let res = json.query("$.elems[?subset_of(@, $.list)]")?;
569
570 assert_eq!(res, [&json!(["t1", "t2"])]);
571
572 Ok(())
573 }
574
575 #[test]
576 fn convert_paths() -> Parsed<()> {
577 let r = convert_js_path("$.a.b[2]")?;
578 assert_eq!(r, "/a/b/2");
579
580 Ok(())
581 }
582
583 #[test]
584 fn test_references() -> Parsed<()> {
585 let mut json = json!({
586 "a": {
587 "b": {
588 "c": 42
589 }
590 }
591 });
592
593 let r = convert_js_path("$.a.b.c")?;
594
595 if let Some(v) = json.pointer_mut(r.as_str()) {
596 *v = json!(43);
597 }
598
599 assert_eq!(
600 json,
601 json!({
602 "a": {
603 "b": {
604 "c": 43
605 }
606 }
607 })
608 );
609
610 Ok(())
611 }
612 #[test]
613 fn test_js_reference() -> Parsed<()> {
614 let mut json = json!({
615 "a": {
616 "b": {
617 "c": 42
618 }
619 }
620 });
621
622 if let Some(path) = json.query_only_path("$.a.b.c")?.first() {
623 if let Some(v) = json.reference_mut(path) {
624 *v = json!(43);
625 }
626
627 assert_eq!(
628 json,
629 json!({
630 "a": {
631 "b": {
632 "c": 43
633 }
634 }
635 })
636 );
637 } else {
638 panic!("no path found");
639 }
640
641 Ok(())
642 }
643 #[test]
644 fn test_delete_object_field() {
645 let mut data = json!({
646 "users": {
647 "alice": {"age": 30},
648 "bob": {"age": 25}
649 }
650 });
651
652 let deleted = data.delete_by_path("$.users.alice").unwrap();
653 assert_eq!(deleted, 1);
654
655 let expected = json!({
656 "users": {
657 "bob": {"age": 25}
658 }
659 });
660 assert_eq!(data, expected);
661 }
662
663 #[test]
664 fn test_delete_array_element() {
665 let mut data = json!({
666 "numbers": [1, 2, 3, 4, 5]
667 });
668
669 let deleted = data.delete_by_path("$.numbers[2]").unwrap();
670 assert_eq!(deleted, 1);
671
672 let expected = json!({
673 "numbers": [1, 2, 4, 5]
674 });
675 assert_eq!(data, expected);
676 }
677
678 #[test]
679 fn test_delete_multiple_elements() {
680 let mut data = json!({
681 "users": [
682 {"name": "Alice", "age": 30},
683 {"name": "Bob", "age": 25},
684 {"name": "Charlie", "age": 35},
685 {"name": "David", "age": 22}
686 ]
687 });
688
689 let deleted = data.delete_by_path("$.users[?(@.age > 24)]").unwrap();
691 assert_eq!(deleted, 3);
692
693 let expected = json!({
694 "users": [
695 {"name": "David", "age": 22}
696 ]
697 });
698 assert_eq!(data, expected);
699 }
700
701 #[test]
702 fn test_delete_nested_fields() {
703 let mut data = json!({
704 "company": {
705 "departments": {
706 "engineering": {"budget": 100000},
707 "marketing": {"budget": 50000},
708 "hr": {"budget": 30000}
709 }
710 }
711 });
712
713 let deleted = data
714 .delete_by_path("$.company.departments.marketing")
715 .unwrap();
716 assert_eq!(deleted, 1);
717
718 let expected = json!({
719 "company": {
720 "departments": {
721 "engineering": {"budget": 100000},
722 "hr": {"budget": 30000}
723 }
724 }
725 });
726 assert_eq!(data, expected);
727 }
728
729 #[test]
730 fn test_delete_nonexistent_path() {
731 let mut data = json!({
732 "test": "value"
733 });
734
735 let deleted = data.delete_by_path("$.nonexistent").unwrap();
736 assert_eq!(deleted, 0);
737
738 let expected = json!({
740 "test": "value"
741 });
742 assert_eq!(data, expected);
743 }
744
745 #[test]
746 fn test_delete_root() {
747 let mut data = json!({
748 "test": "value"
749 });
750
751 let deleted = data.delete_by_path("$").unwrap();
752 assert_eq!(deleted, 1);
753 assert_eq!(data, Value::Null);
754 }
755}