diff --git a/core/json/json_operations.rs b/core/json/json_operations.rs index edbdfc9ba..70f7af689 100644 --- a/core/json/json_operations.rs +++ b/core/json/json_operations.rs @@ -1,6 +1,9 @@ use std::collections::VecDeque; -use crate::types::OwnedValue; +use crate::{ + json::{mutate_json_by_path, Target}, + types::OwnedValue, +}; use super::{convert_json_to_db_type, get_json_value, json_path::json_path, Val}; @@ -167,9 +170,17 @@ pub fn json_remove(args: &[OwnedValue]) -> crate::Result { }) .collect(); let paths = paths?; - println!("{:?}", paths); - Ok(OwnedValue::Null) + for path in paths { + mutate_json_by_path(&mut parsed_target, path, |val| match val { + Target::Array(arr, index) => { + arr.remove(index); + } + Target::Value(val) => *val = Val::Removed, + }); + } + + convert_json_to_db_type(&parsed_target, false) } #[cfg(test)] diff --git a/core/json/mod.rs b/core/json/mod.rs index 40753c392..b4665baf5 100644 --- a/core/json/mod.rs +++ b/core/json/mod.rs @@ -4,7 +4,7 @@ mod json_operations; mod json_path; mod ser; -use std::{ops::Mul, rc::Rc}; +use std::rc::Rc; pub use crate::json::de::from_str; use crate::json::de::ordered_object; @@ -404,19 +404,23 @@ fn json_extract_single<'a>( Ok(Some(current_element)) } -fn operate_on_json_by_path(json: &mut Val, path: JsonPath, mut closure: F) -where - F: FnMut(&mut Val) -> (), -{ - if let Some(target) = find_target(json, &path) { - closure(target); - } +enum Target<'a> { + Array(&'a mut Vec, usize), + Value(&'a mut Val), } -fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option<&'a mut Val> { +fn mutate_json_by_path(json: &mut Val, path: JsonPath, mut closure: F) -> Option +where + F: FnMut(Target) -> R, +{ + find_target(json, &path).map(|target| closure(target)) +} + +fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option> { let mut current = json; - for key in path.elements { - match &key { + for (i, key) in path.elements.iter().enumerate() { + let is_last = i == path.elements.len() - 1; + match key { PathElement::Root() => continue, PathElement::ArrayLocator(index) => match current { Val::Array(arr) => { @@ -424,7 +428,11 @@ fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option<&'a mut Val> { i if *i < 0 => arr.len().checked_sub(i.abs() as usize), i => ((*i as usize) < arr.len()).then_some(*i as usize), } { - current = &mut arr[index]; + if is_last { + return Some(Target::Array(arr, index)); + } else { + current = &mut arr[index]; + } } else { return None; } @@ -435,7 +443,10 @@ fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option<&'a mut Val> { }, PathElement::Key(key) => match current { Val::Object(obj) => { - if let Some(pos) = &obj.iter().position(|(obj_key, _)| &key == obj_key) { + if let Some(pos) = &obj + .iter() + .position(|(k, v)| k == key && !matches!(v, Val::Removed)) + { let val = &mut obj[*pos].1; current = val; } else { @@ -448,7 +459,7 @@ fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option<&'a mut Val> { }, } } - return Some(current); + return Some(Target::Value(current)); } pub fn json_error_position(json: &OwnedValue) -> crate::Result {