From 19b0920e15d7af915e2ba9c4d47beacb4aff2a7f Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Tue, 9 May 2023 18:17:29 -0400 Subject: [PATCH] Ensure `Idiom` paths result in writeable transactions where necessary (#1957) --- lib/src/sql/array.rs | 1 + lib/src/sql/block.rs | 4 ++- lib/src/sql/constant.rs | 2 +- lib/src/sql/expression.rs | 1 + lib/src/sql/field.rs | 1 + lib/src/sql/function.rs | 1 + lib/src/sql/future.rs | 1 + lib/src/sql/id.rs | 1 + lib/src/sql/idiom.rs | 5 ++++ lib/src/sql/object.rs | 1 + lib/src/sql/param.rs | 1 + lib/src/sql/part.rs | 9 +++++++ lib/src/sql/range.rs | 1 + lib/src/sql/statement.rs | 5 ++-- lib/src/sql/statements/create.rs | 5 ++-- lib/src/sql/statements/define.rs | 11 ++++++++ lib/src/sql/statements/delete.rs | 5 ++-- lib/src/sql/statements/ifelse.rs | 3 ++- lib/src/sql/statements/info.rs | 1 + lib/src/sql/statements/insert.rs | 5 ++-- lib/src/sql/statements/kill.rs | 1 + lib/src/sql/statements/live.rs | 1 + lib/src/sql/statements/output.rs | 3 ++- lib/src/sql/statements/relate.rs | 5 ++-- lib/src/sql/statements/remove.rs | 12 +++++++++ lib/src/sql/statements/select.rs | 5 ++-- lib/src/sql/statements/set.rs | 3 ++- lib/src/sql/statements/sleep.rs | 1 + lib/src/sql/statements/update.rs | 5 ++-- lib/src/sql/subquery.rs | 3 ++- lib/src/sql/thing.rs | 1 + lib/src/sql/value/value.rs | 4 ++- lib/tests/select.rs | 43 ++++++++++++++++++++++++++++++++ 33 files changed, 130 insertions(+), 21 deletions(-) diff --git a/lib/src/sql/array.rs b/lib/src/sql/array.rs index 2fd5b79f..f2454b74 100644 --- a/lib/src/sql/array.rs +++ b/lib/src/sql/array.rs @@ -111,6 +111,7 @@ impl Array { } impl Array { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/block.rs b/lib/src/sql/block.rs index 13f7ea3e..0a0a6bf2 100644 --- a/lib/src/sql/block.rs +++ b/lib/src/sql/block.rs @@ -48,10 +48,11 @@ impl From for Block { } impl Block { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { self.iter().any(Entry::writeable) } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, @@ -189,6 +190,7 @@ impl PartialOrd for Entry { } impl Entry { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { match self { Self::Set(v) => v.writeable(), diff --git a/lib/src/sql/constant.rs b/lib/src/sql/constant.rs index 0e69aa26..c18d05e3 100644 --- a/lib/src/sql/constant.rs +++ b/lib/src/sql/constant.rs @@ -63,7 +63,7 @@ impl Constant { Self::MathTau => std::f64::consts::TAU, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, diff --git a/lib/src/sql/expression.rs b/lib/src/sql/expression.rs index c6bc49e8..ee82c973 100644 --- a/lib/src/sql/expression.rs +++ b/lib/src/sql/expression.rs @@ -60,6 +60,7 @@ impl Expression { } impl Expression { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/field.rs b/lib/src/sql/field.rs index 529417c4..88062c02 100644 --- a/lib/src/sql/field.rs +++ b/lib/src/sql/field.rs @@ -70,6 +70,7 @@ impl Display for Fields { } impl Fields { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/function.rs b/lib/src/sql/function.rs index a261bd46..85d584c2 100644 --- a/lib/src/sql/function.rs +++ b/lib/src/sql/function.rs @@ -133,6 +133,7 @@ impl Function { } impl Function { + /// Process this type returning a computed simple Value #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] pub(crate) async fn compute( diff --git a/lib/src/sql/future.rs b/lib/src/sql/future.rs index 8769fe72..a030c56b 100644 --- a/lib/src/sql/future.rs +++ b/lib/src/sql/future.rs @@ -24,6 +24,7 @@ impl From for Future { } impl Future { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/id.rs b/lib/src/sql/id.rs index 5195a610..fa3ec9e6 100644 --- a/lib/src/sql/id.rs +++ b/lib/src/sql/id.rs @@ -166,6 +166,7 @@ impl Display for Id { } impl Id { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/idiom.rs b/lib/src/sql/idiom.rs index 2970caa8..5fb00b5b 100644 --- a/lib/src/sql/idiom.rs +++ b/lib/src/sql/idiom.rs @@ -123,6 +123,11 @@ impl Idiom { } impl Idiom { + /// Check if we require a writeable transaction + pub(crate) fn writeable(&self) -> bool { + self.0.iter().any(|v| v.writeable()) + } + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/object.rs b/lib/src/sql/object.rs index cf56c4ff..65ba75e5 100644 --- a/lib/src/sql/object.rs +++ b/lib/src/sql/object.rs @@ -118,6 +118,7 @@ impl Object { } impl Object { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/param.rs b/lib/src/sql/param.rs index 147dde0d..a0bb48e0 100644 --- a/lib/src/sql/param.rs +++ b/lib/src/sql/param.rs @@ -43,6 +43,7 @@ impl Deref for Param { } impl Param { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/part.rs b/lib/src/sql/part.rs index d6f17a99..c4bebf55 100644 --- a/lib/src/sql/part.rs +++ b/lib/src/sql/part.rs @@ -89,6 +89,15 @@ impl From<&str> for Part { } impl Part { + /// Check if we require a writeable transaction + pub(crate) fn writeable(&self) -> bool { + match self { + Part::Where(v) => v.writeable(), + Part::Value(v) => v.writeable(), + Part::Method(_, v) => v.iter().any(Value::writeable), + _ => false, + } + } /// Returns a yield if an alias is specified pub(crate) fn alias(&self) -> Option<&Idiom> { match self { diff --git a/lib/src/sql/range.rs b/lib/src/sql/range.rs index 02aa3b91..3d8bf9b7 100644 --- a/lib/src/sql/range.rs +++ b/lib/src/sql/range.rs @@ -30,6 +30,7 @@ pub struct Range { } impl Range { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statement.rs b/lib/src/sql/statement.rs index a2a0ae1c..c0bf214e 100644 --- a/lib/src/sql/statement.rs +++ b/lib/src/sql/statement.rs @@ -97,6 +97,7 @@ pub enum Statement { } impl Statement { + /// Get the statement timeout duration, if any pub fn timeout(&self) -> Option { match self { Self::Create(v) => v.timeout.as_ref().map(|v| *v.0), @@ -108,7 +109,7 @@ impl Statement { _ => None, } } - + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { match self { Self::Create(v) => v.writeable(), @@ -131,7 +132,7 @@ impl Statement { _ => unreachable!(), } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/create.rs b/lib/src/sql/statements/create.rs index 14563969..1dbb12e9 100644 --- a/lib/src/sql/statements/create.rs +++ b/lib/src/sql/statements/create.rs @@ -29,10 +29,11 @@ pub struct CreateStatement { } impl CreateStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { true } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match self.what.len() { 1 if self.what[0].is_object() => true, @@ -41,7 +42,7 @@ impl CreateStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/define.rs b/lib/src/sql/statements/define.rs index 57702390..aa9211d8 100644 --- a/lib/src/sql/statements/define.rs +++ b/lib/src/sql/statements/define.rs @@ -57,6 +57,7 @@ pub enum DefineStatement { } impl DefineStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, @@ -125,6 +126,7 @@ pub struct DefineNamespaceStatement { } impl DefineNamespaceStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -175,6 +177,7 @@ pub struct DefineDatabaseStatement { } impl DefineDatabaseStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -232,6 +235,7 @@ pub struct DefineFunctionStatement { } impl DefineFunctionStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -318,6 +322,7 @@ pub struct DefineLoginStatement { } impl DefineLoginStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -442,6 +447,7 @@ pub struct DefineTokenStatement { } impl DefineTokenStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -563,6 +569,7 @@ pub struct DefineScopeStatement { } impl DefineScopeStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -683,6 +690,7 @@ pub struct DefineParamStatement { } impl DefineParamStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -933,6 +941,7 @@ pub struct DefineEventStatement { } impl DefineEventStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -1019,6 +1028,7 @@ pub struct DefineFieldStatement { } impl DefineFieldStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -1181,6 +1191,7 @@ pub struct DefineIndexStatement { } impl DefineIndexStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/delete.rs b/lib/src/sql/statements/delete.rs index 61c696d4..65bdf828 100644 --- a/lib/src/sql/statements/delete.rs +++ b/lib/src/sql/statements/delete.rs @@ -30,10 +30,11 @@ pub struct DeleteStatement { } impl DeleteStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { true } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match self.what.len() { 1 if self.what[0].is_object() => true, @@ -41,7 +42,7 @@ impl DeleteStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/ifelse.rs b/lib/src/sql/statements/ifelse.rs index 882d9e29..5834190f 100644 --- a/lib/src/sql/statements/ifelse.rs +++ b/lib/src/sql/statements/ifelse.rs @@ -20,6 +20,7 @@ pub struct IfelseStatement { } impl IfelseStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { for (cond, then) in self.exprs.iter() { if cond.writeable() || then.writeable() { @@ -28,7 +29,7 @@ impl IfelseStatement { } self.close.as_ref().map_or(false, |v| v.writeable()) } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/info.rs b/lib/src/sql/statements/info.rs index 2602515e..0c1deb06 100644 --- a/lib/src/sql/statements/info.rs +++ b/lib/src/sql/statements/info.rs @@ -24,6 +24,7 @@ pub enum InfoStatement { } impl InfoStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, diff --git a/lib/src/sql/statements/insert.rs b/lib/src/sql/statements/insert.rs index 00b6318c..e32240b3 100644 --- a/lib/src/sql/statements/insert.rs +++ b/lib/src/sql/statements/insert.rs @@ -33,10 +33,11 @@ pub struct InsertStatement { } impl InsertStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { true } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match &self.data { Data::SingleExpression(v) if v.is_object() => true, @@ -44,7 +45,7 @@ impl InsertStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/kill.rs b/lib/src/sql/statements/kill.rs index d47b2f57..bf9bdcd1 100644 --- a/lib/src/sql/statements/kill.rs +++ b/lib/src/sql/statements/kill.rs @@ -18,6 +18,7 @@ pub struct KillStatement { } impl KillStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, diff --git a/lib/src/sql/statements/live.rs b/lib/src/sql/statements/live.rs index 711e7b8b..b4b55e00 100644 --- a/lib/src/sql/statements/live.rs +++ b/lib/src/sql/statements/live.rs @@ -31,6 +31,7 @@ pub struct LiveStatement { } impl LiveStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/output.rs b/lib/src/sql/statements/output.rs index c0db7866..08cebd3b 100644 --- a/lib/src/sql/statements/output.rs +++ b/lib/src/sql/statements/output.rs @@ -20,10 +20,11 @@ pub struct OutputStatement { } impl OutputStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { self.what.writeable() } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/relate.rs b/lib/src/sql/statements/relate.rs index ee6e028b..aaf0cfa2 100644 --- a/lib/src/sql/statements/relate.rs +++ b/lib/src/sql/statements/relate.rs @@ -41,10 +41,11 @@ pub struct RelateStatement { } impl RelateStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { true } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match (&self.from, &self.with) { (v, w) if v.is_object() && w.is_object() => true, @@ -54,7 +55,7 @@ impl RelateStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/remove.rs b/lib/src/sql/statements/remove.rs index bbddad18..dad0c800 100644 --- a/lib/src/sql/statements/remove.rs +++ b/lib/src/sql/statements/remove.rs @@ -38,6 +38,7 @@ pub enum RemoveStatement { } impl RemoveStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, @@ -106,6 +107,7 @@ pub struct RemoveNamespaceStatement { } impl RemoveNamespaceStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -163,6 +165,7 @@ pub struct RemoveDatabaseStatement { } impl RemoveDatabaseStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -220,6 +223,7 @@ pub struct RemoveFunctionStatement { } impl RemoveFunctionStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -283,6 +287,7 @@ pub struct RemoveLoginStatement { } impl RemoveLoginStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -363,6 +368,7 @@ pub struct RemoveTokenStatement { } impl RemoveTokenStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -457,6 +463,7 @@ pub struct RemoveScopeStatement { } impl RemoveScopeStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -514,6 +521,7 @@ pub struct RemoveParamStatement { } impl RemoveParamStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -569,6 +577,7 @@ pub struct RemoveTableStatement { } impl RemoveTableStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -627,6 +636,7 @@ pub struct RemoveEventStatement { } impl RemoveEventStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -691,6 +701,7 @@ pub struct RemoveFieldStatement { } impl RemoveFieldStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, @@ -756,6 +767,7 @@ pub struct RemoveIndexStatement { } impl RemoveIndexStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, _ctx: &Context<'_>, diff --git a/lib/src/sql/statements/select.rs b/lib/src/sql/statements/select.rs index df6430c5..0025702a 100644 --- a/lib/src/sql/statements/select.rs +++ b/lib/src/sql/statements/select.rs @@ -46,6 +46,7 @@ pub struct SelectStatement { } impl SelectStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { if self.expr.iter().any(|v| match v { Field::All => false, @@ -59,7 +60,7 @@ impl SelectStatement { } self.cond.as_ref().map_or(false, |v| v.writeable()) } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match self.what.len() { 1 if self.what[0].is_object() => true, @@ -67,7 +68,7 @@ impl SelectStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/set.rs b/lib/src/sql/statements/set.rs index 92cc2812..1465ec8e 100644 --- a/lib/src/sql/statements/set.rs +++ b/lib/src/sql/statements/set.rs @@ -21,10 +21,11 @@ pub struct SetStatement { } impl SetStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { self.what.writeable() } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/sleep.rs b/lib/src/sql/statements/sleep.rs index 7f1895ff..aa2095c4 100644 --- a/lib/src/sql/statements/sleep.rs +++ b/lib/src/sql/statements/sleep.rs @@ -18,6 +18,7 @@ pub struct SleepStatement { } impl SleepStatement { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/update.rs b/lib/src/sql/statements/update.rs index b298b155..f2d4ea7b 100644 --- a/lib/src/sql/statements/update.rs +++ b/lib/src/sql/statements/update.rs @@ -31,10 +31,11 @@ pub struct UpdateStatement { } impl UpdateStatement { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { true } - + /// Check if this statement is for a single record pub(crate) fn single(&self) -> bool { match self.what.len() { 1 if self.what[0].is_object() => true, @@ -42,7 +43,7 @@ impl UpdateStatement { _ => false, } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/subquery.rs b/lib/src/sql/subquery.rs index ca3d528d..4638075f 100644 --- a/lib/src/sql/subquery.rs +++ b/lib/src/sql/subquery.rs @@ -46,6 +46,7 @@ impl PartialOrd for Subquery { } impl Subquery { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { match self { Self::Value(v) => v.writeable(), @@ -59,7 +60,7 @@ impl Subquery { Self::Insert(v) => v.writeable(), } } - + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/thing.rs b/lib/src/sql/thing.rs index 00c231de..fd62ae96 100644 --- a/lib/src/sql/thing.rs +++ b/lib/src/sql/thing.rs @@ -102,6 +102,7 @@ impl fmt::Display for Thing { } impl Thing { + /// Process this type returning a computed simple Value pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index 8d8494ac..fc3789f5 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -1942,9 +1942,11 @@ impl fmt::Display for Value { } impl Value { + /// Check if we require a writeable transaction pub(crate) fn writeable(&self) -> bool { match self { Value::Block(v) => v.writeable(), + Value::Idiom(v) => v.writeable(), Value::Array(v) => v.iter().any(Value::writeable), Value::Object(v) => v.iter().any(|(_, v)| v.writeable()), Value::Function(v) => v.is_custom() || v.args().iter().any(Value::writeable), @@ -1953,7 +1955,7 @@ impl Value { _ => false, } } - + /// Process this type returning a computed simple Value #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] pub(crate) async fn compute( diff --git a/lib/tests/select.rs b/lib/tests/select.rs index 00db9600..ba493d9b 100644 --- a/lib/tests/select.rs +++ b/lib/tests/select.rs @@ -64,3 +64,46 @@ async fn select_field_value() -> Result<(), Error> { // Ok(()) } + +#[tokio::test] +async fn select_writeable_subqueries() -> Result<(), Error> { + let sql = " + LET $id = (UPDATE tester:test); + RETURN $id; + LET $id = (UPDATE tester:test).id; + RETURN $id; + LET $id = (SELECT VALUE id FROM (UPDATE tester:test))[0]; + RETURN $id; + "; + let dbs = Datastore::new("memory").await?; + let ses = Session::for_kv().with_ns("test").with_db("test"); + let res = &mut dbs.execute(&sql, &ses, None, false).await?; + assert_eq!(res.len(), 6); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + "{ + id: tester:test + }", + ); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse("tester:test"); + assert_eq!(tmp, val); + // + let tmp = res.remove(0).result; + assert!(tmp.is_ok()); + // + let tmp = res.remove(0).result?; + let val = Value::parse("tester:test"); + assert_eq!(tmp, val); + // + Ok(()) +}