From c28057f8ef31f3923411580d74627bcce2b329a7 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Tue, 22 Feb 2022 16:33:43 +0000 Subject: [PATCH] Allow flat query expressions Instead of having to specify [*] or * to get/set/del values in embedded arrays, it now supports access embedded values using a flat style for arrays. --- lib/src/sql/value/del.rs | 27 ++++++++++++++++++++++++--- lib/src/sql/value/get.rs | 16 ++++++++++++++-- lib/src/sql/value/set.rs | 21 ++++++++++++++++++--- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/lib/src/sql/value/del.rs b/lib/src/sql/value/del.rs index 23ce520d..0bf6800f 100644 --- a/lib/src/sql/value/del.rs +++ b/lib/src/sql/value/del.rs @@ -25,12 +25,12 @@ impl Value { Some(p) => match self { // Current path part is an object Value::Object(v) => match p { - Part::Field(p) => match path.parts.len() { + Part::Field(f) => match path.parts.len() { 1 => { - v.remove(&p.name); + v.remove(&f.name); Ok(()) } - _ => match v.value.get_mut(&p.name) { + _ => match v.value.get_mut(&f.name) { Some(v) if v.is_some() => v.del(ctx, opt, txn, &path.next()).await, _ => Ok(()), }, @@ -110,6 +110,17 @@ impl Value { Ok(()) } }, + _ => match path.parts.len() { + 1 => { + v.value.clear(); + Ok(()) + } + _ => { + let fut = v.value.iter_mut().map(|v| v.del(&ctx, opt, txn, &path)); + try_join_all(fut).await?; + Ok(()) + } + }, _ => Ok(()), }, // Ignore everything else @@ -208,6 +219,16 @@ mod tests { 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: [{ age: 34 }, { age: 36 }] } }"); + let res = Value::parse("{ test: { something: [{ }, { }] } }"); + 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; diff --git a/lib/src/sql/value/get.rs b/lib/src/sql/value/get.rs index d3227aef..a9daf72e 100644 --- a/lib/src/sql/value/get.rs +++ b/lib/src/sql/value/get.rs @@ -25,7 +25,7 @@ impl Value { Some(p) => match self { // Current path part is an object Value::Object(v) => match p { - Part::Field(p) => match v.value.get(&p.name) { + Part::Field(f) => match v.value.get(&f.name) { Some(v) => v.get(ctx, opt, txn, &path.next()).await, None => Ok(Value::None), }, @@ -60,7 +60,10 @@ impl Value { } Ok(a.into()) } - _ => Ok(Value::None), + _ => { + let fut = v.value.iter().map(|v| v.get(&ctx, opt, txn, &path)); + try_join_all(fut).await.map(|v| v.into()) + } }, // Current path part is a thing Value::Thing(v) => match path.parts.len() { @@ -173,6 +176,15 @@ mod tests { assert_eq!(res, Value::from(vec![34, 36])); } + #[tokio::test] + async fn get_array_fields_flat() { + let (ctx, opt, txn) = mock().await; + let idi = Idiom::parse("test.something.age"); + let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); + let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap(); + assert_eq!(res, Value::from(vec![34, 36])); + } + #[tokio::test] async fn get_array_where_field() { let (ctx, opt, txn) = mock().await; diff --git a/lib/src/sql/value/set.rs b/lib/src/sql/value/set.rs index 0c577d00..c12e1f11 100644 --- a/lib/src/sql/value/set.rs +++ b/lib/src/sql/value/set.rs @@ -24,12 +24,12 @@ impl Value { Some(p) => match self { // Current path part is an object Value::Object(v) => match p { - Part::Field(p) => match v.value.get_mut(&p.name) { + Part::Field(f) => match v.value.get_mut(&f.name) { Some(v) if v.is_some() => v.set(ctx, opt, txn, &path.next(), val).await, _ => { let mut obj = Value::base(); obj.set(ctx, opt, txn, &path.next(), val).await?; - v.insert(&p.name, obj); + v.insert(&f.name, obj); Ok(()) } }, @@ -65,7 +65,12 @@ impl Value { } Ok(()) } - _ => Ok(()), + _ => { + let fut = + v.value.iter_mut().map(|v| v.set(ctx, opt, txn, &path, val.clone())); + try_join_all(fut).await?; + Ok(()) + } }, // Current path part is empty Value::Null => { @@ -206,6 +211,16 @@ mod tests { assert_eq!(res, val); } + #[tokio::test] + async fn set_array_fields_flat() { + let (ctx, opt, txn) = mock().await; + let idi = Idiom::parse("test.something.age"); + let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); + let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }"); + val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap(); + assert_eq!(res, val); + } + #[tokio::test] async fn set_array_where_field() { let (ctx, opt, txn) = mock().await;