mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 08:55:40 +01:00
remove and replace functions defenitions
This commit is contained in:
@@ -84,6 +84,9 @@ pub enum JsonFunc {
|
||||
JsonValid,
|
||||
JsonPatch,
|
||||
JsonRemove,
|
||||
JsonbRemove,
|
||||
JsonReplace,
|
||||
JsonbReplace,
|
||||
JsonPretty,
|
||||
JsonSet,
|
||||
JsonQuote,
|
||||
@@ -110,6 +113,9 @@ impl Display for JsonFunc {
|
||||
Self::JsonValid => "json_valid".to_string(),
|
||||
Self::JsonPatch => "json_patch".to_string(),
|
||||
Self::JsonRemove => "json_remove".to_string(),
|
||||
Self::JsonbRemove => "jsonb_remove".to_string(),
|
||||
Self::JsonReplace => "json_replace".to_string(),
|
||||
Self::JsonbReplace => "jsonb_replace".to_string(),
|
||||
Self::JsonPretty => "json_pretty".to_string(),
|
||||
Self::JsonSet => "json_set".to_string(),
|
||||
Self::JsonQuote => "json_quote".to_string(),
|
||||
@@ -575,6 +581,12 @@ impl Func {
|
||||
#[cfg(feature = "json")]
|
||||
"json_remove" => Ok(Self::Json(JsonFunc::JsonRemove)),
|
||||
#[cfg(feature = "json")]
|
||||
"jsonb_remove" => Ok(Self::Json(JsonFunc::JsonbRemove)),
|
||||
#[cfg(feature = "json")]
|
||||
"json_replace" => Ok(Self::Json(JsonFunc::JsonReplace)),
|
||||
#[cfg(feature = "json")]
|
||||
"jsonb_replace" => Ok(Self::Json(JsonFunc::JsonReplace)),
|
||||
#[cfg(feature = "json")]
|
||||
"json_pretty" => Ok(Self::Json(JsonFunc::JsonPretty)),
|
||||
#[cfg(feature = "json")]
|
||||
"json_set" => Ok(Self::Json(JsonFunc::JsonSet)),
|
||||
|
||||
152
core/json/mod.rs
152
core/json/mod.rs
@@ -8,7 +8,9 @@ mod ser;
|
||||
use crate::bail_constraint_error;
|
||||
pub use crate::json::de::from_str;
|
||||
use crate::json::error::Error as JsonError;
|
||||
pub use crate::json::json_operations::{json_patch, json_remove};
|
||||
pub use crate::json::json_operations::{
|
||||
json_patch, json_remove, json_replace, jsonb_remove, jsonb_replace,
|
||||
};
|
||||
use crate::json::json_path::{json_path, JsonPath, PathElement};
|
||||
pub use crate::json::ser::to_string;
|
||||
use crate::types::{OwnedValue, Text, TextSubtype};
|
||||
@@ -501,60 +503,6 @@ enum Target<'a> {
|
||||
Value(&'a mut Val),
|
||||
}
|
||||
|
||||
fn mutate_json_by_path<F, R>(json: &mut Val, path: JsonPath, closure: F) -> Option<R>
|
||||
where
|
||||
F: FnMut(Target) -> R,
|
||||
{
|
||||
find_target(json, &path).map(closure)
|
||||
}
|
||||
|
||||
fn find_target<'a>(json: &'a mut Val, path: &JsonPath) -> Option<Target<'a>> {
|
||||
let mut current = json;
|
||||
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) => {
|
||||
if let Some(index) = match index {
|
||||
Some(i) if *i < 0 => arr.len().checked_sub(i.unsigned_abs() as usize),
|
||||
Some(i) => ((*i as usize) < arr.len()).then_some(*i as usize),
|
||||
None => Some(arr.len()),
|
||||
} {
|
||||
if is_last {
|
||||
return Some(Target::Array(arr, index));
|
||||
} else {
|
||||
current = &mut arr[index];
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
PathElement::Key(key, _) => match current {
|
||||
Val::Object(obj) => {
|
||||
if let Some(pos) = &obj
|
||||
.iter()
|
||||
.position(|(k, v)| k == key && !matches!(v, Val::Removed))
|
||||
{
|
||||
let val = &mut obj[*pos].1;
|
||||
current = val;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Some(Target::Value(current))
|
||||
}
|
||||
|
||||
fn create_and_mutate_json_by_path<F, R>(json: &mut Val, path: JsonPath, closure: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(Target) -> R,
|
||||
@@ -1235,100 +1183,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_target_array() {
|
||||
let mut val = Val::Array(vec![
|
||||
Val::String("first".to_string()),
|
||||
Val::String("second".to_string()),
|
||||
]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::ArrayLocator(Some(0))],
|
||||
};
|
||||
|
||||
match find_target(&mut val, &path) {
|
||||
Some(Target::Array(_, idx)) => assert_eq!(idx, 0),
|
||||
_ => panic!("Expected Array target"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_target_negative_index() {
|
||||
let mut val = Val::Array(vec![
|
||||
Val::String("first".to_string()),
|
||||
Val::String("second".to_string()),
|
||||
]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::ArrayLocator(Some(-1))],
|
||||
};
|
||||
|
||||
match find_target(&mut val, &path) {
|
||||
Some(Target::Array(_, idx)) => assert_eq!(idx, 1),
|
||||
_ => panic!("Expected Array target"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_target_object() {
|
||||
let mut val = Val::Object(vec![("key".to_string(), Val::String("value".to_string()))]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::Key(Cow::Borrowed("key"), false)],
|
||||
};
|
||||
|
||||
match find_target(&mut val, &path) {
|
||||
Some(Target::Value(_)) => {}
|
||||
_ => panic!("Expected Value target"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_target_removed() {
|
||||
let mut val = Val::Object(vec![
|
||||
("key".to_string(), Val::Removed),
|
||||
("key".to_string(), Val::String("value".to_string())),
|
||||
]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::Key(Cow::Borrowed("key"), false)],
|
||||
};
|
||||
|
||||
match find_target(&mut val, &path) {
|
||||
Some(Target::Value(val)) => assert!(matches!(val, Val::String(_))),
|
||||
_ => panic!("Expected second value, not removed"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_json() {
|
||||
let mut val = Val::Array(vec![Val::String("test".to_string())]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::ArrayLocator(Some(0))],
|
||||
};
|
||||
|
||||
let result = mutate_json_by_path(&mut val, path, |target| match target {
|
||||
Target::Array(arr, idx) => {
|
||||
arr.remove(idx);
|
||||
"removed"
|
||||
}
|
||||
_ => panic!("Expected Array target"),
|
||||
});
|
||||
|
||||
assert_eq!(result, Some("removed"));
|
||||
assert!(matches!(val, Val::Array(arr) if arr.is_empty()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutate_json_none() {
|
||||
let mut val = Val::Array(vec![]);
|
||||
let path = JsonPath {
|
||||
elements: vec![PathElement::ArrayLocator(Some(0))],
|
||||
};
|
||||
|
||||
let result: Option<()> = mutate_json_by_path(&mut val, path, |_| {
|
||||
panic!("Should not be called");
|
||||
});
|
||||
|
||||
assert_eq!(result, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_path_from_owned_value_root_strict() {
|
||||
let path = OwnedValue::Text(Text::new("$"));
|
||||
|
||||
@@ -897,7 +897,10 @@ pub fn translate_expr(
|
||||
JsonFunc::JsonArray
|
||||
| JsonFunc::JsonExtract
|
||||
| JsonFunc::JsonSet
|
||||
| JsonFunc::JsonbExtract => translate_function(
|
||||
| JsonFunc::JsonbExtract
|
||||
| JsonFunc::JsonReplace
|
||||
| JsonFunc::JsonbReplace
|
||||
| JsonFunc::JsonbRemove => translate_function(
|
||||
program,
|
||||
args.as_deref().unwrap_or_default(),
|
||||
referenced_tables,
|
||||
|
||||
@@ -52,8 +52,8 @@ use crate::{
|
||||
function::JsonFunc, json::get_json, json::is_json_valid, json::json_array,
|
||||
json::json_array_length, json::json_arrow_extract, json::json_arrow_shift_extract,
|
||||
json::json_error_position, json::json_extract, json::json_object, json::json_patch,
|
||||
json::json_quote, json::json_remove, json::json_set, json::json_type, json::jsonb,
|
||||
json::jsonb_extract,
|
||||
json::json_quote, json::json_remove, json::json_replace, json::json_set, json::json_type,
|
||||
json::jsonb, json::jsonb_extract, json::jsonb_remove, json::jsonb_replace,
|
||||
};
|
||||
use crate::{info, CheckpointStatus};
|
||||
use crate::{
|
||||
@@ -2192,6 +2192,7 @@ impl Program {
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
JsonFunc::JsonArrowExtract | JsonFunc::JsonArrowShiftExtract => {
|
||||
assert_eq!(arg_count, 2);
|
||||
let json = &state.registers[*start_reg];
|
||||
@@ -2250,6 +2251,21 @@ impl Program {
|
||||
&state.registers[*start_reg..*start_reg + arg_count],
|
||||
)?;
|
||||
}
|
||||
JsonFunc::JsonbRemove => {
|
||||
state.registers[*dest] = jsonb_remove(
|
||||
&state.registers[*start_reg..*start_reg + arg_count],
|
||||
)?;
|
||||
}
|
||||
JsonFunc::JsonReplace => {
|
||||
state.registers[*dest] = json_replace(
|
||||
&state.registers[*start_reg..*start_reg + arg_count],
|
||||
)?;
|
||||
}
|
||||
JsonFunc::JsonbReplace => {
|
||||
state.registers[*dest] = jsonb_replace(
|
||||
&state.registers[*start_reg..*start_reg + arg_count],
|
||||
)?;
|
||||
}
|
||||
JsonFunc::JsonPretty => {
|
||||
let json_value = &state.registers[*start_reg];
|
||||
let indent = if arg_count > 1 {
|
||||
|
||||
Reference in New Issue
Block a user