Ensure chained future values have access to current document context (#1939)

This commit is contained in:
Tobie Morgan Hitchcock 2023-05-06 07:29:42 +01:00 committed by GitHub
parent 53212b23be
commit 531e75a5b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 68 additions and 38 deletions

View file

@ -225,7 +225,7 @@ impl Iterator {
Value::Function(f) if f.is_aggregate() => {
let x = vals
.all()
.get(ctx, opt, txn, v.to_idiom().as_ref())
.get(ctx, opt, txn, None, v.to_idiom().as_ref())
.await?;
let x = f.aggregate(x).compute(ctx, opt, txn, None).await?;
obj.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
@ -241,7 +241,7 @@ impl Iterator {
if let Field::Alias(v, i) = field {
match v {
Value::Function(f) if f.is_aggregate() => {
let x = vals.all().get(ctx, opt, txn, i).await?;
let x = vals.all().get(ctx, opt, txn, None, i).await?;
let x = f.aggregate(x).compute(ctx, opt, txn, None).await?;
obj.set(ctx, opt, txn, i, x).await?;
}

View file

@ -118,7 +118,7 @@ impl Fields {
};
// Continue fetching the next idiom part
let x = x
.get(ctx, opt, txn, v)
.get(ctx, opt, txn, Some(doc), v)
.await?
.compute(ctx, opt, txn, Some(doc))
.await?
@ -174,7 +174,7 @@ impl Fields {
};
// Continue fetching the next idiom part
let x = x
.get(ctx, opt, txn, v)
.get(ctx, opt, txn, Some(doc), v)
.await?
.compute(ctx, opt, txn, Some(doc))
.await?

View file

@ -135,7 +135,7 @@ impl Idiom {
Some(Part::Value(v)) => {
v.compute(ctx, opt, txn, doc)
.await?
.get(ctx, opt, txn, self.as_ref().next())
.get(ctx, opt, txn, doc, self.as_ref().next())
.await?
.compute(ctx, opt, txn, doc)
.await
@ -143,7 +143,7 @@ impl Idiom {
// Otherwise use the current document
_ => match doc {
// There is a current document
Some(v) => v.get(ctx, opt, txn, self).await?.compute(ctx, opt, txn, doc).await,
Some(v) => v.get(ctx, opt, txn, doc, self).await?.compute(ctx, opt, txn, doc).await,
// There isn't any document
None => Ok(Value::None),
},

View file

@ -16,7 +16,7 @@ impl Value {
path: &[Part],
val: Value,
) -> Result<(), Error> {
match self.get(ctx, opt, txn, path).await? {
match self.get(ctx, opt, txn, None, path).await? {
Value::Number(v) => match val {
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
_ => Ok(()),

View file

@ -15,7 +15,7 @@ impl Value {
path: &[Part],
val: Value,
) -> Result<(), Error> {
match self.get(ctx, opt, txn, path).await? {
match self.get(ctx, opt, txn, None, path).await? {
Value::Array(v) => match val {
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
x => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,

View file

@ -94,7 +94,7 @@ impl Value {
.compute(ctx, opt, txn, None)
.await?
.all()
.get(ctx, opt, txn, path.next())
.get(ctx, opt, txn, None, path.next())
.await?
.flatten()
.ok()?;

View file

@ -23,6 +23,7 @@ impl Value {
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&'async_recursion Value>,
path: &[Part],
) -> Result<Self, Error> {
match path.first() {
@ -39,9 +40,9 @@ impl Value {
// Ensure the future is processed
let fut = &opt.futures(true);
// Get the future return value
let val = v.compute(ctx, fut, txn, None).await?;
let val = v.compute(ctx, fut, txn, doc).await?;
// Fetch the embedded field
val.get(ctx, opt, txn, path).await
val.get(ctx, opt, txn, doc, path).await
}
}
}
@ -52,42 +53,42 @@ impl Value {
Some(Value::Thing(Thing {
id: Id::Object(v),
..
})) => Value::Object(v.clone()).get(ctx, opt, txn, path.next()).await,
})) => Value::Object(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
Some(Value::Thing(Thing {
id: Id::Array(v),
..
})) => Value::Array(v.clone()).get(ctx, opt, txn, path.next()).await,
Some(v) => v.get(ctx, opt, txn, path.next()).await,
})) => Value::Array(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None),
},
Part::Graph(_) => match v.rid() {
Some(v) => Value::Thing(v).get(ctx, opt, txn, path).await,
Some(v) => Value::Thing(v).get(ctx, opt, txn, doc, path).await,
None => Ok(Value::None),
},
Part::Field(f) => match v.get(f as &str) {
Some(v) => v.get(ctx, opt, txn, path.next()).await,
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None),
},
Part::All => self.get(ctx, opt, txn, path.next()).await,
Part::All => self.get(ctx, opt, txn, doc, path.next()).await,
_ => Ok(Value::None),
},
// Current path part is an array
Value::Array(v) => match p {
Part::All => {
let path = path.next();
let futs = v.iter().map(|v| v.get(ctx, opt, txn, path));
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
try_join_all_buffered(futs).await.map(Into::into)
}
Part::First => match v.first() {
Some(v) => v.get(ctx, opt, txn, path.next()).await,
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None),
},
Part::Last => match v.last() {
Some(v) => v.get(ctx, opt, txn, path.next()).await,
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None),
},
Part::Index(i) => match v.get(i.to_usize()) {
Some(v) => v.get(ctx, opt, txn, path.next()).await,
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None),
},
Part::Where(w) => {
@ -95,13 +96,13 @@ impl Value {
let mut a = Vec::new();
for v in v.iter() {
if w.compute(ctx, opt, txn, Some(v)).await?.is_truthy() {
a.push(v.get(ctx, opt, txn, path).await?)
a.push(v.get(ctx, opt, txn, doc, path).await?)
}
}
Ok(a.into())
}
_ => {
let futs = v.iter().map(|v| v.get(ctx, opt, txn, path));
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
try_join_all_buffered(futs).await.map(Into::into)
}
},
@ -123,7 +124,7 @@ impl Value {
stm.compute(ctx, opt, txn, None)
.await?
.first()
.get(ctx, opt, txn, path)
.get(ctx, opt, txn, None, path)
.await
}
}
@ -155,7 +156,7 @@ impl Value {
.compute(ctx, opt, txn, None)
.await?
.all()
.get(ctx, opt, txn, ID.as_ref())
.get(ctx, opt, txn, None, ID.as_ref())
.await?
.flatten()
.ok(),
@ -163,7 +164,7 @@ impl Value {
.compute(ctx, opt, txn, None)
.await?
.all()
.get(ctx, opt, txn, path.next())
.get(ctx, opt, txn, None, path.next())
.await?
.flatten()
.ok(),
@ -179,7 +180,7 @@ impl Value {
stm.compute(ctx, opt, txn, None)
.await?
.first()
.get(ctx, opt, txn, path)
.get(ctx, opt, txn, None, path)
.await
}
},
@ -209,7 +210,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::default();
let val = Value::parse("{ test: { other: null, something: 123 } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, val);
}
@ -218,7 +219,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something");
let val = Value::parse("{ test: { other: null, something: 123 } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(123));
}
@ -227,7 +228,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other");
let val = Value::parse("{ test: { other: test:tobie, something: 123 } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(
res,
Value::from(Thing {
@ -242,7 +243,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]");
let val = Value::parse("{ test: { something: [123, 456, 789] } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(456));
}
@ -251,7 +252,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]");
let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(
res,
Value::from(Thing {
@ -266,7 +267,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1].age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(36));
}
@ -275,7 +276,7 @@ mod tests {
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();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(vec![34, 36]));
}
@ -284,7 +285,7 @@ mod tests {
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();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(vec![34, 36]));
}
@ -293,7 +294,7 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[WHERE age > 35].age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(res, Value::from(vec![36]));
}
@ -302,7 +303,36 @@ mod tests {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = val.get(&ctx, &opt, &txn, &idi).await.unwrap();
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(
res,
Value::from(vec![Value::from(map! {
"age".to_string() => Value::from(36),
})])
);
}
#[tokio::test]
async fn get_future_embedded_field() {
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: <future> { { something: [{ age: 34 }, { age: 36 }] } } }");
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
assert_eq!(
res,
Value::from(vec![Value::from(map! {
"age".to_string() => Value::from(36),
})])
);
}
#[tokio::test]
async fn get_future_embedded_field_with_reference() {
let (ctx, opt, txn) = mock().await;
let doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }");
let idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: <future> { { something: something } } }");
let res = val.get(&ctx, &opt, &txn, Some(&doc), &idi).await.unwrap();
assert_eq!(
res,
Value::from(vec![Value::from(map! {

View file

@ -16,7 +16,7 @@ impl Value {
path: &[Part],
val: Value,
) -> Result<(), Error> {
match self.get(ctx, opt, txn, path).await? {
match self.get(ctx, opt, txn, None, path).await? {
Value::Number(v) => match val {
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
_ => Ok(()),