2023-05-06 00:15:03 +00:00
|
|
|
use crate::sql::part::Next;
|
|
|
|
use crate::sql::part::Part;
|
|
|
|
use crate::sql::value::Value;
|
|
|
|
|
|
|
|
impl Value {
|
|
|
|
/// Synchronous method for deleting a field from a `Value`
|
|
|
|
pub(crate) fn cut(&mut self, path: &[Part]) {
|
|
|
|
if let Some(p) = path.first() {
|
|
|
|
// Get the current path part
|
|
|
|
match self {
|
|
|
|
// Current path part is an object
|
|
|
|
Value::Object(v) => {
|
|
|
|
if let Part::Field(f) = p {
|
|
|
|
match path.len() {
|
|
|
|
1 => {
|
2023-05-09 17:48:14 +00:00
|
|
|
v.remove(f.as_str());
|
2023-05-06 00:15:03 +00:00
|
|
|
}
|
|
|
|
_ => {
|
2023-05-09 17:48:14 +00:00
|
|
|
if let Some(v) = v.get_mut(f.as_str()) {
|
2023-05-06 00:15:03 +00:00
|
|
|
v.cut(path.next())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Current path part is an array
|
|
|
|
Value::Array(v) => match p {
|
|
|
|
Part::All => match path.len() {
|
|
|
|
1 => {
|
|
|
|
v.clear();
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
let path = path.next();
|
|
|
|
v.iter_mut().for_each(|v| v.cut(path));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Part::First => match path.len() {
|
|
|
|
1 => {
|
|
|
|
if !v.is_empty() {
|
|
|
|
let i = 0;
|
|
|
|
v.remove(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(v) = v.first_mut() {
|
|
|
|
v.cut(path.next())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Part::Last => match path.len() {
|
|
|
|
1 => {
|
|
|
|
if !v.is_empty() {
|
|
|
|
let i = v.len() - 1;
|
|
|
|
v.remove(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(v) = v.last_mut() {
|
|
|
|
v.cut(path.next())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Part::Index(i) => match path.len() {
|
|
|
|
1 => {
|
|
|
|
if v.len().gt(&i.to_usize()) {
|
|
|
|
v.remove(i.to_usize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(v) = v.get_mut(i.to_usize()) {
|
|
|
|
v.cut(path.next())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
v.iter_mut().for_each(|v| v.cut(path));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// Ignore everything else
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
use crate::dbs::test::mock;
|
|
|
|
use crate::sql::idiom::Idiom;
|
|
|
|
use crate::sql::test::Parse;
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_none() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::default();
|
|
|
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_reset() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test");
|
|
|
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
let res = Value::parse("{ }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_basic() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something");
|
|
|
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
let res = Value::parse("{ test: { other: null } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_wrong() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something.wrong");
|
|
|
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_other() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.other.something");
|
|
|
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something[1]");
|
|
|
|
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
|
|
|
let res = Value::parse("{ test: { something: [123, 789] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array_field() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something[1].age");
|
|
|
|
let mut val = Value::parse(
|
|
|
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
|
|
|
);
|
|
|
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array_fields() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something[*].age");
|
|
|
|
let mut val = Value::parse(
|
|
|
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
|
|
|
);
|
|
|
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array_fields_flat() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something.age");
|
|
|
|
let mut val = Value::parse(
|
|
|
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
|
|
|
);
|
|
|
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array_where_field() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
|
|
|
let mut val = Value::parse(
|
|
|
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
|
|
|
);
|
|
|
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn del_array_where_fields() {
|
|
|
|
let (ctx, opt, txn) = mock().await;
|
|
|
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
|
|
|
let mut val = Value::parse(
|
|
|
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
|
|
|
);
|
|
|
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
|
|
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
|
|
|
assert_eq!(res, val);
|
|
|
|
}
|
|
|
|
}
|