11use crate :: parser:: errors:: JsonPathError ;
22use crate :: parser:: model:: { JpQuery , Segment , Selector } ;
33use crate :: parser:: { parse_json_path, Parsed } ;
4- use crate :: query:: QueryPath ;
4+ use crate :: query:: { QueryPath , Queried } ;
55use crate :: JsonPath ;
66use serde_json:: Value ;
77use std:: borrow:: Cow ;
@@ -139,6 +139,37 @@ where
139139 {
140140 None
141141 }
142+
143+ /// Deletes all elements matching the given JSONPath
144+ ///
145+ /// # Arguments
146+ /// * `path` - JSONPath string specifying elements to delete
147+ ///
148+ /// # Returns
149+ /// * `Ok(usize)` - Number of elements deleted
150+ /// * `Err(JsonPathError)` - If the path is invalid or deletion fails
151+ ///
152+ /// # Examples
153+ /// ```
154+ /// use serde_json::json;
155+ /// use jsonpath_rust::JsonPath;
156+ /// use crate::jsonpath_rust::query::queryable::Queryable;
157+ ///
158+ /// let mut data = json!({
159+ /// "users": [
160+ /// {"name": "Alice", "age": 30},
161+ /// {"name": "Bob", "age": 25},
162+ /// {"name": "Charlie", "age": 35}
163+ /// ]
164+ /// });
165+ ///
166+ /// // Delete users older than 30
167+ /// let deleted = data.delete_by_path("$.users[?(@.age > 30)]").unwrap();
168+ /// assert_eq!(deleted, 1);
169+ /// ```
170+ fn delete_by_path ( & mut self , _path : & str ) -> Queried < usize > {
171+ Err ( JsonPathError :: InvalidJsonPath ( "Deletion not supported" . to_string ( ) ) )
172+ }
142173}
143174
144175impl Queryable for Value {
@@ -280,119 +311,35 @@ impl Queryable for Value {
280311 . ok ( )
281312 . and_then ( |p| self . pointer_mut ( p. as_str ( ) ) )
282313 }
283- }
284-
285- fn convert_js_path ( path : & str ) -> Parsed < String > {
286- let JpQuery { segments } = parse_json_path ( path) ?;
287-
288- let mut path = String :: new ( ) ;
289- for segment in segments {
290- match segment {
291- Segment :: Selector ( Selector :: Name ( name) ) => {
292- path. push_str ( & format ! ( "/{}" , name. trim_matches( |c| c == '\'' ) ) ) ;
293- }
294- Segment :: Selector ( Selector :: Index ( index) ) => {
295- path. push_str ( & format ! ( "/{}" , index) ) ;
296- }
297- s => {
298- return Err ( JsonPathError :: InvalidJsonPath ( format ! (
299- "Invalid segment: {:?}" ,
300- s
301- ) ) ) ;
302- }
303- }
304- }
305- Ok ( path)
306- }
307-
308- pub trait QueryableDeletable : Queryable {
309- /// Deletes all elements matching the given JSONPath
310- ///
311- /// # Arguments
312- /// * `path` - JSONPath string specifying elements to delete
313- ///
314- /// # Returns
315- /// * `Ok(usize)` - Number of elements deleted
316- /// * `Err(JsonPathError)` - If the path is invalid or deletion fails
317- ///
318- /// # Examples
319- /// ```
320- /// use serde_json::json;
321- /// use crate::jsonpath_rust::query::queryable::QueryableDeletable;
322- /// use jsonpath_rust::JsonPath;
323- ///
324- /// let mut data = json!({
325- /// "users": [
326- /// {"name": "Alice", "age": 30},
327- /// {"name": "Bob", "age": 25},
328- /// {"name": "Charlie", "age": 35}
329- /// ]
330- /// });
331- ///
332- /// // Delete users older than 30
333- /// let deleted = data.delete_by_path("$.users[?(@.age > 30)]").unwrap();
334- /// assert_eq!(deleted, 1);
335- /// ```
336- fn delete_by_path ( & mut self , path : & str ) -> Result < usize , JsonPathError > ;
337-
338- /// Deletes a single element at the given path
339- /// Returns true if an element was deleted, false otherwise
340- fn delete_single ( & mut self , path : & str ) -> Result < bool , JsonPathError > ;
341- }
342314
343- impl QueryableDeletable for Value {
344- fn delete_by_path ( & mut self , path : & str ) -> Result < usize , JsonPathError > {
345-
346- let matching_paths = self . query_only_path ( path)
347- . map_err ( |_| JsonPathError :: InvalidJsonPath ( "Failed to query path" . to_string ( ) ) ) ?;
348-
349- if matching_paths. is_empty ( ) {
350- return Ok ( 0 ) ;
351- }
352-
315+ fn delete_by_path ( & mut self , path : & str ) -> Queried < usize > {
353316 let mut deletions = Vec :: new ( ) ;
354- for query_path in & matching_paths {
317+ for query_path in & self . query_only_path ( path ) ? {
355318 if let Some ( deletion_info) = parse_deletion_path ( query_path) ? {
356319 deletions. push ( deletion_info) ;
357320 }
358321 }
359322
360323 // Sort deletions to handle array indices correctly (delete from end to start)
361- deletions. sort_by ( |a, b| {
362- // First sort by path depth (deeper paths first)
363- let depth_cmp = b. path_depth ( ) . cmp ( & a. path_depth ( ) ) ;
364- if depth_cmp != std:: cmp:: Ordering :: Equal {
365- return depth_cmp;
366- }
367-
368- // Then by array index (higher indices first)
369- match ( a, b) {
370- ( DeletionInfo :: ArrayIndex { index : idx_a, .. } ,
371- DeletionInfo :: ArrayIndex { index : idx_b, .. } ) => {
372- idx_b. cmp ( idx_a)
324+ deletions. sort_by ( |a, b|
325+ b. path_depth ( ) . cmp ( & a. path_depth ( ) ) . then_with ( || {
326+ match ( a, b) {
327+ (
328+ DeletionInfo :: ArrayIndex { index : idx_a, .. } ,
329+ DeletionInfo :: ArrayIndex { index : idx_b, .. } ,
330+ ) => idx_b. cmp ( idx_a) ,
331+ _ => std:: cmp:: Ordering :: Equal ,
373332 }
374- _ => std:: cmp:: Ordering :: Equal
375- }
376- } ) ;
333+ } )
334+ ) ;
377335
378336 // Perform deletions
379- let mut deleted_count = 0 ;
380- for deletion in deletions {
381- if execute_deletion ( self , & deletion) ? {
382- deleted_count += 1 ;
383- }
384- }
337+ let deleted_count = deletions
338+ . iter ( )
339+ . try_fold ( 0 , |c, d| execute_deletion ( self , d) . map ( |deleted| if deleted { c + 1 } else { c } ) ) ?;
385340
386341 Ok ( deleted_count)
387342 }
388-
389- fn delete_single ( & mut self , path : & str ) -> Result < bool , JsonPathError > {
390- if let Some ( deletion_info) = parse_deletion_path ( path) ? {
391- execute_deletion ( self , & deletion_info)
392- } else {
393- Ok ( false )
394- }
395- }
396343}
397344
398345#[ derive( Debug , Clone ) ]
@@ -444,10 +391,11 @@ fn parse_deletion_path(query_path: &str) -> Result<Option<DeletionInfo>, JsonPat
444391 Segment :: Selector ( Selector :: Index ( index) ) => {
445392 parent_path. push_str ( & format ! ( "/{}" , index) ) ;
446393 }
447- _ => {
448- return Err ( JsonPathError :: InvalidJsonPath (
449- "Unsupported segment type for deletion" . to_string ( )
450- ) ) ;
394+ e => {
395+ return Err ( JsonPathError :: InvalidJsonPath ( format ! (
396+ "Unsupported segment to be deleted: {:?}" ,
397+ e
398+ ) ) ) ;
451399 }
452400 }
453401 } else {
@@ -465,10 +413,11 @@ fn parse_deletion_path(query_path: &str) -> Result<Option<DeletionInfo>, JsonPat
465413 index : * index as usize ,
466414 } ) ) ;
467415 }
468- _ => {
469- return Err ( JsonPathError :: InvalidJsonPath (
470- "Unsupported final segment for deletion" . to_string ( )
471- ) ) ;
416+ e => {
417+ return Err ( JsonPathError :: InvalidJsonPath ( format ! (
418+ "Unsupported segment to be deleted: {:?}" ,
419+ e
420+ ) ) ) ;
472421 }
473422 }
474423 }
@@ -477,7 +426,7 @@ fn parse_deletion_path(query_path: &str) -> Result<Option<DeletionInfo>, JsonPat
477426 Ok ( None )
478427}
479428
480- fn execute_deletion ( value : & mut Value , deletion : & DeletionInfo ) -> Result < bool , JsonPathError > {
429+ fn execute_deletion ( value : & mut Value , deletion : & DeletionInfo ) -> Queried < bool > {
481430 match deletion {
482431 DeletionInfo :: Root => {
483432 * value = Value :: Null ;
@@ -525,10 +474,33 @@ fn execute_deletion(value: &mut Value, deletion: &DeletionInfo) -> Result<bool,
525474 }
526475}
527476
477+ fn convert_js_path ( path : & str ) -> Parsed < String > {
478+ let JpQuery { segments } = parse_json_path ( path) ?;
479+
480+ let mut path = String :: new ( ) ;
481+ for segment in segments {
482+ match segment {
483+ Segment :: Selector ( Selector :: Name ( name) ) => {
484+ path. push_str ( & format ! ( "/{}" , name. trim_matches( |c| c == '\'' ) ) ) ;
485+ }
486+ Segment :: Selector ( Selector :: Index ( index) ) => {
487+ path. push_str ( & format ! ( "/{}" , index) ) ;
488+ }
489+ s => {
490+ return Err ( JsonPathError :: InvalidJsonPath ( format ! (
491+ "Invalid segment: {:?}" ,
492+ s
493+ ) ) ) ;
494+ }
495+ }
496+ }
497+ Ok ( path)
498+ }
499+
528500#[ cfg( test) ]
529501mod tests {
530502 use crate :: parser:: Parsed ;
531- use crate :: query:: queryable:: { convert_js_path, Queryable , QueryableDeletable } ;
503+ use crate :: query:: queryable:: { convert_js_path, Queryable } ;
532504 use crate :: query:: Queried ;
533505 use crate :: JsonPath ;
534506 use serde_json:: { json, Value } ;
@@ -773,8 +745,8 @@ mod tests {
773745 "test" : "value"
774746 } ) ;
775747
776- let deleted = data. delete_single ( "$" ) . unwrap ( ) ;
777- assert_eq ! ( deleted, true ) ;
748+ let deleted = data. delete_by_path ( "$" ) . unwrap ( ) ;
749+ assert_eq ! ( deleted, 1 ) ;
778750 assert_eq ! ( data, Value :: Null ) ;
779751 }
780- }
752+ }
0 commit comments