Improve performance with query path analysis
Instead of creating a new Vec<_> for every embedded path part, we now use a reference when calling get/set/del on a value’s data. This means we aren’t creating and copying the Vec items each and every time we traverse down a path.
This commit is contained in:
parent
cf707bf5e3
commit
d4566ff6ea
15 changed files with 113 additions and 96 deletions
|
@ -47,11 +47,11 @@ impl<'a> Document<'a> {
|
|||
Field::All => (),
|
||||
Field::Alone(v) => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, &v.to_idiom(), x).await?;
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
|
||||
}
|
||||
Field::Alias(v, i) => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, &i, x).await?;
|
||||
out.set(ctx, opt, txn, i, x).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,11 +69,11 @@ impl<'a> Document<'a> {
|
|||
Field::All => (),
|
||||
Field::Alone(v) => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, &v.to_idiom(), x).await?;
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
|
||||
}
|
||||
Field::Alias(v, i) => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, &i, x).await?;
|
||||
out.set(ctx, opt, txn, i, x).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use nom::multi::many0;
|
|||
use nom::multi::separated_list1;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
|
@ -32,6 +33,13 @@ pub struct Idiom {
|
|||
pub parts: Vec<Part>,
|
||||
}
|
||||
|
||||
impl Deref for Idiom {
|
||||
type Target = [Part];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.parts.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Idiom {
|
||||
fn from(v: String) -> Self {
|
||||
Idiom {
|
||||
|
@ -55,13 +63,6 @@ impl Idiom {
|
|||
Idiom::from(p)
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Idiom {
|
||||
match self.parts.len() {
|
||||
0 => Idiom::from(vec![]),
|
||||
_ => Idiom::from(self.parts[1..].to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_path(&self) -> String {
|
||||
format!("/{}", self).replace(']', "").replace(&['.', '['][..], "/")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::err::Error;
|
|||
use crate::sql::error::IResult;
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Next;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
use nom::bytes::complete::tag;
|
||||
|
@ -39,10 +40,12 @@ impl Param {
|
|||
Some(Part::Field(v)) => match ctx.value::<Value>(v.name.clone()) {
|
||||
// The base variable exists
|
||||
Some(v) => {
|
||||
// Get the path parts
|
||||
let pth: &[Part] = &self.name;
|
||||
// Process the paramater value
|
||||
let res = v.compute(ctx, opt, txn, doc).await?;
|
||||
// Return the desired field
|
||||
res.get(ctx, opt, txn, &self.name.next()).await
|
||||
res.get(ctx, opt, txn, pth.next()).await
|
||||
}
|
||||
// The base variable does not exist
|
||||
None => Ok(Value::None),
|
||||
|
|
|
@ -87,6 +87,23 @@ impl fmt::Display for Part {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
pub trait Next<'a> {
|
||||
fn next(&'a self) -> &[Part];
|
||||
}
|
||||
|
||||
impl<'a> Next<'a> for &'a [Part] {
|
||||
fn next(&'a self) -> &'a [Part] {
|
||||
match self.len() {
|
||||
0 => &[],
|
||||
_ => &self[1..],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
pub fn part(i: &str) -> IResult<&str, Part> {
|
||||
alt((all, last, index, field, graph, filter))(i)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::dbs::Runtime;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Array;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
|
@ -12,7 +12,7 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
) -> Result<(), Error> {
|
||||
let val = Value::from(Array::default());
|
||||
self.set(ctx, opt, txn, path, val).await
|
||||
|
@ -24,6 +24,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
|
@ -12,7 +12,7 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, txn, path).await? {
|
||||
|
@ -40,6 +40,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,23 +2,14 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
static RID: Lazy<Idiom> = Lazy::new(|| Idiom {
|
||||
parts: vec![Part::from("id")],
|
||||
});
|
||||
|
||||
static MTB: Lazy<Idiom> = Lazy::new(|| Idiom {
|
||||
parts: vec![Part::from("meta"), Part::from("tb")],
|
||||
});
|
||||
|
||||
static MID: Lazy<Idiom> = Lazy::new(|| Idiom {
|
||||
parts: vec![Part::from("meta"), Part::from("id")],
|
||||
});
|
||||
static RID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
|
||||
static MTB: Lazy<[Part; 2]> = Lazy::new(|| [Part::from("meta"), Part::from("tb")]);
|
||||
static MID: Lazy<[Part; 2]> = Lazy::new(|| [Part::from("meta"), Part::from("id")]);
|
||||
|
||||
impl Value {
|
||||
pub async fn def(
|
||||
|
@ -32,9 +23,9 @@ impl Value {
|
|||
Some(id) => {
|
||||
let id = id.clone();
|
||||
let md = id.clone();
|
||||
self.set(ctx, opt, txn, &RID, id.into()).await?;
|
||||
self.set(ctx, opt, txn, &MTB, md.tb.into()).await?;
|
||||
self.set(ctx, opt, txn, &MID, md.id.into()).await?;
|
||||
self.set(ctx, opt, txn, RID.as_ref(), id.into()).await?;
|
||||
self.set(ctx, opt, txn, MTB.as_ref(), md.tb.into()).await?;
|
||||
self.set(ctx, opt, txn, MID.as_ref(), md.id.into()).await?;
|
||||
Ok(())
|
||||
}
|
||||
None => unreachable!(),
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::dbs::Runtime;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Abolish;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Next;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
use async_recursion::async_recursion;
|
||||
|
@ -18,20 +18,20 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
) -> Result<(), Error> {
|
||||
match path.parts.first() {
|
||||
match path.first() {
|
||||
// Get the current path part
|
||||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match path.parts.len() {
|
||||
Part::Field(f) => match path.len() {
|
||||
1 => {
|
||||
v.remove(&f.name);
|
||||
Ok(())
|
||||
}
|
||||
_ => match v.value.get_mut(&f.name) {
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -39,19 +39,19 @@ impl Value {
|
|||
},
|
||||
// Current path part is an array
|
||||
Value::Array(v) => match p {
|
||||
Part::All => match path.parts.len() {
|
||||
Part::All => match path.len() {
|
||||
1 => {
|
||||
v.value.clear();
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let pth = path.next();
|
||||
let fut = v.value.iter_mut().map(|v| v.del(&ctx, opt, txn, &pth));
|
||||
try_join_all(fut).await?;
|
||||
let path = path.next();
|
||||
let futs = v.value.iter_mut().map(|v| v.del(&ctx, opt, txn, path));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Part::First => match path.parts.len() {
|
||||
Part::First => match path.len() {
|
||||
1 => {
|
||||
if v.value.len().gt(&0) {
|
||||
v.value.remove(0);
|
||||
|
@ -59,11 +59,11 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.value.first_mut() {
|
||||
Some(v) => v.del(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
Part::Last => match path.parts.len() {
|
||||
Part::Last => match path.len() {
|
||||
1 => {
|
||||
if v.value.len().gt(&0) {
|
||||
v.value.remove(v.value.len() - 1);
|
||||
|
@ -71,25 +71,25 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.value.last_mut() {
|
||||
Some(v) => v.del(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
Part::Index(i) => match path.parts.len() {
|
||||
Part::Index(i) => match path.len() {
|
||||
1 => {
|
||||
if v.value.len().gt(&i.to_usize()) {
|
||||
v.value.remove(i.to_usize());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => match path.parts.len() {
|
||||
_ => match path.len() {
|
||||
_ => match v.value.get_mut(i.to_usize()) {
|
||||
Some(v) => v.del(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
},
|
||||
Part::Where(w) => match path.parts.len() {
|
||||
Part::Where(w) => match path.len() {
|
||||
1 => {
|
||||
let mut m = HashMap::new();
|
||||
for (i, v) in v.value.iter().enumerate() {
|
||||
|
@ -101,27 +101,26 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let pth = path.next();
|
||||
let path = path.next();
|
||||
for v in &mut v.value {
|
||||
if w.compute(ctx, opt, txn, Some(&v)).await?.is_truthy() {
|
||||
v.del(ctx, opt, txn, &pth).await?;
|
||||
v.del(ctx, opt, txn, path).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
_ => match path.parts.len() {
|
||||
_ => match path.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?;
|
||||
let futs = v.value.iter_mut().map(|v| v.del(&ctx, opt, txn, path));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
_ => Ok(()),
|
||||
},
|
||||
// Ignore everything else
|
||||
_ => Ok(()),
|
||||
|
@ -137,6 +136,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
|
@ -13,6 +12,6 @@ impl Value {
|
|||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Self, Error> {
|
||||
self.get(ctx, opt, txn, &Idiom::from(vec![Part::First])).await
|
||||
self.get(ctx, opt, txn, &[Part::First]).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::dbs::Runtime;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::field::{Field, Fields};
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Next;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::statements::select::SelectStatement;
|
||||
use crate::sql::value::{Value, Values};
|
||||
|
@ -18,15 +18,15 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
) -> Result<Self, Error> {
|
||||
match path.parts.first() {
|
||||
match path.first() {
|
||||
// Get the current path part
|
||||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Field(f) => match v.value.get(&f.name) {
|
||||
Some(v) => v.get(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
_ => Ok(Value::None),
|
||||
|
@ -34,39 +34,39 @@ impl Value {
|
|||
// Current path part is an array
|
||||
Value::Array(v) => match p {
|
||||
Part::All => {
|
||||
let pth = path.next();
|
||||
let fut = v.value.iter().map(|v| v.get(&ctx, opt, txn, &pth));
|
||||
try_join_all(fut).await.map(|v| v.into())
|
||||
let path = path.next();
|
||||
let futs = v.value.iter().map(|v| v.get(&ctx, opt, txn, path));
|
||||
try_join_all(futs).await.map(|v| v.into())
|
||||
}
|
||||
Part::First => match v.value.first() {
|
||||
Some(v) => v.get(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Last => match v.value.last() {
|
||||
Some(v) => v.get(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Index(i) => match v.value.get(i.to_usize()) {
|
||||
Some(v) => v.get(ctx, opt, txn, &path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Where(w) => {
|
||||
let pth = path.next();
|
||||
let path = path.next();
|
||||
let mut a = Vec::new();
|
||||
for v in &v.value {
|
||||
if w.compute(ctx, opt, txn, Some(&v)).await?.is_truthy() {
|
||||
a.push(v.get(ctx, opt, txn, &pth).await?)
|
||||
a.push(v.get(ctx, opt, txn, path).await?)
|
||||
}
|
||||
}
|
||||
Ok(a.into())
|
||||
}
|
||||
_ => {
|
||||
let fut = v.value.iter().map(|v| v.get(&ctx, opt, txn, &path));
|
||||
try_join_all(fut).await.map(|v| v.into())
|
||||
let futs = v.value.iter().map(|v| v.get(&ctx, opt, txn, path));
|
||||
try_join_all(futs).await.map(|v| v.into())
|
||||
}
|
||||
},
|
||||
// Current path part is a thing
|
||||
Value::Thing(v) => match path.parts.len() {
|
||||
Value::Thing(v) => match path.len() {
|
||||
// No remote embedded fields, so just return this
|
||||
0 => Ok(Value::Thing(v.clone())),
|
||||
// Remote embedded field, so fetch the thing
|
||||
|
@ -80,7 +80,7 @@ impl Value {
|
|||
.await?
|
||||
.first(ctx, opt, txn)
|
||||
.await?
|
||||
.get(ctx, opt, txn, &path)
|
||||
.get(ctx, opt, txn, path)
|
||||
.await
|
||||
}
|
||||
},
|
||||
|
@ -98,6 +98,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
use crate::sql::thing::Thing;
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
|
@ -12,7 +12,7 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, txn, path).await? {
|
||||
|
@ -41,6 +41,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
|
@ -13,6 +12,6 @@ impl Value {
|
|||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Self, Error> {
|
||||
self.get(ctx, opt, txn, &Idiom::from(vec![Part::Last])).await
|
||||
self.get(ctx, opt, txn, &[Part::Last]).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
|
@ -15,7 +16,7 @@ impl Value {
|
|||
match val.compute(ctx, opt, txn, Some(self)).await? {
|
||||
Value::Object(v) => {
|
||||
for (k, v) in v.value.into_iter() {
|
||||
self.set(ctx, opt, txn, &k.into(), v).await?;
|
||||
self.set(ctx, opt, txn, &[Part::from(k)], v).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::object::Object;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
impl Value {
|
||||
|
@ -12,7 +12,7 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
) -> Result<(), Error> {
|
||||
let val = Value::from(Object::default());
|
||||
self.set(ctx, opt, txn, path, val).await
|
||||
|
@ -24,6 +24,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Runtime;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::part::Next;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::Value;
|
||||
use async_recursion::async_recursion;
|
||||
|
@ -16,19 +16,19 @@ impl Value {
|
|||
ctx: &Runtime,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &Idiom,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match path.parts.first() {
|
||||
match path.first() {
|
||||
// Get the current path part
|
||||
Some(p) => match self {
|
||||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
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,
|
||||
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?;
|
||||
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||
v.insert(&f.name, obj);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -38,37 +38,37 @@ impl Value {
|
|||
// Current path part is an array
|
||||
Value::Array(v) => match p {
|
||||
Part::All => {
|
||||
let pth = path.next();
|
||||
let fut =
|
||||
v.value.iter_mut().map(|v| v.set(ctx, opt, txn, &pth, val.clone()));
|
||||
try_join_all(fut).await?;
|
||||
let path = path.next();
|
||||
let futs =
|
||||
v.value.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
Part::First => match v.value.first_mut() {
|
||||
Some(v) => v.set(ctx, opt, txn, &path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Last => match v.value.last_mut() {
|
||||
Some(v) => v.set(ctx, opt, txn, &path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Index(i) => match v.value.get_mut(i.to_usize()) {
|
||||
Some(v) => v.set(ctx, opt, txn, &path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Where(w) => {
|
||||
let pth = path.next();
|
||||
let path = path.next();
|
||||
for v in &mut v.value {
|
||||
if w.compute(ctx, opt, txn, Some(&v)).await?.is_truthy() {
|
||||
v.set(ctx, opt, txn, &pth, val.clone()).await?;
|
||||
v.set(ctx, opt, txn, path, val.clone()).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let fut =
|
||||
v.value.iter_mut().map(|v| v.set(ctx, opt, txn, &path, val.clone()));
|
||||
try_join_all(fut).await?;
|
||||
let futs =
|
||||
v.value.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
|
@ -99,6 +99,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use crate::dbs::test::mock;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::test::Parse;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
Loading…
Reference in a new issue