From e9eeb9aca740ec0454b19f74d2de54451f154dff Mon Sep 17 00:00:00 2001 From: Emmanuel Keller Date: Thu, 6 Jul 2023 15:57:42 +0100 Subject: [PATCH] QueryPlanner / indexing / Context / Cursor doc (#2229) --- Cargo.lock | 1 - lib/Cargo.toml | 1 - lib/src/ctx/context.rs | 62 --- lib/src/dbs/channel.rs | 497 ------------------ lib/src/dbs/executor.rs | 19 +- lib/src/dbs/iterator.rs | 91 ++-- lib/src/dbs/mod.rs | 8 +- lib/src/dbs/{iterate.rs => processor.rs} | 190 ++++--- lib/src/dbs/test.rs | 9 +- lib/src/doc/allow.rs | 11 +- lib/src/doc/alter.rs | 65 +-- lib/src/doc/check.rs | 7 +- lib/src/doc/clean.rs | 17 +- lib/src/doc/compute.rs | 24 +- lib/src/doc/create.rs | 27 +- lib/src/doc/delete.rs | 19 +- lib/src/doc/document.rs | 40 +- lib/src/doc/edges.rs | 15 +- lib/src/doc/empty.rs | 4 +- lib/src/doc/erase.rs | 2 +- lib/src/doc/event.rs | 18 +- lib/src/doc/exist.rs | 5 +- lib/src/doc/field.rs | 26 +- lib/src/doc/index.rs | 26 +- lib/src/doc/insert.rs | 53 +- lib/src/doc/lives.rs | 13 +- lib/src/doc/merge.rs | 13 +- lib/src/doc/pluck.rs | 68 +-- lib/src/doc/purge.rs | 15 +- lib/src/doc/relate.rs | 29 +- lib/src/doc/reset.rs | 12 +- lib/src/doc/select.rs | 11 +- lib/src/doc/store.rs | 9 +- lib/src/doc/table.rs | 107 ++-- lib/src/doc/update.rs | 29 +- lib/src/fnc/mod.rs | 26 +- lib/src/fnc/operate.rs | 21 +- lib/src/fnc/script/main.rs | 9 +- .../script/modules/surrealdb/functions/mod.rs | 2 +- lib/src/fnc/search.rs | 63 ++- lib/src/idx/bkeys.rs | 2 - lib/src/idx/btree.rs | 119 ++--- lib/src/idx/ft/docids.rs | 22 +- lib/src/idx/ft/doclength.rs | 23 +- lib/src/idx/ft/postings.rs | 22 +- lib/src/idx/ft/terms.rs | 22 +- lib/src/idx/planner/executor.rs | 6 +- lib/src/idx/planner/mod.rs | 10 +- lib/src/idx/planner/plan.rs | 55 +- lib/src/idx/planner/tree.rs | 2 +- lib/src/kvs/ds.rs | 4 +- lib/src/sql/array.rs | 13 +- lib/src/sql/block.rs | 31 +- lib/src/sql/cast.rs | 13 +- lib/src/sql/constant.rs | 11 +- lib/src/sql/data.rs | 11 +- lib/src/sql/expression.rs | 19 +- lib/src/sql/field.rs | 54 +- lib/src/sql/function.rs | 25 +- lib/src/sql/future.rs | 13 +- lib/src/sql/id.rs | 15 +- lib/src/sql/idiom.rs | 23 +- lib/src/sql/limit.rs | 13 +- lib/src/sql/object.rs | 13 +- lib/src/sql/param.rs | 19 +- lib/src/sql/range.rs | 19 +- lib/src/sql/start.rs | 13 +- lib/src/sql/statement.rs | 45 +- lib/src/sql/statements/analyze.rs | 13 +- lib/src/sql/statements/create.rs | 17 +- lib/src/sql/statements/define.rs | 165 ++++-- lib/src/sql/statements/delete.rs | 15 +- lib/src/sql/statements/ifelse.rs | 17 +- lib/src/sql/statements/info.rs | 21 +- lib/src/sql/statements/insert.rs | 19 +- lib/src/sql/statements/kill.rs | 13 +- lib/src/sql/statements/live.rs | 15 +- lib/src/sql/statements/output.rs | 15 +- lib/src/sql/statements/relate.rs | 19 +- lib/src/sql/statements/remove.rs | 149 ++++-- lib/src/sql/statements/select.rs | 19 +- lib/src/sql/statements/set.rs | 12 +- lib/src/sql/statements/show.rs | 8 +- lib/src/sql/statements/sleep.rs | 12 +- lib/src/sql/statements/update.rs | 15 +- lib/src/sql/subquery.rs | 65 ++- lib/src/sql/thing.rs | 13 +- lib/src/sql/value/cut.rs | 44 +- lib/src/sql/value/decrement.rs | 33 +- lib/src/sql/value/del.rs | 74 +-- lib/src/sql/value/extend.rs | 21 +- lib/src/sql/value/fetch.rs | 39 +- lib/src/sql/value/get.rs | 114 ++-- lib/src/sql/value/increment.rs | 37 +- lib/src/sql/value/set.rs | 93 ++-- lib/src/sql/value/value.rs | 37 +- lib/tests/matches.rs | 26 +- 97 files changed, 1624 insertions(+), 1817 deletions(-) delete mode 100644 lib/src/dbs/channel.rs rename lib/src/dbs/{iterate.rs => processor.rs} (75%) diff --git a/Cargo.lock b/Cargo.lock index c8699849..74d264a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4523,7 +4523,6 @@ dependencies = [ "async-channel", "async-executor", "async-recursion", - "async-trait", "base64 0.21.2", "bcrypt", "bincode", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 15471e12..9b3b8b56 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -54,7 +54,6 @@ targets = [] addr = { version = "0.15.6", default-features = false, features = ["std"] } argon2 = "0.5.0" ascii = { version = "0.3.2", package = "any_ascii" } -async-trait = "0.1.69" async-recursion = "1.0.4" base64_lib = { version = "0.21.2", package = "base64" } bcrypt = "0.14.0" diff --git a/lib/src/ctx/context.rs b/lib/src/ctx/context.rs index 0166d7c5..917142a5 100644 --- a/lib/src/ctx/context.rs +++ b/lib/src/ctx/context.rs @@ -1,12 +1,8 @@ use crate::ctx::canceller::Canceller; use crate::ctx::reason::Reason; use crate::dbs::Notification; -use crate::dbs::Transaction; -use crate::err::Error; -use crate::idx::ft::docids::DocId; use crate::idx::planner::executor::QueryExecutor; use crate::sql::value::Value; -use crate::sql::Thing; use channel::Sender; use std::borrow::Cow; use std::collections::HashMap; @@ -36,18 +32,10 @@ pub struct Context<'a> { cancelled: Arc, // A collection of read only values stored in this context. values: HashMap, Cow<'a, Value>>, - // Stores the current transaction if available - transaction: Option, // Stores the notification channel if available notifications: Option>, // An optional query executor query_executors: Option>>, - // An optional record id - thing: Option<&'a Thing>, - // An optional doc id - doc_id: Option, - // An optional cursor document - cursor_doc: Option<&'a Value>, } impl<'a> Default for Context<'a> { @@ -63,8 +51,6 @@ impl<'a> Debug for Context<'a> { .field("deadline", &self.deadline) .field("cancelled", &self.cancelled) .field("values", &self.values) - .field("thing", &self.thing) - .field("doc", &self.cursor_doc) .finish() } } @@ -77,12 +63,8 @@ impl<'a> Context<'a> { parent: None, deadline: None, cancelled: Arc::new(AtomicBool::new(false)), - transaction: None, notifications: None, query_executors: None, - thing: None, - doc_id: None, - cursor_doc: None, } } @@ -93,12 +75,8 @@ impl<'a> Context<'a> { parent: Some(parent), deadline: parent.deadline, cancelled: Arc::new(AtomicBool::new(false)), - transaction: parent.transaction.clone(), notifications: parent.notifications.clone(), query_executors: parent.query_executors.clone(), - thing: parent.thing, - doc_id: parent.doc_id, - cursor_doc: parent.cursor_doc, } } @@ -134,34 +112,12 @@ impl<'a> Context<'a> { self.add_deadline(Instant::now() + timeout) } - /// Add the current transaction to the context, so that it can be fetched - /// where necessary, including inside the query planner. - pub fn add_transaction(&mut self, txn: Option<&Transaction>) { - self.transaction = txn.cloned() - } - /// Add the LIVE query notification channel to the context, so that we /// can send notifications to any subscribers. pub fn add_notifications(&mut self, chn: Option<&Sender>) { self.notifications = chn.cloned() } - /// Add a cursor document to this context. - /// Usage: A new child context is created by an iterator for each document. - /// The iterator sets the value of the current document (known as cursor document). - /// The cursor document is copied do the child contexts. - pub fn add_cursor_doc(&mut self, doc: &'a Value) { - self.cursor_doc = Some(doc); - } - - pub fn add_thing(&mut self, thing: &'a Thing) { - self.thing = Some(thing); - } - - pub fn add_doc_id(&mut self, doc_id: DocId) { - self.doc_id = Some(doc_id); - } - /// Set the query executors pub(crate) fn set_query_executors(&mut self, executors: HashMap) { self.query_executors = Some(Arc::new(executors)); @@ -173,28 +129,10 @@ impl<'a> Context<'a> { self.deadline.map(|v| v.saturating_duration_since(Instant::now())) } - /// Returns a transaction if any. - /// Otherwise it fails by returning a Error::NoTx error. - pub fn try_clone_transaction(&self) -> Result { - self.transaction.clone().ok_or(Error::Unreachable) - } - pub fn notifications(&self) -> Option> { self.notifications.clone() } - pub fn thing(&self) -> Option<&Thing> { - self.thing - } - - pub fn doc_id(&self) -> Option { - self.doc_id - } - - pub fn doc(&self) -> Option<&Value> { - self.cursor_doc - } - pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> { if let Some(qe) = &self.query_executors { qe.get(tb) diff --git a/lib/src/dbs/channel.rs b/lib/src/dbs/channel.rs deleted file mode 100644 index f9ea2730..00000000 --- a/lib/src/dbs/channel.rs +++ /dev/null @@ -1,497 +0,0 @@ -use crate::ctx::Context; -use crate::dbs::Iterable; -use crate::dbs::Operable; -use crate::dbs::Options; -use crate::dbs::Statement; -use crate::err::Error; -use crate::idx::planner::plan::Plan; -use crate::key::graph; -use crate::key::thing; -use crate::sql::dir::Dir; -use crate::sql::thing::Thing; -use crate::sql::value::Value; -use crate::sql::{Edges, Range, Table}; -use channel::Sender; -use std::ops::Bound; - -impl Iterable { - #[allow(dead_code)] - pub(crate) async fn channel( - self, - ctx: &Context<'_>, - opt: &Options, - _stm: &Statement<'_>, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - if ctx.is_ok() { - match self { - Iterable::Value(v) => Self::channel_value(ctx, opt, v, chn).await?, - Iterable::Thing(v) => Self::channel_thing(ctx, opt, v, chn).await?, - Iterable::Table(v) => Self::channel_table(ctx, opt, v, chn).await?, - Iterable::Range(v) => Self::channel_range(ctx, opt, v, chn).await?, - Iterable::Edges(e) => Self::channel_edge(ctx, opt, e, chn).await?, - Iterable::Index(t, p) => Self::channel_index(ctx, opt, t, p, chn).await?, - Iterable::Mergeable(v, o) => Self::channel_mergeable(ctx, opt, v, o, chn).await?, - Iterable::Relatable(f, v, w) => { - Self::channel_relatable(ctx, opt, f, v, w, chn).await? - } - } - } - Ok(()) - } - - async fn channel_value( - _ctx: &Context<'_>, - _opt: &Options, - v: Value, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Pass the value through - let val = Operable::Value(v); - // Process the document record - chn.send((None, val)).await?; - // Everything ok - Ok(()) - } - - async fn channel_thing( - ctx: &Context<'_>, - opt: &Options, - v: Thing, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; - // Fetch the data from the store - let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id); - let val = txn.clone().lock().await.get(key).await?; - // Parse the data from the store - let val = Operable::Value(match val { - Some(v) => Value::from(v), - None => Value::None, - }); - // Get the optional query executor - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); - // Process the document record - chn.send((Some(v), val)).await?; - // Everything ok - Ok(()) - } - - async fn channel_mergeable( - ctx: &Context<'_>, - opt: &Options, - v: Thing, - o: Value, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; - // Fetch the data from the store - let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id); - let val = txn.clone().lock().await.get(key).await?; - // Parse the data from the store - let x = match val { - Some(v) => Value::from(v), - None => Value::None, - }; - // Create a new operable value - let val = Operable::Mergeable(x, o); - // Create a new context to process the operable - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); - // Process the document record - chn.send((Some(v), val)).await?; - // Everything ok - Ok(()) - } - - async fn channel_relatable( - ctx: &Context<'_>, - opt: &Options, - f: Thing, - v: Thing, - w: Thing, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; - // Fetch the data from the store - let key = thing::new(opt.ns(), opt.db(), &v.tb, &v.id); - let val = txn.clone().lock().await.get(key).await?; - // Parse the data from the store - let x = match val { - Some(v) => Value::from(v), - None => Value::None, - }; - // Create a new operable value - let val = Operable::Relatable(f, x, w); - // Create the child context - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); - // Process the document record - chn.send((Some(v), val)).await?; - // Everything ok - Ok(()) - } - - async fn channel_table( - ctx: &Context<'_>, - opt: &Options, - v: Table, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?; - // Prepare the start and end keys - let beg = thing::prefix(opt.ns(), opt.db(), &v); - let end = thing::suffix(opt.ns(), opt.db(), &v); - // Prepare the next holder key - let mut nxt: Option> = None; - // Loop until no more keys - loop { - // Check if the context is finished - if ctx.is_done() { - break; - } - // Get the next 1000 key-value entries - let res = match nxt { - None => { - let min = beg.clone(); - let max = end.clone(); - txn.clone().lock().await.scan(min..max, 1000).await? - } - Some(ref mut beg) => { - beg.push(0x00); - let min = beg.clone(); - let max = end.clone(); - txn.clone().lock().await.scan(min..max, 1000).await? - } - }; - // If there are key-value entries then fetch them - if !res.is_empty() { - // Get total results - let n = res.len(); - // Loop over results - for (i, (k, v)) in res.into_iter().enumerate() { - // Check the context - if ctx.is_done() { - break; - } - // Ready the next - if n == i + 1 { - nxt = Some(k.clone()); - } - // Parse the data from the store - let key: crate::key::thing::Thing = (&k).into(); - let val: crate::sql::value::Value = (&v).into(); - let rid = Thing::from((key.tb, key.id)); - // Create a new operable value - let val = Operable::Value(val); - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&rid); - // Process the record - chn.send((Some(rid), val)).await?; - } - continue; - } - break; - } - // Everything ok - Ok(()) - } - - async fn channel_range( - ctx: &Context<'_>, - opt: &Options, - v: Range, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; - // Prepare the range start key - let beg = match &v.beg { - Bound::Unbounded => thing::prefix(opt.ns(), opt.db(), &v.tb), - Bound::Included(id) => thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(), - Bound::Excluded(id) => { - let mut key = thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(); - key.push(0x00); - key - } - }; - // Prepare the range end key - let end = match &v.end { - Bound::Unbounded => thing::suffix(opt.ns(), opt.db(), &v.tb), - Bound::Excluded(id) => thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(), - Bound::Included(id) => { - let mut key = thing::new(opt.ns(), opt.db(), &v.tb, id).encode().unwrap(); - key.push(0x00); - key - } - }; - // Prepare the next holder key - let mut nxt: Option> = None; - // Loop until no more keys - loop { - // Check if the context is finished - if ctx.is_done() { - break; - } - // Get the next 1000 key-value entries - let res = match nxt { - None => { - let min = beg.clone(); - let max = end.clone(); - txn.clone().lock().await.scan(min..max, 1000).await? - } - Some(ref mut beg) => { - beg.push(0x00); - let min = beg.clone(); - let max = end.clone(); - txn.clone().lock().await.scan(min..max, 1000).await? - } - }; - // If there are key-value entries then fetch them - if !res.is_empty() { - // Get total results - let n = res.len(); - // Loop over results - for (i, (k, v)) in res.into_iter().enumerate() { - // Check the context - if ctx.is_done() { - break; - } - // Ready the next - if n == i + 1 { - nxt = Some(k.clone()); - } - // Parse the data from the store - let key: crate::key::thing::Thing = (&k).into(); - let val: crate::sql::value::Value = (&v).into(); - let rid = Thing::from((key.tb, key.id)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); - // Create a new operable value - let val = Operable::Value(val); - // Process the record - chn.send((Some(rid), val)).await?; - } - continue; - } - break; - } - // Everything ok - Ok(()) - } - - async fn channel_edge( - ctx: &Context<'_>, - opt: &Options, - e: Edges, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - // Pull out options - let ns = opt.ns(); - let db = opt.db(); - let tb = &e.from.tb; - let id = &e.from.id; - // Fetch start and end key pairs - let keys = match e.what.len() { - 0 => match e.dir { - // /ns/db/tb/id - Dir::Both => { - vec![(graph::prefix(ns, db, tb, id), graph::suffix(ns, db, tb, id))] - } - // /ns/db/tb/id/IN - Dir::In => vec![( - graph::egprefix(ns, db, tb, id, &e.dir), - graph::egsuffix(ns, db, tb, id, &e.dir), - )], - // /ns/db/tb/id/OUT - Dir::Out => vec![( - graph::egprefix(ns, db, tb, id, &e.dir), - graph::egsuffix(ns, db, tb, id, &e.dir), - )], - }, - _ => match e.dir { - // /ns/db/tb/id/IN/TB - Dir::In => e - .what - .iter() - .map(|v| v.to_string()) - .map(|v| { - ( - graph::ftprefix(ns, db, tb, id, &e.dir, &v), - graph::ftsuffix(ns, db, tb, id, &e.dir, &v), - ) - }) - .collect::>(), - // /ns/db/tb/id/OUT/TB - Dir::Out => e - .what - .iter() - .map(|v| v.to_string()) - .map(|v| { - ( - graph::ftprefix(ns, db, tb, id, &e.dir, &v), - graph::ftsuffix(ns, db, tb, id, &e.dir, &v), - ) - }) - .collect::>(), - // /ns/db/tb/id/IN/TB, /ns/db/tb/id/OUT/TB - Dir::Both => e - .what - .iter() - .map(|v| v.to_string()) - .flat_map(|v| { - vec![ - ( - graph::ftprefix(ns, db, tb, id, &Dir::In, &v), - graph::ftsuffix(ns, db, tb, id, &Dir::In, &v), - ), - ( - graph::ftprefix(ns, db, tb, id, &Dir::Out, &v), - graph::ftsuffix(ns, db, tb, id, &Dir::Out, &v), - ), - ] - }) - .collect::>(), - }, - }; - // - for (beg, end) in keys.iter() { - // Prepare the next holder key - let mut nxt: Option> = None; - // Loop until no more keys - loop { - // Check if the context is finished - if ctx.is_done() { - break; - } - // Get the next 1000 key-value entries - let res = match nxt { - None => { - let min = beg.clone(); - let max = end.clone(); - ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await? - } - Some(ref mut beg) => { - beg.push(0x00); - let min = beg.clone(); - let max = end.clone(); - ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await? - } - }; - // If there are key-value entries then fetch them - if !res.is_empty() { - // Get total results - let n = res.len(); - // Exit when settled - if n == 0 { - break; - } - // Loop over results - for (i, (k, _)) in res.into_iter().enumerate() { - // Check the context - if ctx.is_done() { - break; - } - // Ready the next - if n == i + 1 { - nxt = Some(k.clone()); - } - // Parse the data from the store - let gra: crate::key::graph::Graph = (&k).into(); - // Fetch the data from the store - let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk); - let val = ctx.try_clone_transaction()?.lock().await.get(key).await?; - let rid = Thing::from((gra.ft, gra.fk)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); - // Parse the data from the store - let val = Operable::Value(match val { - Some(v) => Value::from(v), - None => Value::None, - }); - // Process the record - chn.send((Some(rid), val)).await?; - } - continue; - } - break; - } - } - // Everything ok - Ok(()) - } - - async fn channel_index( - ctx: &Context<'_>, - opt: &Options, - table: Table, - plan: Plan, - chn: Sender<(Option, Operable)>, - ) -> Result<(), Error> { - let txn = ctx.try_clone_transaction()?; - // Check that the table exists - txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?; - let exe = ctx.get_query_executor(&table.0); - if let Some(exe) = exe { - let mut iterator = plan.new_iterator(opt, &txn, exe).await?; - let mut things = iterator.next_batch(&txn, 1000).await?; - while !things.is_empty() { - // Check if the context is finished - if ctx.is_done() { - break; - } - - for (thing, doc_id) in things { - // Check the context - if ctx.is_done() { - break; - } - - // If the record is from another table we can skip - if !thing.tb.eq(table.as_str()) { - continue; - } - - // Fetch the data from the store - let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id); - let val = txn.lock().await.get(key.clone()).await?; - let rid = Thing::from((key.tb, key.id)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); - ctx.add_doc_id(doc_id); - // Parse the data from the store - let val = Operable::Value(match val { - Some(v) => Value::from(v), - None => Value::None, - }); - // Process the document record - chn.send((Some(rid), val)).await?; - } - - // Collect the next batch of ids - things = iterator.next_batch(&txn, 1000).await?; - } - // Everything ok - Ok(()) - } else { - Err(Error::QueryNotExecutedDetail { - message: "The QueryExecutor has not been found.".to_string(), - }) - } - } -} diff --git a/lib/src/dbs/executor.rs b/lib/src/dbs/executor.rs index 6af4b492..27f7ea04 100644 --- a/lib/src/dbs/executor.rs +++ b/lib/src/dbs/executor.rs @@ -34,6 +34,10 @@ impl<'a> Executor<'a> { } } + fn txn(&self) -> Transaction { + self.txn.clone().expect("unreachable: txn was None after successful begin") + } + /// # Return /// - true if a new transaction has begun /// - false if @@ -275,10 +279,7 @@ impl<'a> Executor<'a> { // Check if the variable is a protected variable let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) { // The variable isn't protected and can be stored - false => { - ctx.add_transaction(self.txn.as_ref()); - stm.compute(&ctx, &opt).await - } + false => stm.compute(&ctx, &opt, &self.txn(), None).await, // The user tried to set a protected variable true => Err(Error::InvalidParam { // Move the parameter name, as we no longer need it @@ -338,16 +339,15 @@ impl<'a> Executor<'a> { true => Err(Error::TxFailure), // The transaction began successfully false => { + let mut ctx = Context::new(&ctx); // Process the statement let res = match stm.timeout() { // There is a timeout clause Some(timeout) => { // Set statement timeout - let mut ctx = Context::new(&ctx); ctx.add_timeout(timeout); - ctx.add_transaction(self.txn.as_ref()); // Process the statement - let res = stm.compute(&ctx, &opt).await; + let res = stm.compute(&ctx, &opt, &self.txn(), None).await; // Catch statement timeout match ctx.is_timedout() { true => Err(Error::QueryTimedout), @@ -355,10 +355,7 @@ impl<'a> Executor<'a> { } } // There is no timeout clause - None => { - ctx.add_transaction(self.txn.as_ref()); - stm.compute(&ctx, &opt).await - } + None => stm.compute(&ctx, &opt, &self.txn(), None).await, }; // Catch global timeout let res = match ctx.is_timedout() { diff --git a/lib/src/dbs/iterator.rs b/lib/src/dbs/iterator.rs index d3ce5dbf..522e1d81 100644 --- a/lib/src/dbs/iterator.rs +++ b/lib/src/dbs/iterator.rs @@ -1,9 +1,11 @@ use crate::ctx::Canceller; use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::doc::Document; use crate::err::Error; +use crate::idx::ft::docids::DocId; use crate::idx::planner::plan::Plan; use crate::sql::array::Array; use crate::sql::edges::Edges; @@ -74,6 +76,7 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Log the statement @@ -82,29 +85,29 @@ impl Iterator { let mut cancel_ctx = Context::new(ctx); self.run = cancel_ctx.add_cancel(); // Process the query LIMIT clause - self.setup_limit(&cancel_ctx, opt, stm).await?; + self.setup_limit(&cancel_ctx, opt, txn, stm).await?; // Process the query START clause - self.setup_start(&cancel_ctx, opt, stm).await?; + self.setup_start(&cancel_ctx, opt, txn, stm).await?; // Process any EXPLAIN clause - let explanation = self.output_explain(&cancel_ctx, opt, stm)?; + let explanation = self.output_explain(&cancel_ctx, opt, txn, stm)?; // Process prepared values - self.iterate(&cancel_ctx, opt, stm).await?; + self.iterate(&cancel_ctx, opt, txn, stm).await?; // Return any document errors if let Some(e) = self.error.take() { return Err(e); } // Process any SPLIT clause - self.output_split(ctx, opt, stm).await?; + self.output_split(ctx, opt, txn, stm).await?; // Process any GROUP clause - self.output_group(ctx, opt, stm).await?; + self.output_group(ctx, opt, txn, stm).await?; // Process any ORDER clause - self.output_order(ctx, opt, stm).await?; + self.output_order(ctx, opt, txn, stm).await?; // Process any START clause - self.output_start(ctx, opt, stm).await?; + self.output_start(ctx, opt, txn, stm).await?; // Process any LIMIT clause - self.output_limit(ctx, opt, stm).await?; + self.output_limit(ctx, opt, txn, stm).await?; // Process any FETCH clause - self.output_fetch(ctx, opt, stm).await?; + self.output_fetch(ctx, opt, txn, stm).await?; // Add the EXPLAIN clause to the result if let Some(e) = explanation { self.results.push(e); @@ -118,10 +121,11 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(v) = stm.limit() { - self.limit = Some(v.process(ctx, opt).await?); + self.limit = Some(v.process(ctx, opt, txn, None).await?); } Ok(()) } @@ -131,10 +135,11 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(v) = stm.start() { - self.start = Some(v.process(ctx, opt).await?); + self.start = Some(v.process(ctx, opt, txn, None).await?); } Ok(()) } @@ -144,6 +149,7 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(splits) = stm.split() { @@ -162,7 +168,7 @@ impl Iterator { // Make a copy of object let mut obj = obj.clone(); // Set the value at the path - obj.set(ctx, opt, split, val).await?; + obj.set(ctx, opt, txn, split, val).await?; // Add the object to the results self.results.push(obj); } @@ -171,7 +177,7 @@ impl Iterator { // Make a copy of object let mut obj = obj.clone(); // Set the value at the path - obj.set(ctx, opt, split, val).await?; + obj.set(ctx, opt, txn, split, val).await?; // Add the object to the results self.results.push(obj); } @@ -187,6 +193,7 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(fields) = stm.expr() { @@ -234,20 +241,21 @@ impl Iterator { .unwrap_or_else(|| Cow::Owned(expr.to_idiom())); match expr { Value::Function(f) if f.is_aggregate() => { - let x = vals.all().get(ctx, opt, idiom.as_ref()).await?; - let x = f.aggregate(x).compute(ctx, opt).await?; - obj.set(ctx, opt, idiom.as_ref(), x).await?; + let x = + vals.all().get(ctx, opt, txn, None, idiom.as_ref()).await?; + let x = f.aggregate(x).compute(ctx, opt, txn, None).await?; + obj.set(ctx, opt, txn, idiom.as_ref(), x).await?; } _ => { let x = vals.first(); - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(&x); let x = if let Some(alias) = alias { - alias.compute(&child_ctx, opt).await? + let cur = CursorDoc::new(None, None, &x); + alias.compute(ctx, opt, txn, Some(&cur)).await? } else { - expr.compute(&child_ctx, opt).await? + let cur = CursorDoc::new(None, None, &x); + expr.compute(ctx, opt, txn, Some(&cur)).await? }; - obj.set(ctx, opt, idiom.as_ref(), x).await?; + obj.set(ctx, opt, txn, idiom.as_ref(), x).await?; } } } @@ -265,6 +273,7 @@ impl Iterator { &mut self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(orders) = stm.order() { @@ -303,6 +312,7 @@ impl Iterator { &mut self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(v) = self.start { @@ -316,6 +326,7 @@ impl Iterator { &mut self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(v) = self.limit { @@ -329,6 +340,7 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { if let Some(fetchs) = stm.fetch() { @@ -336,7 +348,7 @@ impl Iterator { // Loop over each result value for obj in &mut self.results { // Fetch the value at the path - obj.fetch(ctx, opt, fetch).await?; + obj.fetch(ctx, opt, txn, fetch).await?; } } } @@ -348,6 +360,7 @@ impl Iterator { &mut self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, stm: &Statement<'_>, ) -> Result, Error> { Ok(if stm.explain() { @@ -405,13 +418,14 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Prevent deep recursion let opt = &opt.dive(4)?; // Process all prepared values for v in mem::take(&mut self.entries) { - v.iterate(ctx, opt, stm, self).await?; + v.iterate(ctx, opt, txn, stm, self).await?; } // Everything processed ok Ok(()) @@ -423,6 +437,7 @@ impl Iterator { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Prevent deep recursion @@ -433,7 +448,7 @@ impl Iterator { false => { // Process all prepared values for v in mem::take(&mut self.entries) { - v.iterate(ctx, opt, stm, self).await?; + v.iterate(ctx, opt, txn, stm, self).await?; } // Everything processed ok Ok(()) @@ -452,7 +467,7 @@ impl Iterator { let adocs = async { // Process all prepared values for v in vals { - e.spawn(v.channel(ctx, opt, stm, chn.clone())) + e.spawn(v.channel(ctx, opt, txn, stm, chn.clone())) // Ensure we detach the spawned task .detach(); } @@ -464,8 +479,8 @@ impl Iterator { // Create an async closure for received values let avals = async { // Process all received values - while let Ok((k, v)) = docs.recv().await { - e.spawn(Document::compute(ctx, opt, stm, chn.clone(), k, v)) + while let Ok((k, d, v)) = docs.recv().await { + e.spawn(Document::compute(ctx, opt, txn, stm, chn.clone(), k, d, v)) // Ensure we detach the spawned task .detach(); } @@ -494,11 +509,15 @@ impl Iterator { } /// Process a new record Thing and Value + #[allow(clippy::too_many_arguments)] pub async fn process( &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, + thg: Option, + doc_id: Option, val: Operable, ) { // Check current context @@ -512,15 +531,15 @@ impl Iterator { Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)), }; // Setup a new document - let mut doc = Document::new(ctx.thing(), &val, ext); + let mut doc = Document::new(thg.as_ref(), doc_id, &val, ext); // Process the document let res = match stm { - Statement::Select(_) => doc.select(ctx, opt, stm).await, - Statement::Create(_) => doc.create(ctx, opt, stm).await, - Statement::Update(_) => doc.update(ctx, opt, stm).await, - Statement::Relate(_) => doc.relate(ctx, opt, stm).await, - Statement::Delete(_) => doc.delete(ctx, opt, stm).await, - Statement::Insert(_) => doc.insert(ctx, opt, stm).await, + Statement::Select(_) => doc.select(ctx, opt, txn, stm).await, + Statement::Create(_) => doc.create(ctx, opt, txn, stm).await, + Statement::Update(_) => doc.update(ctx, opt, txn, stm).await, + Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await, + Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await, + Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await, _ => unreachable!(), }; // Process the result diff --git a/lib/src/dbs/mod.rs b/lib/src/dbs/mod.rs index ef15ad4d..0a38d0e4 100644 --- a/lib/src/dbs/mod.rs +++ b/lib/src/dbs/mod.rs @@ -4,7 +4,6 @@ //! and executors to process the operations. This module also gives a `context` to the transaction. mod auth; mod executor; -mod iterate; mod iterator; mod notification; mod options; @@ -26,13 +25,8 @@ pub(crate) use self::statement::*; pub(crate) use self::transaction::*; pub(crate) use self::variables::*; -#[cfg(not(target_arch = "wasm32"))] -mod channel; - -#[cfg(not(target_arch = "wasm32"))] -pub use self::channel::*; - pub mod cl; +mod processor; #[cfg(test)] pub(crate) mod test; diff --git a/lib/src/dbs/iterate.rs b/lib/src/dbs/processor.rs similarity index 75% rename from lib/src/dbs/iterate.rs rename to lib/src/dbs/processor.rs index 4a2521d1..cd135796 100644 --- a/lib/src/dbs/iterate.rs +++ b/lib/src/dbs/processor.rs @@ -1,17 +1,13 @@ use crate::ctx::Context; -use crate::dbs::Iterable; -use crate::dbs::Iterator; -use crate::dbs::Operable; -use crate::dbs::Options; -use crate::dbs::Statement; +use crate::dbs::{Iterable, Iterator, Operable, Options, Statement, Transaction}; use crate::err::Error; +use crate::idx::ft::docids::DocId; use crate::idx::planner::plan::Plan; -use crate::key::graph; -use crate::key::thing; +use crate::key::{graph, thing}; use crate::sql::dir::Dir; -use crate::sql::thing::Thing; -use crate::sql::value::Value; -use crate::sql::{Edges, Range, Table}; +use crate::sql::{Edges, Range, Table, Thing, Value}; +#[cfg(not(target_arch = "wasm32"))] +use channel::Sender; use std::ops::Bound; impl Iterable { @@ -19,50 +15,105 @@ impl Iterable { self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ite: &mut Iterator, + ) -> Result<(), Error> { + Processor::Iterator(ite).process_iterable(ctx, opt, txn, stm, self).await + } + + #[cfg(not(target_arch = "wasm32"))] + pub(crate) async fn channel( + self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + stm: &Statement<'_>, + chn: Sender<(Option, Option, Operable)>, + ) -> Result<(), Error> { + Processor::Channel(chn).process_iterable(ctx, opt, txn, stm, self).await + } +} + +enum Processor<'a> { + Iterator(&'a mut Iterator), + #[cfg(not(target_arch = "wasm32"))] + Channel(Sender<(Option, Option, Operable)>), +} + +impl<'a> Processor<'a> { + #[allow(clippy::too_many_arguments)] + async fn process( + &mut self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + stm: &Statement<'_>, + rid: Option, + doc_id: Option, + val: Operable, + ) -> Result<(), Error> { + match self { + Processor::Iterator(ite) => { + ite.process(ctx, opt, txn, stm, rid, doc_id, val).await; + } + #[cfg(not(target_arch = "wasm32"))] + Processor::Channel(chn) => { + chn.send((rid, doc_id, val)).await?; + } + }; + Ok(()) + } + + async fn process_iterable( + &mut self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + stm: &Statement<'_>, + iterable: Iterable, ) -> Result<(), Error> { if ctx.is_ok() { - match self { - Iterable::Value(v) => Self::iterate_value(ctx, opt, stm, v, ite).await, - Iterable::Thing(v) => Self::iterate_thing(ctx, opt, stm, v, ite).await?, - Iterable::Table(v) => Self::iterate_table(ctx, opt, stm, v, ite).await?, - Iterable::Range(v) => Self::iterate_range(ctx, opt, stm, v, ite).await?, - Iterable::Edges(e) => Self::iterate_edge(ctx, opt, stm, e, ite).await?, - Iterable::Index(t, p) => Self::iterate_index(ctx, opt, stm, t, p, ite).await?, + match iterable { + Iterable::Value(v) => self.process_value(ctx, opt, txn, stm, v).await?, + Iterable::Thing(v) => self.process_thing(ctx, opt, txn, stm, v).await?, + Iterable::Table(v) => self.process_table(ctx, opt, txn, stm, v).await?, + Iterable::Range(v) => self.process_range(ctx, opt, txn, stm, v).await?, + Iterable::Edges(e) => self.process_edge(ctx, opt, txn, stm, e).await?, + Iterable::Index(t, p) => self.process_index(ctx, opt, txn, stm, t, p).await?, Iterable::Mergeable(v, o) => { - Self::iterate_mergeable(ctx, opt, stm, v, o, ite).await? + self.process_mergeable(ctx, opt, txn, stm, v, o).await? } Iterable::Relatable(f, v, w) => { - Self::iterate_relatable(ctx, opt, stm, f, v, w, ite).await? + self.process_relatable(ctx, opt, txn, stm, f, v, w).await? } } } Ok(()) } - async fn iterate_value( + async fn process_value( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, v: Value, - ite: &mut Iterator, - ) { + ) -> Result<(), Error> { // Pass the value through let val = Operable::Value(v); // Process the document record - ite.process(ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, None, None, val).await } - async fn iterate_thing( + async fn process_thing( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, v: Thing, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; // Fetch the data from the store @@ -73,25 +124,21 @@ impl Iterable { Some(v) => Value::from(v), None => Value::None, }); - // Get the optional query executor - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); // Process the document record - ite.process(&child_ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(v), None, val).await?; // Everything ok Ok(()) } - async fn iterate_mergeable( + async fn process_mergeable( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, v: Thing, o: Value, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; // Fetch the data from the store @@ -104,26 +151,23 @@ impl Iterable { }; // Create a new operable value let val = Operable::Mergeable(x, o); - // Create a new context to process the operable - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); // Process the document record - ite.process(&child_ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(v), None, val).await?; // Everything ok Ok(()) } - async fn iterate_relatable( + #[allow(clippy::too_many_arguments)] + async fn process_relatable( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, f: Thing, v: Thing, w: Thing, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; // Fetch the data from the store @@ -136,24 +180,20 @@ impl Iterable { }; // Create a new operable value let val = Operable::Relatable(f, x, w); - // Create the child context - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&v); // Process the document record - ite.process(&child_ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(v), None, val).await?; // Everything ok Ok(()) } - async fn iterate_table( + async fn process_table( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, v: Table, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?; // Prepare the start and end keys @@ -201,10 +241,8 @@ impl Iterable { let rid = Thing::from((key.tb, key.id)); // Create a new operable value let val = Operable::Value(val); - let mut child_ctx = Context::new(ctx); - child_ctx.add_thing(&rid); // Process the record - ite.process(&child_ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(rid), None, val).await?; } continue; } @@ -214,15 +252,14 @@ impl Iterable { Ok(()) } - async fn iterate_range( + async fn process_range( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, v: Range, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; // Prepare the range start key @@ -285,12 +322,10 @@ impl Iterable { let key: crate::key::thing::Thing = (&k).into(); let val: crate::sql::value::Value = (&v).into(); let rid = Thing::from((key.tb, key.id)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); // Create a new operable value let val = Operable::Value(val); // Process the record - ite.process(&ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(rid), None, val).await?; } continue; } @@ -300,12 +335,13 @@ impl Iterable { Ok(()) } - async fn iterate_edge( + async fn process_edge( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, e: Edges, - ite: &mut Iterator, ) -> Result<(), Error> { // Pull out options let ns = opt.ns(); @@ -390,13 +426,13 @@ impl Iterable { None => { let min = beg.clone(); let max = end.clone(); - ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await? + txn.lock().await.scan(min..max, 1000).await? } Some(ref mut beg) => { beg.push(0x00); let min = beg.clone(); let max = end.clone(); - ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await? + txn.lock().await.scan(min..max, 1000).await? } }; // If there are key-value entries then fetch them @@ -421,17 +457,15 @@ impl Iterable { let gra: crate::key::graph::Graph = (&k).into(); // Fetch the data from the store let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk); - let val = ctx.try_clone_transaction()?.lock().await.get(key).await?; + let val = txn.lock().await.get(key).await?; let rid = Thing::from((gra.ft, gra.fk)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); // Parse the data from the store let val = Operable::Value(match val { Some(v) => Value::from(v), None => Value::None, }); // Process the record - ite.process(&ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(rid), None, val).await?; } continue; } @@ -442,22 +476,21 @@ impl Iterable { Ok(()) } - async fn iterate_index( + async fn process_index( + &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, table: Table, plan: Plan, - ite: &mut Iterator, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check that the table exists txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?; let exe = ctx.get_query_executor(&table.0); if let Some(exe) = exe { - let mut iterator = plan.new_iterator(opt, &txn, exe).await?; - let mut things = iterator.next_batch(&txn, 1000).await?; + let mut iterator = plan.new_iterator(opt, txn, exe).await?; + let mut things = iterator.next_batch(txn, 1000).await?; while !things.is_empty() { // Check if the context is finished if ctx.is_done() { @@ -479,20 +512,17 @@ impl Iterable { let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id); let val = txn.lock().await.get(key.clone()).await?; let rid = Thing::from((key.tb, key.id)); - let mut ctx = Context::new(ctx); - ctx.add_thing(&rid); - ctx.add_doc_id(doc_id); // Parse the data from the store let val = Operable::Value(match val { Some(v) => Value::from(v), None => Value::None, }); // Process the document record - ite.process(&ctx, opt, stm, val).await; + self.process(ctx, opt, txn, stm, Some(rid), Some(doc_id), val).await?; } // Collect the next batch of ids - things = iterator.next_batch(&txn, 1000).await?; + things = iterator.next_batch(txn, 1000).await?; } // Everything ok Ok(()) diff --git a/lib/src/dbs/test.rs b/lib/src/dbs/test.rs index 94a58f2b..d3981ec6 100644 --- a/lib/src/dbs/test.rs +++ b/lib/src/dbs/test.rs @@ -1,15 +1,14 @@ use crate::ctx::Context; -use crate::dbs::{Auth, Options}; +use crate::dbs::{Auth, Options, Transaction}; use crate::kvs::Datastore; use futures::lock::Mutex; use std::sync::Arc; -pub async fn mock<'a>() -> (Context<'a>, Options) { - let mut ctx = Context::default(); +pub async fn mock<'a>() -> (Context<'a>, Options, Transaction) { + let ctx = Context::default(); let opt = Options::default().with_auth(Arc::new(Auth::Kv)); let kvs = Datastore::new("memory").await.unwrap(); let txn = kvs.transaction(true, false).await.unwrap(); let txn = Arc::new(Mutex::new(txn)); - ctx.add_transaction(Some(&txn)); - (ctx, opt) + (ctx, opt, txn) } diff --git a/lib/src/doc/allow.rs b/lib/src/doc/allow.rs index f880c0dd..34dff8ce 100644 --- a/lib/src/doc/allow.rs +++ b/lib/src/doc/allow.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::permission::Permission; @@ -10,16 +10,15 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Check if this record exists if self.id.is_some() { // Should we run permissions checks? if opt.perms && opt.auth.perms() { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Get the table - let tb = self.tb(opt, &txn).await?; + let tb = self.tb(opt, txn).await?; // Get the permission clause let perms = if stm.is_delete() { &tb.permissions.delete @@ -37,10 +36,8 @@ impl<'a> Document<'a> { Permission::Specific(e) => { // Disable permissions let opt = &opt.new_with_perms(false); - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); // Process the PERMISSION clause - if !e.compute(&ctx, opt).await?.is_truthy() { + if !e.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() { return Err(Error::Ignore); } } diff --git a/lib/src/doc/alter.rs b/lib/src/doc/alter.rs index dc341538..7d37ebd4 100644 --- a/lib/src/doc/alter.rs +++ b/lib/src/doc/alter.rs @@ -1,7 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; use crate::dbs::Workable; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::data::Data; @@ -13,57 +13,50 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Get the record id let rid = self.id.as_ref().unwrap(); // Set default field values - self.current.to_mut().def(rid); + self.current.doc.to_mut().def(rid); // The statement has a data clause if let Some(v) = stm.data() { match v { Data::PatchExpression(data) => { - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); - let data = data.compute(¤t_ctx, opt).await?; - self.current.to_mut().patch(data)? + let data = data.compute(ctx, opt, txn, Some(&self.current)).await?; + self.current.doc.to_mut().patch(data)? } Data::MergeExpression(data) => { - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); - let data = data.compute(¤t_ctx, opt).await?; - self.current.to_mut().merge(data)? + let data = data.compute(ctx, opt, txn, Some(&self.current)).await?; + self.current.doc.to_mut().merge(data)? } Data::ReplaceExpression(data) => { - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); - let data = data.compute(¤t_ctx, opt).await?; - self.current.to_mut().replace(data)? + let data = data.compute(ctx, opt, txn, Some(&self.current)).await?; + self.current.doc.to_mut().replace(data)? } Data::ContentExpression(data) => { - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); - let data = data.compute(¤t_ctx, opt).await?; - self.current.to_mut().replace(data)? + let data = data.compute(ctx, opt, txn, Some(&self.current)).await?; + self.current.doc.to_mut().replace(data)? } Data::SetExpression(x) => { for x in x.iter() { - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); - let v = x.2.compute(¤t_ctx, opt).await?; + let v = x.2.compute(ctx, opt, txn, Some(&self.current)).await?; match x.1 { Operator::Equal => match v { - Value::None => self.current.to_mut().del(ctx, opt, &x.0).await?, - _ => self.current.to_mut().set(ctx, opt, &x.0, v).await?, + Value::None => { + self.current.doc.to_mut().del(ctx, opt, txn, &x.0).await? + } + _ => self.current.doc.to_mut().set(ctx, opt, txn, &x.0, v).await?, }, Operator::Inc => { - self.current.to_mut().increment(ctx, opt, &x.0, v).await? + self.current.doc.to_mut().increment(ctx, opt, txn, &x.0, v).await? } Operator::Dec => { - self.current.to_mut().decrement(ctx, opt, &x.0, v).await? + self.current.doc.to_mut().decrement(ctx, opt, txn, &x.0, v).await? } Operator::Ext => { - self.current.to_mut().extend(ctx, opt, &x.0, v).await? + self.current.doc.to_mut().extend(ctx, opt, txn, &x.0, v).await? } _ => unreachable!(), } @@ -71,7 +64,7 @@ impl<'a> Document<'a> { } Data::UnsetExpression(i) => { for i in i.iter() { - self.current.to_mut().del(ctx, opt, i).await? + self.current.doc.to_mut().del(ctx, opt, txn, i).await? } } Data::UpdateExpression(x) => { @@ -83,22 +76,22 @@ impl<'a> Document<'a> { } // Process ON DUPLICATE KEY clause for x in x.iter() { - let mut current_ctx = Context::new(&ctx); - current_ctx.add_cursor_doc(&self.current); - let v = x.2.compute(¤t_ctx, opt).await?; + let v = x.2.compute(&ctx, opt, txn, Some(&self.current)).await?; match x.1 { Operator::Equal => match v { - Value::None => self.current.to_mut().del(&ctx, opt, &x.0).await?, - _ => self.current.to_mut().set(&ctx, opt, &x.0, v).await?, + Value::None => { + self.current.doc.to_mut().del(&ctx, opt, txn, &x.0).await? + } + _ => self.current.doc.to_mut().set(&ctx, opt, txn, &x.0, v).await?, }, Operator::Inc => { - self.current.to_mut().increment(&ctx, opt, &x.0, v).await? + self.current.doc.to_mut().increment(&ctx, opt, txn, &x.0, v).await? } Operator::Dec => { - self.current.to_mut().decrement(&ctx, opt, &x.0, v).await? + self.current.doc.to_mut().decrement(&ctx, opt, txn, &x.0, v).await? } Operator::Ext => { - self.current.to_mut().extend(&ctx, opt, &x.0, v).await? + self.current.doc.to_mut().extend(&ctx, opt, txn, &x.0, v).await? } _ => unreachable!(), } @@ -108,7 +101,7 @@ impl<'a> Document<'a> { }; }; // Set default field values - self.current.to_mut().def(rid); + self.current.doc.to_mut().def(rid); // Carry on Ok(()) } diff --git a/lib/src/doc/check.rs b/lib/src/doc/check.rs index 36b5b006..3a33f2c3 100644 --- a/lib/src/doc/check.rs +++ b/lib/src/doc/check.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; @@ -9,14 +9,13 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Check where condition if let Some(cond) = stm.conds() { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); // Check if the expression is truthy - if !cond.compute(&ctx, opt).await?.is_truthy() { + if !cond.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() { // Ignore this document return Err(Error::Ignore); } diff --git a/lib/src/doc/clean.rs b/lib/src/doc/clean.rs index 66f9be98..06256421 100644 --- a/lib/src/doc/clean.rs +++ b/lib/src/doc/clean.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::idiom::Idiom; @@ -10,43 +10,42 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Get the table - let tb = self.tb(opt, &txn).await?; + let tb = self.tb(opt, txn).await?; // This table is schemafull if tb.full { // Create a vector to store the keys let mut keys: Vec = vec![]; // Loop through all field statements - for fd in self.fd(opt, &txn).await?.iter() { + for fd in self.fd(opt, txn).await?.iter() { // Is this a schemaless field? match fd.flex { false => { // Loop over this field in the document - for k in self.current.each(&fd.name).into_iter() { + for k in self.current.doc.each(&fd.name).into_iter() { keys.push(k); } } true => { // Loop over every field under this field in the document - for k in self.current.every(Some(&fd.name), true, true).into_iter() { + for k in self.current.doc.every(Some(&fd.name), true, true).into_iter() { keys.push(k); } } } } // Loop over every field in the document - for fd in self.current.every(None, true, true).iter() { + for fd in self.current.doc.every(None, true, true).iter() { if !keys.contains(fd) { match fd { fd if fd.is_id() => continue, fd if fd.is_in() => continue, fd if fd.is_out() => continue, fd if fd.is_meta() => continue, - fd => self.current.to_mut().del(ctx, opt, fd).await?, + fd => self.current.doc.to_mut().del(ctx, opt, txn, fd).await?, } } } diff --git a/lib/src/doc/compute.rs b/lib/src/doc/compute.rs index 5c85321e..a5652490 100644 --- a/lib/src/doc/compute.rs +++ b/lib/src/doc/compute.rs @@ -1,28 +1,28 @@ use crate::ctx::Context; -use crate::dbs::Operable; use crate::dbs::Options; use crate::dbs::Statement; use crate::dbs::Workable; +use crate::dbs::{Operable, Transaction}; use crate::doc::Document; use crate::err::Error; +use crate::idx::ft::docids::DocId; use crate::sql::thing::Thing; use crate::sql::value::Value; use channel::Sender; impl<'a> Document<'a> { #[allow(dead_code)] + #[allow(clippy::too_many_arguments)] pub(crate) async fn compute( ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, chn: Sender>, thg: Option, + doc_id: Option, val: Operable, ) -> Result<(), Error> { - let mut ctx = Context::new(ctx); - if let Some(t) = &thg { - ctx.add_thing(t); - } // Setup a new workable let ins = match val { Operable::Value(v) => (v, Workable::Normal), @@ -30,15 +30,15 @@ impl<'a> Document<'a> { Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)), }; // Setup a new document - let mut doc = Document::new(ctx.thing(), &ins.0, ins.1); + let mut doc = Document::new(thg.as_ref(), doc_id, &ins.0, ins.1); // Process the statement let res = match stm { - Statement::Select(_) => doc.select(&ctx, opt, stm).await, - Statement::Create(_) => doc.create(&ctx, opt, stm).await, - Statement::Update(_) => doc.update(&ctx, opt, stm).await, - Statement::Relate(_) => doc.relate(&ctx, opt, stm).await, - Statement::Delete(_) => doc.delete(&ctx, opt, stm).await, - Statement::Insert(_) => doc.insert(&ctx, opt, stm).await, + Statement::Select(_) => doc.select(ctx, opt, txn, stm).await, + Statement::Create(_) => doc.create(ctx, opt, txn, stm).await, + Statement::Update(_) => doc.update(ctx, opt, txn, stm).await, + Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await, + Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await, + Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await, _ => unreachable!(), }; // Send back the result diff --git a/lib/src/doc/create.rs b/lib/src/doc/create.rs index 9a3a0fa3..8c91cd96 100644 --- a/lib/src/doc/create.rs +++ b/lib/src/doc/create.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,31 +10,32 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check if exists - self.exist(ctx, opt, stm).await?; + self.exist(ctx, opt, txn, stm).await?; // Alter record data - self.alter(ctx, opt, stm).await?; + self.alter(ctx, opt, txn, stm).await?; // Merge fields data - self.field(ctx, opt, stm).await?; + self.field(ctx, opt, txn, stm).await?; // Reset fields data - self.reset(ctx, opt, stm).await?; + self.reset(ctx, opt, txn, stm).await?; // Clean fields data - self.clean(ctx, opt, stm).await?; + self.clean(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Store index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Store record data - self.store(ctx, opt, stm).await?; + self.store(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } diff --git a/lib/src/doc/delete.rs b/lib/src/doc/delete.rs index 0a5eec52..d2b7f648 100644 --- a/lib/src/doc/delete.rs +++ b/lib/src/doc/delete.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,25 +10,26 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check where clause - self.check(ctx, opt, stm).await?; + self.check(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Erase document self.erase(ctx, opt, stm).await?; // Purge index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Purge record data - self.purge(ctx, opt, stm).await?; + self.purge(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } diff --git a/lib/src/doc/document.rs b/lib/src/doc/document.rs index a094e92c..14b9e75d 100644 --- a/lib/src/doc/document.rs +++ b/lib/src/doc/document.rs @@ -3,6 +3,7 @@ use crate::dbs::Options; use crate::dbs::Transaction; use crate::dbs::Workable; use crate::err::Error; +use crate::idx::ft::docids::DocId; use crate::sql::statements::define::DefineEventStatement; use crate::sql::statements::define::DefineFieldStatement; use crate::sql::statements::define::DefineIndexStatement; @@ -17,8 +18,24 @@ use std::sync::Arc; pub(crate) struct Document<'a> { pub(super) id: Option<&'a Thing>, pub(super) extras: Workable, - pub(super) current: Cow<'a, Value>, - pub(super) initial: Cow<'a, Value>, + pub(super) initial: CursorDoc<'a>, + pub(super) current: CursorDoc<'a>, +} + +pub struct CursorDoc<'a> { + pub(crate) rid: Option<&'a Thing>, + pub(crate) doc: Cow<'a, Value>, + pub(crate) doc_id: Option, +} + +impl<'a> CursorDoc<'a> { + pub(crate) fn new(rid: Option<&'a Thing>, doc_id: Option, doc: &'a Value) -> Self { + Self { + rid, + doc: Cow::Borrowed(doc), + doc_id, + } + } } impl<'a> Debug for Document<'a> { @@ -29,17 +46,22 @@ impl<'a> Debug for Document<'a> { impl<'a> From<&Document<'a>> for Vec { fn from(val: &Document<'a>) -> Vec { - val.current.as_ref().into() + val.current.doc.as_ref().into() } } impl<'a> Document<'a> { - pub fn new(id: Option<&'a Thing>, val: &'a Value, ext: Workable) -> Self { + pub fn new( + id: Option<&'a Thing>, + doc_id: Option, + val: &'a Value, + extras: Workable, + ) -> Self { Document { id, - extras: ext, - current: Cow::Borrowed(val), - initial: Cow::Borrowed(val), + extras, + current: CursorDoc::new(id, doc_id, val), + initial: CursorDoc::new(id, doc_id, val), } } } @@ -47,11 +69,11 @@ impl<'a> Document<'a> { impl<'a> Document<'a> { /// Check if document has changed pub fn changed(&self) -> bool { - self.initial != self.current + self.initial.doc != self.current.doc } /// Check if document has changed pub fn is_new(&self) -> bool { - self.initial.is_none() + self.initial.doc.is_none() } /// Get the table for this document pub async fn tb( diff --git a/lib/src/doc/edges.rs b/lib/src/doc/edges.rs index 6b01a971..f84b9a56 100644 --- a/lib/src/doc/edges.rs +++ b/lib/src/doc/edges.rs @@ -1,7 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; use crate::dbs::Workable; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::paths::EDGE; @@ -13,14 +13,13 @@ use crate::sql::Dir; impl<'a> Document<'a> { pub async fn edges( &mut self, - ctx: &Context<'_>, + _ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check if the table is a view - if self.tb(opt, &txn).await?.drop { + if self.tb(opt, txn).await?.drop { return Ok(()); } // Claim transaction @@ -44,9 +43,9 @@ impl<'a> Document<'a> { let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid); run.set(key, vec![]).await?; // Store the edges on the record - self.current.to_mut().put(&*EDGE, Value::Bool(true)); - self.current.to_mut().put(&*IN, l.clone().into()); - self.current.to_mut().put(&*OUT, r.clone().into()); + self.current.doc.to_mut().put(&*EDGE, Value::Bool(true)); + self.current.doc.to_mut().put(&*IN, l.clone().into()); + self.current.doc.to_mut().put(&*OUT, r.clone().into()); } // Carry on Ok(()) diff --git a/lib/src/doc/empty.rs b/lib/src/doc/empty.rs index cc19acf7..6b82863f 100644 --- a/lib/src/doc/empty.rs +++ b/lib/src/doc/empty.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::Transaction; use crate::doc::Document; use crate::err::Error; @@ -9,12 +10,13 @@ impl<'a> Document<'a> { &self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check if this record exists if self.id.is_some() { // There is no current record - if self.current.is_none() { + if self.current.doc.is_none() { // Ignore this requested record return Err(Error::Ignore); } diff --git a/lib/src/doc/erase.rs b/lib/src/doc/erase.rs index ce05abd7..c2775924 100644 --- a/lib/src/doc/erase.rs +++ b/lib/src/doc/erase.rs @@ -11,6 +11,6 @@ impl<'a> Document<'a> { _opt: &Options, _stm: &Statement<'_>, ) -> Result<(), Error> { - self.current.to_mut().clear() + self.current.doc.to_mut().clear() } } diff --git a/lib/src/doc/event.rs b/lib/src/doc/event.rs index d3f03116..17c4aa9e 100644 --- a/lib/src/doc/event.rs +++ b/lib/src/doc/event.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -11,6 +11,7 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Check events @@ -23,10 +24,8 @@ impl<'a> Document<'a> { } // Don't run permissions let opt = &opt.new_with_perms(false); - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Loop through all event statements - for ev in self.ev(opt, &txn).await?.iter() { + for ev in self.ev(opt, txn).await?.iter() { // Get the event action let met = if stm.is_delete() { Value::from("DELETE") @@ -38,16 +37,15 @@ impl<'a> Document<'a> { // Configure the context let mut ctx = Context::new(ctx); ctx.add_value("event", met); - ctx.add_value("value", self.current.deref()); - ctx.add_value("after", self.current.deref()); - ctx.add_value("before", self.initial.deref()); - ctx.add_cursor_doc(&self.current); + ctx.add_value("value", self.current.doc.deref()); + ctx.add_value("after", self.current.doc.deref()); + ctx.add_value("before", self.initial.doc.deref()); // Process conditional clause - let val = ev.when.compute(&ctx, opt).await?; + let val = ev.when.compute(&ctx, opt, txn, Some(&self.current)).await?; // Execute event if value is truthy if val.is_truthy() { for v in ev.then.iter() { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, Some(&self.current)).await?; } } } diff --git a/lib/src/doc/exist.rs b/lib/src/doc/exist.rs index e762baee..f813cd6e 100644 --- a/lib/src/doc/exist.rs +++ b/lib/src/doc/exist.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; @@ -9,12 +9,13 @@ impl<'a> Document<'a> { &self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check if this record exists if let Some(id) = &self.id { // If there is a current value - if self.current.is_some() { + if self.current.doc.is_some() { // The record already exists return Err(Error::RecordExists { thing: id.to_string(), diff --git a/lib/src/doc/field.rs b/lib/src/doc/field.rs index 53057f0d..52ddf798 100644 --- a/lib/src/doc/field.rs +++ b/lib/src/doc/field.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::permission::Permission; @@ -11,6 +11,7 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check fields @@ -20,15 +21,13 @@ impl<'a> Document<'a> { // Get the record id let rid = self.id.as_ref().unwrap(); // Get the user applied input - let inp = self.initial.changed(self.current.as_ref()); - // Clone transaction - let txn = ctx.try_clone_transaction()?; + let inp = self.initial.doc.changed(self.current.doc.as_ref()); // Loop through all field statements - for fd in self.fd(opt, &txn).await?.iter() { + for fd in self.fd(opt, txn).await?.iter() { // Loop over each field in document - for (k, mut val) in self.current.walk(&fd.name).into_iter() { + for (k, mut val) in self.current.doc.walk(&fd.name).into_iter() { // Get the initial value - let old = self.initial.pick(&k); + let old = self.initial.doc.pick(&k); // Get the input value let inp = inp.pick(&k); // Check for a TYPE clause @@ -58,9 +57,8 @@ impl<'a> Document<'a> { ctx.add_value("value", &val); ctx.add_value("after", &val); ctx.add_value("before", &old); - ctx.add_cursor_doc(&self.current); // Process the VALUE clause - val = expr.compute(&ctx, opt).await?; + val = expr.compute(&ctx, opt, txn, Some(&self.current)).await?; } // Check for a TYPE clause if let Some(kind) = &fd.kind { @@ -87,9 +85,8 @@ impl<'a> Document<'a> { ctx.add_value("value", &val); ctx.add_value("after", &val); ctx.add_value("before", &old); - ctx.add_cursor_doc(&self.current); // Process the ASSERT clause - if !expr.compute(&ctx, opt).await?.is_truthy() { + if !expr.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() { return Err(Error::FieldValue { thing: rid.to_string(), field: fd.name.clone(), @@ -119,9 +116,8 @@ impl<'a> Document<'a> { ctx.add_value("value", &val); ctx.add_value("after", &val); ctx.add_value("before", &old); - ctx.add_cursor_doc(&self.current); // Process the PERMISSION clause - if !e.compute(&ctx, opt).await?.is_truthy() { + if !e.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() { val = old } } @@ -129,8 +125,8 @@ impl<'a> Document<'a> { } // Set the value of the field match val { - Value::None => self.current.to_mut().del(ctx, opt, &k).await?, - _ => self.current.to_mut().set(ctx, opt, &k, val).await?, + Value::None => self.current.doc.to_mut().del(ctx, opt, txn, &k).await?, + _ => self.current.doc.to_mut().set(ctx, opt, txn, &k, val).await?, }; } } diff --git a/lib/src/doc/index.rs b/lib/src/doc/index.rs index df3c310c..e4a72154 100644 --- a/lib/src/doc/index.rs +++ b/lib/src/doc/index.rs @@ -1,7 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; -use crate::doc::Document; +use crate::dbs::{Options, Transaction}; +use crate::doc::{CursorDoc, Document}; use crate::err::Error; use crate::idx::ft::FtIndex; use crate::idx::IndexKeyBase; @@ -9,7 +9,7 @@ use crate::sql::array::Array; use crate::sql::index::Index; use crate::sql::scoring::Scoring; use crate::sql::statements::DefineIndexStatement; -use crate::sql::{Ident, Thing, Value}; +use crate::sql::{Ident, Thing}; use crate::{key, kvs}; impl<'a> Document<'a> { @@ -17,6 +17,7 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check indexes @@ -27,21 +28,19 @@ impl<'a> Document<'a> { if !opt.force && !self.changed() { return Ok(()); } - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check if the table is a view - if self.tb(opt, &txn).await?.drop { + if self.tb(opt, txn).await?.drop { return Ok(()); } // Get the record id let rid = self.id.as_ref().unwrap(); // Loop through all index statements - for ix in self.ix(opt, &txn).await?.iter() { + for ix in self.ix(opt, txn).await?.iter() { // Calculate old values - let o = Self::build_opt_array(ctx, opt, ix, &self.initial).await?; + let o = Self::build_opt_array(ctx, opt, txn, ix, &self.initial).await?; // Calculate new values - let n = Self::build_opt_array(ctx, opt, ix, &self.current).await?; + let n = Self::build_opt_array(ctx, opt, txn, ix, &self.current).await?; // Update the index entries if opt.force || o != n { @@ -75,17 +74,16 @@ impl<'a> Document<'a> { async fn build_opt_array( ctx: &Context<'_>, opt: &Options, + txn: &Transaction, ix: &DefineIndexStatement, - value: &Value, + doc: &CursorDoc<'_>, ) -> Result, Error> { - if !value.is_some() { + if !doc.doc.is_some() { return Ok(None); } - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(value); let mut o = Array::with_capacity(ix.cols.len()); for i in ix.cols.iter() { - let v = i.compute(&ctx, opt).await?; + let v = i.compute(ctx, opt, txn, Some(doc)).await?; o.push(v); } Ok(Some(o)) diff --git a/lib/src/doc/insert.rs b/lib/src/doc/insert.rs index db75efc8..695e5b9f 100644 --- a/lib/src/doc/insert.rs +++ b/lib/src/doc/insert.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,63 +10,64 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check current record - match self.current.is_some() { + match self.current.doc.is_some() { // Run INSERT clause false => { // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Merge record data - self.merge(ctx, opt, stm).await?; + self.merge(ctx, opt, txn, stm).await?; // Merge fields data - self.field(ctx, opt, stm).await?; + self.field(ctx, opt, txn, stm).await?; // Reset fields data - self.reset(ctx, opt, stm).await?; + self.reset(ctx, opt, txn, stm).await?; // Clean fields data - self.clean(ctx, opt, stm).await?; + self.clean(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Store index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Store record data - self.store(ctx, opt, stm).await?; + self.store(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } // Run UPDATE clause true => { // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Alter record data - self.alter(ctx, opt, stm).await?; + self.alter(ctx, opt, txn, stm).await?; // Merge fields data - self.field(ctx, opt, stm).await?; + self.field(ctx, opt, txn, stm).await?; // Reset fields data - self.reset(ctx, opt, stm).await?; + self.reset(ctx, opt, txn, stm).await?; // Clean fields data - self.clean(ctx, opt, stm).await?; + self.clean(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Store index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Store record data - self.store(ctx, opt, stm).await?; + self.store(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } } diff --git a/lib/src/doc/lives.rs b/lib/src/doc/lives.rs index 8caaf99a..480d33f1 100644 --- a/lib/src/doc/lives.rs +++ b/lib/src/doc/lives.rs @@ -1,8 +1,8 @@ use crate::ctx::Context; -use crate::dbs::Action; use crate::dbs::Notification; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Action, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::Value; @@ -12,14 +12,13 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Check if forced if !opt.force && !self.changed() { return Ok(()); } - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Get the record id let rid = self.id.as_ref().unwrap(); // Check if we can send notifications @@ -27,11 +26,11 @@ impl<'a> Document<'a> { // Clone the sending channel let chn = chn.clone(); // Loop through all index statements - for lv in self.lv(opt, &txn).await?.iter() { + for lv in self.lv(opt, txn).await?.iter() { // Create a new statement let lq = Statement::from(lv); // Check LIVE SELECT where condition - if self.check(ctx, opt, &lq).await.is_err() { + if self.check(ctx, opt, txn, &lq).await.is_err() { continue; } // Check what type of data change this is @@ -54,7 +53,7 @@ impl<'a> Document<'a> { chn.send(Notification { id: lv.id.0, action: Action::Create, - result: self.pluck(ctx, opt, &lq).await?, + result: self.pluck(ctx, opt, txn, &lq).await?, }) .await?; } else { @@ -66,7 +65,7 @@ impl<'a> Document<'a> { chn.send(Notification { id: lv.id.0, action: Action::Update, - result: self.pluck(ctx, opt, &lq).await?, + result: self.pluck(ctx, opt, txn, &lq).await?, }) .await?; } else { diff --git a/lib/src/doc/merge.rs b/lib/src/doc/merge.rs index d511317f..1ab4c0de 100644 --- a/lib/src/doc/merge.rs +++ b/lib/src/doc/merge.rs @@ -1,7 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; use crate::dbs::Workable; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; @@ -10,21 +10,20 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Get the record id let rid = self.id.as_ref().unwrap(); // Set default field values - self.current.to_mut().def(rid); + self.current.doc.to_mut().def(rid); // This is an INSERT statement if let Workable::Insert(v) = &self.extras { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - let v = v.compute(&ctx, opt).await?; - self.current.to_mut().merge(v)?; + let v = v.compute(ctx, opt, txn, Some(&self.current)).await?; + self.current.doc.to_mut().merge(v)?; } // Set default field values - self.current.to_mut().def(rid); + self.current.doc.to_mut().def(rid); // Carry on Ok(()) } diff --git a/lib/src/doc/pluck.rs b/lib/src/doc/pluck.rs index ac21586b..e260effa 100644 --- a/lib/src/doc/pluck.rs +++ b/lib/src/doc/pluck.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::idiom::Idiom; @@ -14,6 +14,7 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Ensure futures are run @@ -23,56 +24,34 @@ impl<'a> Document<'a> { Some(v) => match v { Output::None => Err(Error::Ignore), Output::Null => Ok(Value::Null), - Output::Diff => Ok(self.initial.diff(&self.current, Idiom::default()).into()), - Output::After => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - self.current.compute(&ctx, opt).await + Output::Diff => { + Ok(self.initial.doc.diff(self.current.doc.as_ref(), Idiom::default()).into()) } + Output::After => self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await, Output::Before => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.initial); - self.initial.compute(&ctx, opt).await - } - Output::Fields(v) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - v.compute(&ctx, opt, false).await + self.initial.doc.compute(ctx, opt, txn, Some(&self.initial)).await } + Output::Fields(v) => v.compute(ctx, opt, txn, Some(&self.current), false).await, }, None => match stm { Statement::Live(s) => match s.expr.len() { - 0 => Ok(self.initial.diff(&self.current, Idiom::default()).into()), - _ => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - s.expr.compute(&ctx, opt, false).await - } + 0 => Ok(self.initial.doc.diff(&self.current.doc, Idiom::default()).into()), + _ => s.expr.compute(ctx, opt, txn, Some(&self.current), false).await, }, Statement::Select(s) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - s.expr.compute(&ctx, opt, s.group.is_some()).await + s.expr.compute(ctx, opt, txn, Some(&self.current), s.group.is_some()).await } Statement::Create(_) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - self.current.compute(&ctx, opt).await + self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await } Statement::Update(_) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - self.current.compute(&ctx, opt).await + self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await } Statement::Relate(_) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - self.current.compute(&ctx, opt).await + self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await } Statement::Insert(_) => { - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); - self.current.compute(&ctx, opt).await + self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await } _ => Err(Error::Ignore), }, @@ -81,28 +60,29 @@ impl<'a> Document<'a> { if self.id.is_some() { // Should we run permissions checks? if opt.perms && opt.auth.perms() { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Loop through all field statements - for fd in self.fd(opt, &txn).await?.iter() { + for fd in self.fd(opt, txn).await?.iter() { // Loop over each field in document for k in out.each(&fd.name).iter() { // Process the field permissions match &fd.permissions.select { Permission::Full => (), - Permission::None => out.del(ctx, opt, k).await?, + Permission::None => out.del(ctx, opt, txn, k).await?, Permission::Specific(e) => { // Disable permissions let opt = &opt.new_with_perms(false); // Get the current value - let val = self.current.pick(k); + let val = self.current.doc.pick(k); // Configure the context let mut ctx = Context::new(ctx); ctx.add_value("value", &val); - ctx.add_cursor_doc(&self.current); // Process the PERMISSION clause - if !e.compute(&ctx, opt).await?.is_truthy() { - out.del(&ctx, opt, k).await? + if !e + .compute(&ctx, opt, txn, Some(&self.current)) + .await? + .is_truthy() + { + out.del(&ctx, opt, txn, k).await? } } } @@ -111,7 +91,7 @@ impl<'a> Document<'a> { } } // Remove metadata fields on output - out.del(ctx, opt, &*META).await?; + out.del(ctx, opt, txn, &*META).await?; // Output result Ok(out) } diff --git a/lib/src/doc/purge.rs b/lib/src/doc/purge.rs index 9d8416ad..dbdafb20 100644 --- a/lib/src/doc/purge.rs +++ b/lib/src/doc/purge.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::dir::Dir; @@ -17,16 +17,15 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check if forced if !opt.force && !self.changed() { return Ok(()); } - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check if the table is a view - if self.tb(opt, &txn).await?.drop { + if self.tb(opt, txn).await?.drop { return Ok(()); } // Clone transaction @@ -39,7 +38,11 @@ impl<'a> Document<'a> { let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id); run.del(key).await?; // Purge the record edges - match (self.initial.pick(&*EDGE), self.initial.pick(&*IN), self.initial.pick(&*OUT)) { + match ( + self.initial.doc.pick(&*EDGE), + self.initial.doc.pick(&*IN), + self.initial.doc.pick(&*OUT), + ) { (Value::Bool(true), Value::Thing(ref l), Value::Thing(ref r)) => { // Get temporary edge references let (ref o, ref i) = (Dir::Out, Dir::In); @@ -69,7 +72,7 @@ impl<'a> Document<'a> { ..DeleteStatement::default() }; // Execute the delete statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } } diff --git a/lib/src/doc/relate.rs b/lib/src/doc/relate.rs index 5a96e5b6..0f8d3559 100644 --- a/lib/src/doc/relate.rs +++ b/lib/src/doc/relate.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,33 +10,34 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Alter record data - self.alter(ctx, opt, stm).await?; + self.alter(ctx, opt, txn, stm).await?; // Merge fields data - self.field(ctx, opt, stm).await?; + self.field(ctx, opt, txn, stm).await?; // Reset fields data - self.reset(ctx, opt, stm).await?; + self.reset(ctx, opt, txn, stm).await?; // Clean fields data - self.clean(ctx, opt, stm).await?; + self.clean(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Store record edges - self.edges(ctx, opt, stm).await?; + self.edges(ctx, opt, txn, stm).await?; // Store index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Store record data - self.store(ctx, opt, stm).await?; + self.store(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } diff --git a/lib/src/doc/reset.rs b/lib/src/doc/reset.rs index 973ca84c..4c3b0367 100644 --- a/lib/src/doc/reset.rs +++ b/lib/src/doc/reset.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::Transaction; use crate::doc::Document; use crate::err::Error; use crate::sql::paths::EDGE; @@ -13,17 +14,18 @@ impl<'a> Document<'a> { &mut self, _ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Get the record id let rid = self.id.as_ref().unwrap(); // Set default field values - self.current.to_mut().def(rid); + self.current.doc.to_mut().def(rid); // Ensure edge fields are reset - if self.initial.pick(&*EDGE).is_true() { - self.current.to_mut().put(&*EDGE, Value::Bool(true)); - self.current.to_mut().put(&*IN, self.initial.pick(&*IN)); - self.current.to_mut().put(&*OUT, self.initial.pick(&*OUT)); + if self.initial.doc.pick(&*EDGE).is_true() { + self.current.doc.to_mut().put(&*EDGE, Value::Bool(true)); + self.current.doc.to_mut().put(&*IN, self.initial.doc.pick(&*IN)); + self.current.doc.to_mut().put(&*OUT, self.initial.doc.pick(&*OUT)); } // Carry on Ok(()) diff --git a/lib/src/doc/select.rs b/lib/src/doc/select.rs index 774b215c..abe325f3 100644 --- a/lib/src/doc/select.rs +++ b/lib/src/doc/select.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,15 +10,16 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check if record exists - self.empty(ctx, opt, stm).await?; + self.empty(ctx, opt, txn, stm).await?; // Check where clause - self.check(ctx, opt, stm).await?; + self.check(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } diff --git a/lib/src/doc/store.rs b/lib/src/doc/store.rs index 128fb903..8aee1767 100644 --- a/lib/src/doc/store.rs +++ b/lib/src/doc/store.rs @@ -1,24 +1,23 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; impl<'a> Document<'a> { pub async fn store( &self, - ctx: &Context<'_>, + _ctx: &Context<'_>, opt: &Options, + txn: &Transaction, _stm: &Statement<'_>, ) -> Result<(), Error> { // Check if forced if !opt.force && !self.changed() { return Ok(()); } - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Check if the table is a view - if self.tb(opt, &txn).await?.drop { + if self.tb(opt, txn).await?.drop { return Ok(()); } // Claim transaction diff --git a/lib/src/doc/table.rs b/lib/src/doc/table.rs index 987c4343..b71b63eb 100644 --- a/lib/src/doc/table.rs +++ b/lib/src/doc/table.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::data::Data; @@ -33,6 +33,7 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result<(), Error> { // Check tables @@ -55,43 +56,41 @@ impl<'a> Document<'a> { } else { Action::Update }; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Loop through all foreign table statements - for ft in self.ft(opt, &txn).await?.iter() { + for ft in self.ft(opt, txn).await?.iter() { // Get the table definition let tb = ft.view.as_ref().unwrap(); // Check if there is a GROUP BY clause match &tb.group { // There is a GROUP BY clause specified Some(group) => { - let mut initial_ctx = Context::new(ctx); - initial_ctx.add_cursor_doc(&self.initial); // Set the previous record id let old = Thing { tb: ft.name.to_raw(), - id: try_join_all(group.iter().map(|v| v.compute(&initial_ctx, opt))) - .await? - .into_iter() - .collect::>() - .into(), + id: try_join_all( + group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.initial))), + ) + .await? + .into_iter() + .collect::>() + .into(), }; - let mut current_ctx = Context::new(ctx); - current_ctx.add_cursor_doc(&self.current); // Set the current record id let rid = Thing { tb: ft.name.to_raw(), - id: try_join_all(group.iter().map(|v| v.compute(¤t_ctx, opt))) - .await? - .into_iter() - .collect::>() - .into(), + id: try_join_all( + group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.current))), + ) + .await? + .into_iter() + .collect::>() + .into(), }; // Check if a WHERE clause is specified match &tb.cond { // There is a WHERE clause specified Some(cond) => { - match cond.compute(¤t_ctx, opt).await? { + match cond.compute(ctx, opt, txn, Some(&self.current)).await? { v if v.is_truthy() => { if !opt.force && act != Action::Create { // Delete the old value @@ -99,11 +98,13 @@ impl<'a> Document<'a> { // Modify the value in the table let stm = UpdateStatement { what: Values(vec![Value::from(old)]), - data: Some(self.data(ctx, opt, act, &tb.expr).await?), + data: Some( + self.data(ctx, opt, txn, act, &tb.expr).await?, + ), ..UpdateStatement::default() }; // Execute the statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } if act != Action::Delete { // Update the new value @@ -111,11 +112,13 @@ impl<'a> Document<'a> { // Modify the value in the table let stm = UpdateStatement { what: Values(vec![Value::from(rid)]), - data: Some(self.data(ctx, opt, act, &tb.expr).await?), + data: Some( + self.data(ctx, opt, txn, act, &tb.expr).await?, + ), ..UpdateStatement::default() }; // Execute the statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } _ => { @@ -125,11 +128,13 @@ impl<'a> Document<'a> { // Modify the value in the table let stm = UpdateStatement { what: Values(vec![Value::from(old)]), - data: Some(self.data(ctx, opt, act, &tb.expr).await?), + data: Some( + self.data(ctx, opt, txn, act, &tb.expr).await?, + ), ..UpdateStatement::default() }; // Execute the statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } } @@ -142,11 +147,11 @@ impl<'a> Document<'a> { // Modify the value in the table let stm = UpdateStatement { what: Values(vec![Value::from(old)]), - data: Some(self.data(ctx, opt, act, &tb.expr).await?), + data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?), ..UpdateStatement::default() }; // Execute the statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } if act != Action::Delete { // Update the new value @@ -154,11 +159,11 @@ impl<'a> Document<'a> { // Modify the value in the table let stm = UpdateStatement { what: Values(vec![Value::from(rid)]), - data: Some(self.data(ctx, opt, act, &tb.expr).await?), + data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?), ..UpdateStatement::default() }; // Execute the statement - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } } @@ -171,13 +176,11 @@ impl<'a> Document<'a> { id: rid.id.clone(), }; // Use the current record data - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(&self.current); // Check if a WHERE clause is specified match &tb.cond { // There is a WHERE clause specified Some(cond) => { - match cond.compute(&ctx, opt).await? { + match cond.compute(ctx, opt, txn, Some(&self.current)).await? { v if v.is_truthy() => { // Define the statement let stm = match act { @@ -190,13 +193,21 @@ impl<'a> Document<'a> { _ => Query::Update(UpdateStatement { what: Values(vec![Value::from(rid)]), data: Some(Data::ReplaceExpression( - tb.expr.compute(&ctx, opt, false).await?, + tb.expr + .compute( + ctx, + opt, + txn, + Some(&self.current), + false, + ) + .await?, )), ..UpdateStatement::default() }), }; // Execute the statement - stm.compute(&ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } _ => { // Delete the value in the table @@ -205,7 +216,7 @@ impl<'a> Document<'a> { ..DeleteStatement::default() }; // Execute the statement - stm.compute(&ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } } @@ -222,13 +233,15 @@ impl<'a> Document<'a> { _ => Query::Update(UpdateStatement { what: Values(vec![Value::from(rid)]), data: Some(Data::ReplaceExpression( - tb.expr.compute(&ctx, opt, false).await?, + tb.expr + .compute(ctx, opt, txn, Some(&self.current), false) + .await?, )), ..UpdateStatement::default() }), }; // Execute the statement - stm.compute(&ctx, opt).await?; + stm.compute(ctx, opt, txn, None).await?; } } } @@ -242,16 +255,16 @@ impl<'a> Document<'a> { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, act: Action, exp: &Fields, ) -> Result { // let mut ops: Ops = vec![]; // Create a new context with the initial or the current doc - let mut ctx = Context::new(ctx); - match act { - Action::Delete => ctx.add_cursor_doc(self.initial.as_ref()), - Action::Update => ctx.add_cursor_doc(self.current.as_ref()), + let doc = match act { + Action::Delete => Some(&self.initial), + Action::Update => Some(&self.current), _ => unreachable!(), }; // @@ -266,29 +279,29 @@ impl<'a> Document<'a> { match expr { Value::Function(f) if f.is_rolling() => match f.name() { "count" => { - let val = f.compute(&ctx, opt).await?; + let val = f.compute(ctx, opt, txn, doc).await?; self.chg(&mut ops, &act, idiom, val); } "math::sum" => { - let val = f.args()[0].compute(&ctx, opt).await?; + let val = f.args()[0].compute(ctx, opt, txn, doc).await?; self.chg(&mut ops, &act, idiom, val); } "math::min" => { - let val = f.args()[0].compute(&ctx, opt).await?; + let val = f.args()[0].compute(ctx, opt, txn, doc).await?; self.min(&mut ops, &act, idiom, val); } "math::max" => { - let val = f.args()[0].compute(&ctx, opt).await?; + let val = f.args()[0].compute(ctx, opt, txn, doc).await?; self.max(&mut ops, &act, idiom, val); } "math::mean" => { - let val = f.args()[0].compute(&ctx, opt).await?; + let val = f.args()[0].compute(ctx, opt, txn, doc).await?; self.mean(&mut ops, &act, idiom, val); } _ => unreachable!(), }, _ => { - let val = expr.compute(&ctx, opt).await?; + let val = expr.compute(ctx, opt, txn, doc).await?; self.set(&mut ops, idiom, val); } } diff --git a/lib/src/doc/update.rs b/lib/src/doc/update.rs index 900cf949..569cee1b 100644 --- a/lib/src/doc/update.rs +++ b/lib/src/doc/update.rs @@ -1,6 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Options, Transaction}; use crate::doc::Document; use crate::err::Error; use crate::sql::value::Value; @@ -10,33 +10,34 @@ impl<'a> Document<'a> { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, stm: &Statement<'_>, ) -> Result { // Check where clause - self.check(ctx, opt, stm).await?; + self.check(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Alter record data - self.alter(ctx, opt, stm).await?; + self.alter(ctx, opt, txn, stm).await?; // Merge fields data - self.field(ctx, opt, stm).await?; + self.field(ctx, opt, txn, stm).await?; // Reset fields data - self.reset(ctx, opt, stm).await?; + self.reset(ctx, opt, txn, stm).await?; // Clean fields data - self.clean(ctx, opt, stm).await?; + self.clean(ctx, opt, txn, stm).await?; // Check if allowed - self.allow(ctx, opt, stm).await?; + self.allow(ctx, opt, txn, stm).await?; // Store index data - self.index(ctx, opt, stm).await?; + self.index(ctx, opt, txn, stm).await?; // Store record data - self.store(ctx, opt, stm).await?; + self.store(ctx, opt, txn, stm).await?; // Run table queries - self.table(ctx, opt, stm).await?; + self.table(ctx, opt, txn, stm).await?; // Run lives queries - self.lives(ctx, opt, stm).await?; + self.lives(ctx, opt, txn, stm).await?; // Run event queries - self.event(ctx, opt, stm).await?; + self.event(ctx, opt, txn, stm).await?; // Yield document - self.pluck(ctx, opt, stm).await + self.pluck(ctx, opt, txn, stm).await } } diff --git a/lib/src/fnc/mod.rs b/lib/src/fnc/mod.rs index 70c32f37..3c5ce25d 100644 --- a/lib/src/fnc/mod.rs +++ b/lib/src/fnc/mod.rs @@ -1,5 +1,7 @@ //! Executes functions from SQL. If there is an SQL function it will be defined in this module. use crate::ctx::Context; +use crate::dbs::Transaction; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::value::Value; @@ -29,7 +31,13 @@ pub mod r#type; pub mod util; /// Attempts to run any function -pub async fn run(ctx: &Context<'_>, name: &str, args: Vec) -> Result { +pub async fn run( + ctx: &Context<'_>, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + name: &str, + args: Vec, +) -> Result { if name.eq("sleep") || name.starts_with("search") || name.starts_with("http") @@ -38,7 +46,7 @@ pub async fn run(ctx: &Context<'_>, name: &str, args: Vec) -> Result, name: &str, args: Vec) -> Result, name: &str, args: Vec) -> Result { +pub async fn asynchronous( + ctx: &Context<'_>, + txn: Option<&Transaction>, + doc: Option<&CursorDoc<'_>>, + name: &str, + args: Vec, +) -> Result { // Wrappers return a function as opposed to a value so that the dispatch! method can always // perform a function call. #[cfg(not(target_arch = "wasm32"))] @@ -302,9 +316,9 @@ pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec) -> Re "http::patch" => http::patch(ctx).await, "http::delete" => http::delete(ctx).await, // - "search::score" => search::score(ctx).await, - "search::highlight" => search::highlight(ctx).await, - "search::offsets" => search::offsets(ctx).await, + "search::score" => search::score((ctx, txn, doc)).await, + "search::highlight" => search::highlight((ctx,txn, doc)).await, + "search::offsets" => search::offsets((ctx, txn, doc)).await, // "sleep" => sleep::sleep(ctx).await, ) diff --git a/lib/src/fnc/operate.rs b/lib/src/fnc/operate.rs index 03da5645..07ff67de 100644 --- a/lib/src/fnc/operate.rs +++ b/lib/src/fnc/operate.rs @@ -1,4 +1,6 @@ use crate::ctx::Context; +use crate::dbs::Transaction; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::value::TryAdd; use crate::sql::value::TryDiv; @@ -165,13 +167,18 @@ pub fn intersects(a: &Value, b: &Value) -> Result { Ok(a.intersects(b).into()) } -pub(crate) async fn matches(ctx: &Context<'_>, e: &Expression) -> Result { - if let Some(thg) = ctx.thing() { - if let Some(exe) = ctx.get_query_executor(&thg.tb) { - // Clone transaction - let txn = ctx.try_clone_transaction()?; - // Check the matches - return exe.matches(&txn, thg, e).await; +pub(crate) async fn matches( + ctx: &Context<'_>, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + e: &Expression, +) -> Result { + if let Some(doc) = doc { + if let Some(thg) = doc.rid { + if let Some(exe) = ctx.get_query_executor(&thg.tb) { + // Check the matches + return exe.matches(txn, thg, e).await; + } } } Ok(Value::Bool(false)) diff --git a/lib/src/fnc/script/main.rs b/lib/src/fnc/script/main.rs index 2cde0b5a..6f837d94 100644 --- a/lib/src/fnc/script/main.rs +++ b/lib/src/fnc/script/main.rs @@ -5,7 +5,8 @@ use super::modules; use super::modules::loader; use super::modules::resolver; use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::value::Value; use js::async_with; @@ -19,6 +20,8 @@ use js::Module; pub async fn run( ctx: &Context<'_>, _opt: &Options, + _txn: &Transaction, + doc: Option<&CursorDoc<'_>>, src: &str, arg: Vec, ) -> Result { @@ -26,8 +29,6 @@ pub async fn run( if ctx.is_done() { return Ok(Value::None); } - // Get the optional doc - let doc = ctx.doc(); // Create an JavaScript context let run = js::AsyncRuntime::new().unwrap(); // Explicitly set max stack size to 256 KiB @@ -68,6 +69,8 @@ pub async fn run( let res = ctx.compile("script", src)?; // Attempt to fetch the main export let fnc = res.get::<_, Function>("default")?; + // Extract the doc if any + let doc = doc.map(|v|v.doc.as_ref()); // Execute the main function let promise: Promise = fnc.call((This(doc), Rest(arg)))?; promise.await diff --git a/lib/src/fnc/script/modules/surrealdb/functions/mod.rs b/lib/src/fnc/script/modules/surrealdb/functions/mod.rs index ea404380..cde9cf38 100644 --- a/lib/src/fnc/script/modules/surrealdb/functions/mod.rs +++ b/lib/src/fnc/script/modules/surrealdb/functions/mod.rs @@ -68,7 +68,7 @@ async fn fut(js_ctx: js::Ctx<'_>, name: &str, args: Vec) -> Result // Create a default context let ctx = Context::background(); // Process the called function - let res = fnc::asynchronous(&ctx, name, args).await; + let res = fnc::asynchronous(&ctx, None, None, name, args).await; // Convert any response error res.map_err(|err| { js::Exception::from_message(js_ctx, &err.to_string()) diff --git a/lib/src/fnc/search.rs b/lib/src/fnc/search.rs index d5736619..771cb33d 100644 --- a/lib/src/fnc/search.rs +++ b/lib/src/fnc/search.rs @@ -1,37 +1,54 @@ use crate::ctx::Context; +use crate::dbs::Transaction; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::Value; -pub async fn score(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result { - if let Some(thg) = ctx.thing() { - if let Some(exe) = ctx.get_query_executor(&thg.tb) { - let txn = ctx.try_clone_transaction()?; - return exe.score(txn, &match_ref, thg, ctx.doc_id()).await; - } - } - Ok(Value::None) -} - -pub async fn highlight( - ctx: &Context<'_>, - (prefix, suffix, match_ref): (Value, Value, Value), +pub async fn score( + (ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>), + (match_ref,): (Value,), ) -> Result { - if let Some(doc) = ctx.doc() { - if let Some(thg) = ctx.thing() { - if let Some(exe) = ctx.get_query_executor(&thg.tb) { - let txn = ctx.try_clone_transaction()?; - return exe.highlight(txn, thg, prefix, suffix, &match_ref, doc).await; + if let Some(txn) = txn { + if let Some(doc) = doc { + if let Some(thg) = doc.rid { + if let Some(exe) = ctx.get_query_executor(&thg.tb) { + return exe.score(txn, &match_ref, thg, doc.doc_id).await; + } } } } Ok(Value::None) } -pub async fn offsets(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result { - if let Some(thg) = ctx.thing() { - if let Some(exe) = ctx.get_query_executor(&thg.tb) { - let txn = ctx.try_clone_transaction()?; - return exe.offsets(txn, thg, &match_ref).await; +pub async fn highlight( + (ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>), + (prefix, suffix, match_ref): (Value, Value, Value), +) -> Result { + if let Some(txn) = txn { + if let Some(doc) = doc { + if let Some(thg) = doc.rid { + if let Some(exe) = ctx.get_query_executor(&thg.tb) { + return exe + .highlight(txn, thg, prefix, suffix, &match_ref, doc.doc.as_ref()) + .await; + } + } + } + } + Ok(Value::None) +} + +pub async fn offsets( + (ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>), + (match_ref,): (Value,), +) -> Result { + if let Some(txn) = txn { + if let Some(doc) = doc { + if let Some(thg) = doc.rid { + if let Some(exe) = ctx.get_query_executor(&thg.tb) { + return exe.offsets(txn, thg, &match_ref).await; + } + } } } Ok(Value::None) diff --git a/lib/src/idx/bkeys.rs b/lib/src/idx/bkeys.rs index 4c6c913b..a5d18c5e 100644 --- a/lib/src/idx/bkeys.rs +++ b/lib/src/idx/bkeys.rs @@ -1,7 +1,6 @@ use crate::err::Error; use crate::idx::btree::Payload; use crate::kvs::Key; -use async_trait::async_trait; use fst::{IntoStreamer, Map, MapBuilder, Streamer}; use radix_trie::{SubTrie, Trie, TrieCommon}; use serde::{de, ser, Deserialize, Serialize}; @@ -361,7 +360,6 @@ impl Display for TrieKeys { } } -#[async_trait] impl BKeys for TrieKeys { fn with_key_val(key: Key, payload: Payload) -> Result { let mut trie_keys = Self { diff --git a/lib/src/idx/btree.rs b/lib/src/idx/btree.rs index bdaa999f..e17020e6 100644 --- a/lib/src/idx/btree.rs +++ b/lib/src/idx/btree.rs @@ -1,9 +1,8 @@ use crate::err::Error; use crate::idx::bkeys::BKeys; -use crate::idx::SerdeState; +use crate::idx::{IndexKeyBase, SerdeState}; use crate::kvs::{Key, Transaction}; use crate::sql::{Object, Value}; -use async_trait::async_trait; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::collections::VecDeque; @@ -12,13 +11,39 @@ use std::fmt::Debug; pub(crate) type NodeId = u64; pub(super) type Payload = u64; -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -pub(super) trait KeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key; - fn get_state_key(&self) -> Key { - panic!("Not supported") +#[derive(Clone)] +pub(super) enum KeyProvider { + DocIds(IndexKeyBase), + DocLengths(IndexKeyBase), + Postings(IndexKeyBase), + Terms(IndexKeyBase), + #[cfg(test)] + Debug, +} + +impl KeyProvider { + pub(super) fn get_node_key(&self, node_id: NodeId) -> Key { + match self { + KeyProvider::DocIds(ikb) => ikb.new_bd_key(Some(node_id)), + KeyProvider::DocLengths(ikb) => ikb.new_bl_key(Some(node_id)), + KeyProvider::Postings(ikb) => ikb.new_bp_key(Some(node_id)), + KeyProvider::Terms(ikb) => ikb.new_bt_key(Some(node_id)), + #[cfg(test)] + KeyProvider::Debug => node_id.to_be_bytes().to_vec(), + } } + + pub(super) fn get_state_key(&self) -> Key { + match self { + KeyProvider::DocIds(ikb) => ikb.new_bd_key(None), + KeyProvider::DocLengths(ikb) => ikb.new_bl_key(None), + KeyProvider::Postings(ikb) => ikb.new_bp_key(None), + KeyProvider::Terms(ikb) => ikb.new_bt_key(None), + #[cfg(test)] + KeyProvider::Debug => "".into(), + } + } + async fn load_node(&self, tx: &mut Transaction, id: NodeId) -> Result, Error> where BK: BKeys + Serialize + DeserializeOwned, @@ -34,11 +59,8 @@ pub(super) trait KeyProvider { } } -pub(super) struct BTree -where - K: KeyProvider + Clone, -{ - keys: K, +pub(super) struct BTree { + keys: KeyProvider, state: State, full_size: u32, updated: bool, @@ -164,11 +186,8 @@ where median_key: Key, } -impl BTree -where - K: KeyProvider + Clone + Sync, -{ - pub(super) fn new(keys: K, state: State) -> Self { +impl BTree { + pub(super) fn new(keys: KeyProvider, state: State) -> Self { Self { keys, full_size: state.minimum_degree * 2 - 1, @@ -730,18 +749,6 @@ mod tests { use std::collections::{HashMap, VecDeque}; use test_log::test; - #[derive(Clone)] - struct TestKeyProvider {} - - impl KeyProvider for TestKeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key { - node_id.to_be_bytes().to_vec() - } - fn get_state_key(&self) -> Key { - "".into() - } - } - #[test] fn test_btree_state_serde() { let s = State::new(3); @@ -766,15 +773,14 @@ mod tests { let _: Node = Node::try_from_val(val).unwrap(); } - async fn insertions_test( + async fn insertions_test( tx: &mut Transaction, - t: &mut BTree, + t: &mut BTree, samples_size: usize, sample_provider: F, ) where F: Fn(usize) -> (Key, Payload), BK: BKeys + Serialize + DeserializeOwned + Default, - K: KeyProvider + Clone + Sync, { for i in 0..samples_size { let (key, payload) = sample_provider(i); @@ -791,10 +797,10 @@ mod tests { #[test(tokio::test)] async fn test_btree_fst_small_order_sequential_insertions() { - let mut t = BTree::new(TestKeyProvider {}, State::new(5)); + let mut t = BTree::new(KeyProvider::Debug, State::new(5)); let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, get_key_value).await; + insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, get_key_value).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); assert_eq!( @@ -810,10 +816,10 @@ mod tests { #[test(tokio::test)] async fn test_btree_trie_small_order_sequential_insertions() { - let mut t = BTree::new(TestKeyProvider {}, State::new(6)); + let mut t = BTree::new(KeyProvider::Debug, State::new(6)); let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, get_key_value).await; + insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, get_key_value).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); assert_eq!( @@ -831,11 +837,11 @@ mod tests { async fn test_btree_fst_small_order_random_insertions() { let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(8)); + let mut t = BTree::new(KeyProvider::Debug, State::new(8)); let mut samples: Vec = (0..100).collect(); let mut rng = thread_rng(); samples.shuffle(&mut rng); - insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await; + insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); let s = t.statistics::(&mut tx).await.unwrap(); @@ -846,12 +852,11 @@ mod tests { async fn test_btree_trie_small_order_random_insertions() { let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(75)); + let mut t = BTree::new(KeyProvider::Debug, State::new(75)); let mut samples: Vec = (0..100).collect(); let mut rng = thread_rng(); samples.shuffle(&mut rng); - insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])) - .await; + insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); let s = t.statistics::(&mut tx).await.unwrap(); @@ -862,8 +867,8 @@ mod tests { async fn test_btree_fst_keys_large_order_sequential_insertions() { let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(60)); - insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 10000, get_key_value).await; + let mut t = BTree::new(KeyProvider::Debug, State::new(60)); + insertions_test::<_, FstKeys>(&mut tx, &mut t, 10000, get_key_value).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); assert_eq!( @@ -881,8 +886,8 @@ mod tests { async fn test_btree_trie_keys_large_order_sequential_insertions() { let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(60)); - insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 10000, get_key_value).await; + let mut t = BTree::new(KeyProvider::Debug, State::new(60)); + insertions_test::<_, TrieKeys>(&mut tx, &mut t, 10000, get_key_value).await; tx.commit().await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap(); assert_eq!( @@ -908,8 +913,8 @@ mod tests { { let ds = Datastore::new("memory").await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(default_minimum_degree)); - insertions_test::<_, BK, _>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| { + let mut t = BTree::new(KeyProvider::Debug, State::new(default_minimum_degree)); + insertions_test::<_, BK>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| { (REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload) }) .await; @@ -1006,7 +1011,7 @@ mod tests { // This check node splitting. CLRS: Figure 18.7, page 498. async fn clrs_insertion_test() { let ds = Datastore::new("memory").await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(3)); + let mut t = BTree::new(KeyProvider::Debug, State::new(3)); let mut tx = ds.transaction(true, false).await.unwrap(); for (key, payload) in CLRS_EXAMPLE { t.insert::(&mut tx, key.into(), payload).await.unwrap(); @@ -1090,7 +1095,7 @@ mod tests { BK: BKeys + Serialize + DeserializeOwned + Default, { let ds = Datastore::new("memory").await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(3)); + let mut t = BTree::new(KeyProvider::Debug, State::new(3)); let mut tx = ds.transaction(true, false).await.unwrap(); for (key, payload) in CLRS_EXAMPLE { t.insert::(&mut tx, key.into(), payload).await.unwrap(); @@ -1180,7 +1185,7 @@ mod tests { BK: BKeys + Serialize + DeserializeOwned + Default, { let ds = Datastore::new("memory").await.unwrap(); - let mut t = BTree::new(TestKeyProvider {}, State::new(3)); + let mut t = BTree::new(KeyProvider::Debug, State::new(3)); let mut tx = ds.transaction(true, false).await.unwrap(); let mut expected_keys = HashMap::new(); @@ -1191,13 +1196,13 @@ mod tests { tx.commit().await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap(); - print_tree::(&mut tx, &t).await; + print_tree::(&mut tx, &t).await; for (key, _) in CLRS_EXAMPLE { debug!("------------------------"); debug!("Delete {}", key); t.delete::(&mut tx, key.into()).await.unwrap(); - print_tree::(&mut tx, &t).await; + print_tree::(&mut tx, &t).await; // Check that every expected keys are still found in the tree expected_keys.remove(key); @@ -1259,9 +1264,8 @@ mod tests { } } - async fn print_tree(tx: &mut Transaction, t: &BTree) + async fn print_tree(tx: &mut Transaction, t: &BTree) where - K: KeyProvider + Clone + Sync, BK: BKeys + Serialize + DeserializeOwned, { debug!("----------------------------------"); @@ -1289,10 +1293,7 @@ mod tests { } } - impl BTree - where - K: KeyProvider + Clone + Sync, - { + impl BTree { /// This is for debugging async fn inspect_nodes( &self, diff --git a/lib/src/idx/ft/docids.rs b/lib/src/idx/ft/docids.rs index 66cc8af6..134398bb 100644 --- a/lib/src/idx/ft/docids.rs +++ b/lib/src/idx/ft/docids.rs @@ -1,6 +1,6 @@ use crate::err::Error; use crate::idx::bkeys::TrieKeys; -use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics}; +use crate::idx::btree::{BTree, KeyProvider, Statistics}; use crate::idx::{btree, IndexKeyBase, SerdeState}; use crate::kvs::{Key, Transaction}; use roaring::RoaringTreemap; @@ -13,7 +13,7 @@ pub(crate) const NO_DOC_ID: u64 = u64::MAX; pub(crate) struct DocIds { state_key: Key, index_key_base: IndexKeyBase, - btree: BTree, + btree: BTree, available_ids: Option, next_doc_id: DocId, updated: bool, @@ -25,9 +25,7 @@ impl DocIds { index_key_base: IndexKeyBase, default_btree_order: u32, ) -> Result { - let keys = DocIdsKeyProvider { - index_key_base: index_key_base.clone(), - }; + let keys = KeyProvider::DocIds(index_key_base.clone()); let state_key: Key = keys.get_state_key(); let state: State = if let Some(val) = tx.get(state_key.clone()).await? { State::try_from_val(val)? @@ -179,20 +177,6 @@ impl Resolved { } } -#[derive(Clone)] -struct DocIdsKeyProvider { - index_key_base: IndexKeyBase, -} - -impl KeyProvider for DocIdsKeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key { - self.index_key_base.new_bd_key(Some(node_id)) - } - fn get_state_key(&self) -> Key { - self.index_key_base.new_bd_key(None) - } -} - #[cfg(test)] mod tests { use crate::idx::ft::docids::{DocIds, Resolved}; diff --git a/lib/src/idx/ft/doclength.rs b/lib/src/idx/ft/doclength.rs index 0d7a412e..ef3d3106 100644 --- a/lib/src/idx/ft/doclength.rs +++ b/lib/src/idx/ft/doclength.rs @@ -1,6 +1,6 @@ use crate::err::Error; use crate::idx::bkeys::TrieKeys; -use crate::idx::btree::{BTree, KeyProvider, NodeId, Payload, Statistics}; +use crate::idx::btree::{BTree, KeyProvider, Payload, Statistics}; use crate::idx::ft::docids::DocId; use crate::idx::{btree, IndexKeyBase, SerdeState}; use crate::kvs::{Key, Transaction}; @@ -9,7 +9,7 @@ pub(super) type DocLength = u64; pub(super) struct DocLengths { state_key: Key, - btree: BTree, + btree: BTree, } impl DocLengths { @@ -18,9 +18,7 @@ impl DocLengths { index_key_base: IndexKeyBase, default_btree_order: u32, ) -> Result { - let keys = DocLengthsKeyProvider { - index_key_base, - }; + let keys = KeyProvider::DocLengths(index_key_base); let state_key: Key = keys.get_state_key(); let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? { btree::State::try_from_val(val)? @@ -70,21 +68,6 @@ impl DocLengths { } } -#[derive(Clone)] -struct DocLengthsKeyProvider { - index_key_base: IndexKeyBase, -} - -impl KeyProvider for DocLengthsKeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key { - self.index_key_base.new_bl_key(Some(node_id)) - } - - fn get_state_key(&self) -> Key { - self.index_key_base.new_bl_key(None) - } -} - #[cfg(test)] mod tests { use crate::idx::ft::doclength::DocLengths; diff --git a/lib/src/idx/ft/postings.rs b/lib/src/idx/ft/postings.rs index 17470eb0..dd24887c 100644 --- a/lib/src/idx/ft/postings.rs +++ b/lib/src/idx/ft/postings.rs @@ -1,6 +1,6 @@ use crate::err::Error; use crate::idx::bkeys::TrieKeys; -use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics}; +use crate::idx::btree::{BTree, KeyProvider, Statistics}; use crate::idx::ft::docids::DocId; use crate::idx::ft::terms::TermId; use crate::idx::{btree, IndexKeyBase, SerdeState}; @@ -11,7 +11,7 @@ pub(super) type TermFrequency = u64; pub(super) struct Postings { state_key: Key, index_key_base: IndexKeyBase, - btree: BTree, + btree: BTree, } impl Postings { @@ -20,9 +20,7 @@ impl Postings { index_key_base: IndexKeyBase, order: u32, ) -> Result { - let keys = PostingsKeyProvider { - index_key_base: index_key_base.clone(), - }; + let keys = KeyProvider::Postings(index_key_base.clone()); let state_key: Key = keys.get_state_key(); let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? { btree::State::try_from_val(val)? @@ -79,20 +77,6 @@ impl Postings { } } -#[derive(Clone)] -pub(super) struct PostingsKeyProvider { - index_key_base: IndexKeyBase, -} - -impl KeyProvider for PostingsKeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key { - self.index_key_base.new_bp_key(Some(node_id)) - } - fn get_state_key(&self) -> Key { - self.index_key_base.new_bp_key(None) - } -} - #[cfg(test)] mod tests { use crate::idx::ft::postings::Postings; diff --git a/lib/src/idx/ft/terms.rs b/lib/src/idx/ft/terms.rs index 5cac716f..0c27a49e 100644 --- a/lib/src/idx/ft/terms.rs +++ b/lib/src/idx/ft/terms.rs @@ -1,6 +1,6 @@ use crate::err::Error; use crate::idx::bkeys::FstKeys; -use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics}; +use crate::idx::btree::{BTree, KeyProvider, Statistics}; use crate::idx::{btree, IndexKeyBase, SerdeState}; use crate::kvs::{Key, Transaction}; use roaring::RoaringTreemap; @@ -11,7 +11,7 @@ pub(crate) type TermId = u64; pub(super) struct Terms { state_key: Key, index_key_base: IndexKeyBase, - btree: BTree, + btree: BTree, available_ids: Option, next_term_id: TermId, updated: bool, @@ -23,9 +23,7 @@ impl Terms { index_key_base: IndexKeyBase, default_btree_order: u32, ) -> Result { - let keys = TermsKeyProvider { - index_key_base: index_key_base.clone(), - }; + let keys = KeyProvider::Terms(index_key_base.clone()); let state_key: Key = keys.get_state_key(); let state: State = if let Some(val) = tx.get(state_key.clone()).await? { State::try_from_val(val)? @@ -143,20 +141,6 @@ impl State { } } -#[derive(Clone)] -struct TermsKeyProvider { - index_key_base: IndexKeyBase, -} - -impl KeyProvider for TermsKeyProvider { - fn get_node_key(&self, node_id: NodeId) -> Key { - self.index_key_base.new_bt_key(Some(node_id)) - } - fn get_state_key(&self) -> Key { - self.index_key_base.new_bt_key(None) - } -} - #[cfg(test)] mod tests { use crate::idx::ft::postings::TermFrequency; diff --git a/lib/src/idx/planner/executor.rs b/lib/src/idx/planner/executor.rs index f2ccd164..70d05595 100644 --- a/lib/src/idx/planner/executor.rs +++ b/lib/src/idx/planner/executor.rs @@ -177,7 +177,7 @@ impl QueryExecutor { pub(crate) async fn highlight( &self, - txn: Transaction, + txn: &Transaction, thg: &Thing, prefix: Value, suffix: Value, @@ -195,7 +195,7 @@ impl QueryExecutor { pub(crate) async fn offsets( &self, - txn: Transaction, + txn: &Transaction, thg: &Thing, match_ref: &Value, ) -> Result { @@ -208,7 +208,7 @@ impl QueryExecutor { pub(crate) async fn score( &self, - txn: Transaction, + txn: &Transaction, match_ref: &Value, rid: &Thing, mut doc_id: Option, diff --git a/lib/src/idx/planner/mod.rs b/lib/src/idx/planner/mod.rs index e0d9b21d..d0553e73 100644 --- a/lib/src/idx/planner/mod.rs +++ b/lib/src/idx/planner/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod plan; mod tree; use crate::ctx::Context; -use crate::dbs::{Iterable, Options}; +use crate::dbs::{Iterable, Options, Transaction}; use crate::err::Error; use crate::idx::planner::executor::QueryExecutor; use crate::idx::planner::plan::{Plan, PlanBuilder}; @@ -30,17 +30,17 @@ impl<'a> QueryPlanner<'a> { pub(crate) async fn get_iterable( &mut self, ctx: &Context<'_>, + txn: &Transaction, t: Table, ) -> Result { - let txn = ctx.try_clone_transaction()?; - let res = Tree::build(ctx, self.opt, &txn, &t, self.cond).await?; + let res = Tree::build(ctx, self.opt, txn, &t, self.cond).await?; if let Some((node, im)) = res { if let Some(plan) = AllAndStrategy::build(&node)? { - let e = QueryExecutor::new(self.opt, &txn, &t, im, Some(plan.e.clone())).await?; + let e = QueryExecutor::new(self.opt, txn, &t, im, Some(plan.e.clone())).await?; self.executors.insert(t.0.clone(), e); return Ok(Iterable::Index(t, plan)); } - let e = QueryExecutor::new(self.opt, &txn, &t, im, None).await?; + let e = QueryExecutor::new(self.opt, txn, &t, im, None).await?; self.executors.insert(t.0.clone(), e); } Ok(Iterable::Table(t)) diff --git a/lib/src/idx/planner/plan.rs b/lib/src/idx/planner/plan.rs index 990cf476..f2f3cc96 100644 --- a/lib/src/idx/planner/plan.rs +++ b/lib/src/idx/planner/plan.rs @@ -11,7 +11,6 @@ use crate::sql::index::Index; use crate::sql::scoring::Scoring; use crate::sql::statements::DefineIndexStatement; use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value}; -use async_trait::async_trait; use std::collections::HashMap; use std::hash::Hash; use std::sync::Arc; @@ -54,7 +53,7 @@ impl Plan { opt: &Options, txn: &Transaction, exe: &QueryExecutor, - ) -> Result, Error> { + ) -> Result { self.i.new_iterator(opt, txn, exe).await } @@ -128,11 +127,11 @@ impl IndexOption { opt: &Options, txn: &Transaction, exe: &QueryExecutor, - ) -> Result, Error> { + ) -> Result { match &self.ix().index { Index::Idx => { if self.op() == &Operator::Equal { - return Ok(Box::new(NonUniqueEqualThingIterator::new( + return Ok(ThingIterator::NonUniqueEqual(NonUniqueEqualThingIterator::new( opt, self.ix(), self.value(), @@ -141,7 +140,7 @@ impl IndexOption { } Index::Uniq => { if self.op() == &Operator::Equal { - return Ok(Box::new(UniqueEqualThingIterator::new( + return Ok(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new( opt, self.ix(), self.value(), @@ -156,7 +155,7 @@ impl IndexOption { } => { if let Operator::Matches(_) = self.op() { let td = exe.pre_match_terms_docs(); - return Ok(Box::new( + return Ok(ThingIterator::Matches( MatchesThingIterator::new(opt, txn, self.ix(), az, *hl, sc, *order, td) .await?, )); @@ -167,23 +166,37 @@ impl IndexOption { } } -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -pub(crate) trait ThingIterator: Send { - async fn next_batch( +pub(crate) enum ThingIterator { + NonUniqueEqual(NonUniqueEqualThingIterator), + UniqueEqual(UniqueEqualThingIterator), + Matches(MatchesThingIterator), +} + +impl ThingIterator { + pub(crate) async fn next_batch( &mut self, tx: &Transaction, size: u32, - ) -> Result, Error>; + ) -> Result, Error> { + match self { + ThingIterator::NonUniqueEqual(i) => i.next_batch(tx, size).await, + ThingIterator::UniqueEqual(i) => i.next_batch(tx, size).await, + ThingIterator::Matches(i) => i.next_batch(tx, size).await, + } + } } -struct NonUniqueEqualThingIterator { +pub(crate) struct NonUniqueEqualThingIterator { beg: Vec, end: Vec, } impl NonUniqueEqualThingIterator { - fn new(opt: &Options, ix: &DefineIndexStatement, v: &Value) -> Result { + fn new( + opt: &Options, + ix: &DefineIndexStatement, + v: &Value, + ) -> Result { let v = Array::from(v.clone()); let beg = key::index::prefix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v); let end = key::index::suffix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v); @@ -192,11 +205,7 @@ impl NonUniqueEqualThingIterator { end, }) } -} -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl ThingIterator for NonUniqueEqualThingIterator { async fn next_batch( &mut self, txn: &Transaction, @@ -214,7 +223,7 @@ impl ThingIterator for NonUniqueEqualThingIterator { } } -struct UniqueEqualThingIterator { +pub(crate) struct UniqueEqualThingIterator { key: Option, } @@ -226,11 +235,7 @@ impl UniqueEqualThingIterator { key: Some(key), }) } -} -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl ThingIterator for UniqueEqualThingIterator { async fn next_batch( &mut self, txn: &Transaction, @@ -245,7 +250,7 @@ impl ThingIterator for UniqueEqualThingIterator { } } -struct MatchesThingIterator { +pub(crate) struct MatchesThingIterator { hits: Option, } @@ -285,11 +290,7 @@ impl MatchesThingIterator { }) } } -} -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -impl ThingIterator for MatchesThingIterator { async fn next_batch( &mut self, txn: &Transaction, diff --git a/lib/src/idx/planner/tree.rs b/lib/src/idx/planner/tree.rs index 51846b33..9e683fd9 100644 --- a/lib/src/idx/planner/tree.rs +++ b/lib/src/idx/planner/tree.rs @@ -79,7 +79,7 @@ impl<'a> TreeBuilder<'a> { Value::Bool(_) => Node::Scalar(v.to_owned()), Value::Subquery(s) => self.eval_subquery(s).await?, Value::Param(p) => { - let v = p.compute(self.ctx, self.opt).await?; + let v = p.compute(self.ctx, self.opt, self.txn, None).await?; self.eval_value(&v).await? } _ => Node::Unsupported, diff --git a/lib/src/kvs/ds.rs b/lib/src/kvs/ds.rs index 4f1368f7..4bb714ea 100644 --- a/lib/src/kvs/ds.rs +++ b/lib/src/kvs/ds.rs @@ -447,8 +447,6 @@ impl Datastore { let txn = Arc::new(Mutex::new(txn)); // Create a default context let mut ctx = Context::default(); - // Add the transaction - ctx.add_transaction(Some(&txn)); // Set the global query timeout if let Some(timeout) = self.query_timeout { ctx.add_timeout(timeout); @@ -462,7 +460,7 @@ impl Datastore { // Store the query variables let ctx = vars.attach(ctx)?; // Compute the value - let res = val.compute(&ctx, &opt).await?; + let res = val.compute(&ctx, &opt, &txn, None).await?; // Store any data match val.writeable() { true => txn.lock().await.commit().await?, diff --git a/lib/src/sql/array.rs b/lib/src/sql/array.rs index 9b43b8c6..2b83b103 100644 --- a/lib/src/sql/array.rs +++ b/lib/src/sql/array.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::common::{closebracket, commas, openbracket}; @@ -117,10 +118,16 @@ impl Array { impl Array { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { let mut x = Self::with_capacity(self.len()); for v in self.iter() { - match v.compute(ctx, opt).await { + match v.compute(ctx, opt, txn, doc).await { Ok(v) => x.push(v), Err(e) => return Err(e), }; diff --git a/lib/src/sql/block.rs b/lib/src/sql/block.rs index 96b22edf..88b52268 100644 --- a/lib/src/sql/block.rs +++ b/lib/src/sql/block.rs @@ -1,6 +1,7 @@ use crate::cnf::PROTECTED_PARAM_NAMES; use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::{comment, mightbespace}; use crate::sql::common::{closebraces, colons, openbraces}; @@ -51,7 +52,13 @@ impl Block { self.iter().any(Entry::writeable) } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Duplicate context let mut ctx = Context::new(ctx); // Loop over the statements @@ -61,7 +68,7 @@ impl Block { // Check if the variable is a protected variable let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) { // The variable isn't protected and can be stored - false => v.compute(&ctx, opt).await, + false => v.compute(&ctx, opt, txn, doc).await, // The user tried to set a protected variable true => { return Err(Error::InvalidParam { @@ -73,31 +80,31 @@ impl Block { ctx.add_value(v.name.to_owned(), val); } Entry::Ifelse(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Select(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Create(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Update(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Delete(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Relate(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Insert(v) => { - v.compute(&ctx, opt).await?; + v.compute(&ctx, opt, txn, doc).await?; } Entry::Output(v) => { - return v.compute(&ctx, opt).await; + return v.compute(&ctx, opt, txn, doc).await; } Entry::Value(v) => { - return v.compute(&ctx, opt).await; + return v.compute(&ctx, opt, txn, doc).await; } } } diff --git a/lib/src/sql/cast.rs b/lib/src/sql/cast.rs index f19931a4..e79dd02c 100644 --- a/lib/src/sql/cast.rs +++ b/lib/src/sql/cast.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::error::IResult; @@ -36,11 +37,17 @@ impl Cast { impl Cast { #[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&'async_recursion CursorDoc<'_>>, + ) -> Result { // Prevent long cast chains let opt = &opt.dive(1)?; // Compute the value to be cast and convert it - self.1.compute(ctx, opt).await?.convert_to(&self.0) + self.1.compute(ctx, opt, txn, doc).await?.convert_to(&self.0) } } diff --git a/lib/src/sql/constant.rs b/lib/src/sql/constant.rs index 92e8e053..c4d8f1ab 100644 --- a/lib/src/sql/constant.rs +++ b/lib/src/sql/constant.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::error::IResult; use crate::sql::value::Value; @@ -78,7 +79,13 @@ impl Constant { } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + _opt: &Options, + _txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { Ok(match self.value() { ConstantValue::Datetime(d) => d.into(), ConstantValue::Float(f) => f.into(), diff --git a/lib/src/sql/data.rs b/lib/src/sql/data.rs index 65b1c219..5f4160d9 100644 --- a/lib/src/sql/data.rs +++ b/lib/src/sql/data.rs @@ -1,5 +1,5 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::comment::shouldbespace; @@ -43,25 +43,26 @@ impl Data { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, tb: &Table, ) -> Result { match self { Self::MergeExpression(v) => { // This MERGE expression has an 'id' field - v.compute(ctx, opt).await?.rid().generate(tb, false) + v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false) } Self::ReplaceExpression(v) => { // This REPLACE expression has an 'id' field - v.compute(ctx, opt).await?.rid().generate(tb, false) + v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false) } Self::ContentExpression(v) => { // This CONTENT expression has an 'id' field - v.compute(ctx, opt).await?.rid().generate(tb, false) + v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false) } Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) { Some((_, _, v)) => { // This SET expression has an 'id' field - v.compute(ctx, opt).await?.generate(tb, false) + v.compute(ctx, opt, txn, None).await?.generate(tb, false) } // This SET expression had no 'id' field _ => Ok(tb.generate()), diff --git a/lib/src/sql/expression.rs b/lib/src/sql/expression.rs index 701280ec..302bbac4 100644 --- a/lib/src/sql/expression.rs +++ b/lib/src/sql/expression.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::fnc; use crate::sql::comment::mightbespace; @@ -101,13 +102,19 @@ impl Expression { } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { let (l, o, r) = match self { Self::Unary { o, v, } => { - let operand = v.compute(ctx, opt).await?; + let operand = v.compute(ctx, opt, txn, doc).await?; return match o { Operator::Neg => fnc::operate::neg(operand), Operator::Not => fnc::operate::not(operand), @@ -121,7 +128,7 @@ impl Expression { } => (l, o, r), }; - let l = l.compute(ctx, opt).await?; + let l = l.compute(ctx, opt, txn, doc).await?; match o { Operator::Or => { if let true = l.is_truthy() { @@ -145,7 +152,7 @@ impl Expression { } _ => {} // Continue } - let r = r.compute(ctx, opt).await?; + let r = r.compute(ctx, opt, txn, doc).await?; match o { Operator::Or => fnc::operate::or(l, r), Operator::And => fnc::operate::and(l, r), @@ -181,7 +188,7 @@ impl Expression { Operator::NoneInside => fnc::operate::inside_none(&l, &r), Operator::Outside => fnc::operate::outside(&l, &r), Operator::Intersects => fnc::operate::intersects(&l, &r), - Operator::Matches(_) => fnc::operate::matches(ctx, self).await, + Operator::Matches(_) => fnc::operate::matches(ctx, txn, doc, self).await, _ => unreachable!(), } } diff --git a/lib/src/sql/field.rs b/lib/src/sql/field.rs index 920d17cf..5fd1e852 100644 --- a/lib/src/sql/field.rs +++ b/lib/src/sql/field.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::common::commas; @@ -75,17 +76,31 @@ impl Fields { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, group: bool, ) -> Result { // Ensure futures are run + if let Some(doc) = doc { + self.compute_value(ctx, opt, txn, doc, group).await + } else { + let doc = CursorDoc::new(None, None, &Value::None); + self.compute_value(ctx, opt, txn, &doc, group).await + } + } + + async fn compute_value( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: &CursorDoc<'_>, + group: bool, + ) -> Result { let opt = &opt.new_with_futures(true); - // - let doc = ctx.doc().unwrap_or(&Value::None); - let mut ctx = Context::new(ctx); - ctx.add_cursor_doc(doc); // Process the desired output let mut out = match self.is_all() { - true => doc.compute(&ctx, opt).await?, + true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?, false => Value::base(), }; for v in self.other() { @@ -104,13 +119,13 @@ impl Fields { Value::Function(f) if group && f.is_aggregate() => { let x = match f.args().len() { // If no function arguments, then compute the result - 0 => f.compute(&ctx, opt).await?, + 0 => f.compute(ctx, opt, txn, Some(doc)).await?, // If arguments, then pass the first value through - _ => f.args()[0].compute(&ctx, opt).await?, + _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, }; // Check if this is a single VALUE field expression match self.single().is_some() { - false => out.set(&ctx, opt, idiom.as_ref(), x).await?, + false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?, true => out = x, } } @@ -123,11 +138,15 @@ impl Fields { // Use the last fetched value for each fetch let x = match res.last() { Some((_, r)) => r, - None => doc, + None => doc.doc.as_ref(), }; // Continue fetching the next idiom part - let x = - x.get(&ctx, opt, v).await?.compute(&ctx, opt).await?.flatten(); + let x = x + .get(ctx, opt, txn, Some(doc), v) + .await? + .compute(ctx, opt, txn, Some(doc)) + .await? + .flatten(); // Add the result to the temporary store res.push((v, x)); } @@ -137,23 +156,24 @@ impl Fields { // This is an alias expression part Some(a) => { if let Some(i) = alias { - out.set(&ctx, opt, i, x.clone()).await?; + out.set(ctx, opt, txn, i, x.clone()).await?; } - out.set(&ctx, opt, a, x).await?; + out.set(ctx, opt, txn, a, x).await?; } // This is the end of the expression None => { - out.set(&ctx, opt, alias.as_ref().unwrap_or(v), x).await? + out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x) + .await? } } } } // This expression is a normal field expression _ => { - let x = expr.compute(&ctx, opt).await?; + let x = expr.compute(ctx, opt, txn, Some(doc)).await?; // Check if this is a single VALUE field expression match self.single().is_some() { - false => out.set(&ctx, opt, idiom.as_ref(), x).await?, + false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?, true => out = x, } } diff --git a/lib/src/sql/function.rs b/lib/src/sql/function.rs index b663b815..3fdccf1d 100644 --- a/lib/src/sql/function.rs +++ b/lib/src/sql/function.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::fnc; use crate::sql::comment::mightbespace; @@ -131,7 +132,13 @@ 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(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&'async_recursion CursorDoc<'_>>, + ) -> Result { // Prevent long function chains let opt = &opt.dive(1)?; // Ensure futures are run @@ -140,15 +147,13 @@ impl Function { match self { Self::Normal(s, x) => { // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?; + let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; // Run the normal function - fnc::run(ctx, s, a).await + fnc::run(ctx, txn, doc, s, a).await } Self::Custom(s, x) => { // Get the function definition let val = { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Get the function definition @@ -165,7 +170,7 @@ impl Function { }); } // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?; + let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; // Duplicate context let mut ctx = Context::new(ctx); // Process the function arguments @@ -173,16 +178,16 @@ impl Function { ctx.add_value(name.to_raw(), val.coerce_to(&kind)?); } // Run the custom function - val.block.compute(&ctx, opt).await + val.block.compute(&ctx, opt, txn, doc).await } #[allow(unused_variables)] Self::Script(s, x) => { #[cfg(feature = "scripting")] { // Compute the function arguments - let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?; + let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?; // Run the script function - fnc::script::run(ctx, opt, s, a).await + fnc::script::run(ctx, opt, txn, doc, s, a).await } #[cfg(not(feature = "scripting"))] { diff --git a/lib/src/sql/future.rs b/lib/src/sql/future.rs index 66ea0985..b02a7ccc 100644 --- a/lib/src/sql/future.rs +++ b/lib/src/sql/future.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::block::{block, Block}; use crate::sql::comment::mightbespace; @@ -24,12 +25,18 @@ impl From for Future { impl Future { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Prevent long future chains let opt = &opt.dive(1)?; // Process the future if enabled match opt.futures { - true => self.0.compute(ctx, opt).await?.ok(), + true => self.0.compute(ctx, opt, txn, doc).await?.ok(), false => Ok(self.clone().into()), } } diff --git a/lib/src/sql/id.rs b/lib/src/sql/id.rs index 73f96eaa..a048536b 100644 --- a/lib/src/sql/id.rs +++ b/lib/src/sql/id.rs @@ -1,6 +1,7 @@ use crate::cnf::ID_CHARS; use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::array::{array, Array}; use crate::sql::error::IResult; @@ -166,15 +167,21 @@ impl Display for Id { impl Id { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { match self { Id::Number(v) => Ok(Id::Number(*v)), Id::String(v) => Ok(Id::String(v.clone())), - Id::Object(v) => match v.compute(ctx, opt).await? { + Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? { Value::Object(v) => Ok(Id::Object(v)), _ => unreachable!(), }, - Id::Array(v) => match v.compute(ctx, opt).await? { + Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? { Value::Array(v) => Ok(Id::Array(v)), _ => unreachable!(), }, diff --git a/lib/src/sql/idiom.rs b/lib/src/sql/idiom.rs index 2b29fdaa..d20e9e85 100644 --- a/lib/src/sql/idiom.rs +++ b/lib/src/sql/idiom.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::common::commas; use crate::sql::error::IResult; @@ -127,21 +128,29 @@ impl Idiom { self.0.iter().any(|v| v.writeable()) } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { match self.first() { // The starting part is a value Some(Part::Value(v)) => { - v.compute(ctx, opt) + v.compute(ctx, opt, txn, doc) .await? - .get(ctx, opt, self.as_ref().next()) + .get(ctx, opt, txn, doc, self.as_ref().next()) .await? - .compute(ctx, opt) + .compute(ctx, opt, txn, doc) .await } // Otherwise use the current document - _ => match ctx.doc() { + _ => match doc { // There is a current document - Some(v) => v.get(ctx, opt, self).await?.compute(ctx, opt).await, + Some(v) => { + v.doc.get(ctx, opt, txn, doc, self).await?.compute(ctx, opt, txn, doc).await + } // There isn't any document None => Ok(Value::None), }, diff --git a/lib/src/sql/limit.rs b/lib/src/sql/limit.rs index 637e0454..381ca44f 100644 --- a/lib/src/sql/limit.rs +++ b/lib/src/sql/limit.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -15,8 +16,14 @@ use std::fmt; pub struct Limit(pub Value); impl Limit { - pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result { - match self.0.compute(ctx, opt).await { + pub(crate) async fn process( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { + match self.0.compute(ctx, opt, txn, doc).await { // This is a valid limiting number Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), // An invalid value was specified diff --git a/lib/src/sql/object.rs b/lib/src/sql/object.rs index 88c7564d..f27bb35d 100644 --- a/lib/src/sql/object.rs +++ b/lib/src/sql/object.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::common::{commas, val_char}; @@ -124,10 +125,16 @@ impl Object { impl Object { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { let mut x = BTreeMap::new(); for (k, v) in self.iter() { - match v.compute(ctx, opt).await { + match v.compute(ctx, opt, txn, doc).await { Ok(v) => x.insert(k.clone(), v), Err(e) => return Err(e), }; diff --git a/lib/src/sql/param.rs b/lib/src/sql/param.rs index cba95317..b8dd653b 100644 --- a/lib/src/sql/param.rs +++ b/lib/src/sql/param.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::error::IResult; use crate::sql::ident::{ident, Ident}; @@ -43,24 +44,28 @@ impl Deref for Param { impl Param { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Find the variable by name match self.as_str() { // This is a special param - "this" | "self" => match ctx.doc() { + "this" | "self" => match doc { // The base document exists - Some(v) => v.compute(ctx, opt).await, + Some(v) => v.doc.compute(ctx, opt, txn, doc).await, // The base document does not exist None => Ok(Value::None), }, // This is a normal param v => match ctx.value(v) { // The param has been set locally - Some(v) => v.compute(ctx, opt).await, + Some(v) => v.compute(ctx, opt, txn, doc).await, // The param has not been set locally None => { - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Get the param definition diff --git a/lib/src/sql/range.rs b/lib/src/sql/range.rs index 0bb2b622..bd93abd2 100644 --- a/lib/src/sql/range.rs +++ b/lib/src/sql/range.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::error::IResult; use crate::sql::id::{id, Id}; @@ -48,17 +49,23 @@ impl TryFrom<&str> for Range { impl Range { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { Ok(Value::Range(Box::new(Range { tb: self.tb.clone(), beg: match &self.beg { - Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?), - Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?), + Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?), + Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?), Bound::Unbounded => Bound::Unbounded, }, end: match &self.end { - Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?), - Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?), + Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?), + Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?), Bound::Unbounded => Bound::Unbounded, }, }))) diff --git a/lib/src/sql/start.rs b/lib/src/sql/start.rs index aa2a0c1f..df08b938 100644 --- a/lib/src/sql/start.rs +++ b/lib/src/sql/start.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -15,8 +16,14 @@ use std::fmt; pub struct Start(pub Value); impl Start { - pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result { - match self.0.compute(ctx, opt).await { + pub(crate) async fn process( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { + match self.0.compute(ctx, opt, txn, doc).await { // This is a valid starting number Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), // An invalid value was specified diff --git a/lib/src/sql/statement.rs b/lib/src/sql/statement.rs index 176fd379..f763d3f8 100644 --- a/lib/src/sql/statement.rs +++ b/lib/src/sql/statement.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::{comment, mightbespace}; use crate::sql::common::colons; @@ -138,25 +139,31 @@ impl Statement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { match self { - Self::Analyze(v) => v.compute(ctx, opt).await, - Self::Create(v) => v.compute(ctx, opt).await, - Self::Delete(v) => v.compute(ctx, opt).await, - Self::Define(v) => v.compute(ctx, opt).await, - Self::Ifelse(v) => v.compute(ctx, opt).await, - Self::Info(v) => v.compute(ctx, opt).await, - Self::Insert(v) => v.compute(ctx, opt).await, - Self::Kill(v) => v.compute(ctx, opt).await, - Self::Live(v) => v.compute(ctx, opt).await, - Self::Output(v) => v.compute(ctx, opt).await, - Self::Relate(v) => v.compute(ctx, opt).await, - Self::Remove(v) => v.compute(ctx, opt).await, - Self::Select(v) => v.compute(ctx, opt).await, - Self::Set(v) => v.compute(ctx, opt).await, - Self::Show(v) => v.compute(ctx, opt).await, - Self::Sleep(v) => v.compute(ctx, opt).await, - Self::Update(v) => v.compute(ctx, opt).await, + Self::Analyze(v) => v.compute(ctx, opt, txn, doc).await, + Self::Create(v) => v.compute(ctx, opt, txn, doc).await, + Self::Delete(v) => v.compute(ctx, opt, txn, doc).await, + Self::Define(v) => v.compute(ctx, opt, txn, doc).await, + Self::Ifelse(v) => v.compute(ctx, opt, txn, doc).await, + Self::Info(v) => v.compute(ctx, opt, txn, doc).await, + Self::Insert(v) => v.compute(ctx, opt, txn, doc).await, + Self::Kill(v) => v.compute(ctx, opt, txn, doc).await, + Self::Live(v) => v.compute(ctx, opt, txn, doc).await, + Self::Output(v) => v.compute(ctx, opt, txn, doc).await, + Self::Relate(v) => v.compute(ctx, opt, txn, doc).await, + Self::Remove(v) => v.compute(ctx, opt, txn, doc).await, + Self::Select(v) => v.compute(ctx, opt, txn, doc).await, + Self::Set(v) => v.compute(ctx, opt, txn, doc).await, + Self::Show(v) => v.compute(ctx, opt, doc).await, + Self::Sleep(v) => v.compute(ctx, opt, doc).await, + Self::Update(v) => v.compute(ctx, opt, txn, doc).await, _ => unreachable!(), } } diff --git a/lib/src/sql/statements/analyze.rs b/lib/src/sql/statements/analyze.rs index 3abf36ef..125abcbb 100644 --- a/lib/src/sql/statements/analyze.rs +++ b/lib/src/sql/statements/analyze.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::idx::ft::FtIndex; use crate::idx::IndexKeyBase; @@ -22,15 +23,19 @@ pub enum AnalyzeStatement { impl AnalyzeStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { match self { AnalyzeStatement::Idx(tb, idx) => { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Read the index diff --git a/lib/src/sql/statements/create.rs b/lib/src/sql/statements/create.rs index 5fe731e9..7c90f486 100644 --- a/lib/src/sql/statements/create.rs +++ b/lib/src/sql/statements/create.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::data::{data, Data}; @@ -42,7 +43,13 @@ impl CreateStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -53,11 +60,11 @@ impl CreateStatement { let opt = &opt.new_with_futures(false); // Loop over the create targets for w in self.what.0.iter() { - let v = w.compute(ctx, opt).await?; + let v = w.compute(ctx, opt, txn, doc).await?; match v { Value::Table(v) => match &self.data { // There is a data clause so check for a record id - Some(data) => match data.rid(ctx, opt, &v).await { + Some(data) => match data.rid(ctx, opt, txn, &v).await { // There was a problem creating the record id Err(e) => return Err(e), // There is an id field so use the record id @@ -116,7 +123,7 @@ impl CreateStatement { // Assign the statement let stm = Statement::from(self); // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } diff --git a/lib/src/sql/statements/define.rs b/lib/src/sql/statements/define.rs index 887a3a90..29a7f087 100644 --- a/lib/src/sql/statements/define.rs +++ b/lib/src/sql/statements/define.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::algorithm::{algorithm, Algorithm}; use crate::sql::base::{base, base_or_scope, Base}; @@ -61,20 +62,26 @@ pub enum DefineStatement { impl DefineStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { match self { - Self::Namespace(ref v) => v.compute(ctx, opt).await, - Self::Database(ref v) => v.compute(ctx, opt).await, - Self::Function(ref v) => v.compute(ctx, opt).await, - Self::Login(ref v) => v.compute(ctx, opt).await, - Self::Token(ref v) => v.compute(ctx, opt).await, - Self::Scope(ref v) => v.compute(ctx, opt).await, - Self::Param(ref v) => v.compute(ctx, opt).await, - Self::Table(ref v) => v.compute(ctx, opt).await, - Self::Event(ref v) => v.compute(ctx, opt).await, - Self::Field(ref v) => v.compute(ctx, opt).await, - Self::Index(ref v) => v.compute(ctx, opt).await, - Self::Analyzer(ref v) => v.compute(ctx, opt).await, + Self::Namespace(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Login(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await, } } } @@ -126,15 +133,19 @@ pub struct DefineNamespaceStatement { impl DefineNamespaceStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // No need for NS/DB opt.needs(Level::Kv)?; // Allowed to run? opt.check(Level::Kv)?; // Process the statement let key = crate::key::ns::new(&self.name); - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; run.set(key, self).await?; @@ -175,13 +186,17 @@ pub struct DefineDatabaseStatement { impl DefineDatabaseStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected NS? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -252,13 +267,17 @@ pub struct DefineFunctionStatement { impl DefineFunctionStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -330,13 +349,17 @@ pub struct DefineAnalyzerStatement { } impl DefineAnalyzerStatement { - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -400,15 +423,19 @@ pub struct DefineLoginStatement { impl DefineLoginStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { match self.base { Base::Ns => { // Selected DB? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Kv)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -423,8 +450,6 @@ impl DefineLoginStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -518,15 +543,19 @@ pub struct DefineTokenStatement { impl DefineTokenStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { match &self.base { Base::Ns => { // Selected DB? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Kv)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -541,8 +570,6 @@ impl DefineTokenStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -558,8 +585,6 @@ impl DefineTokenStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -633,13 +658,17 @@ pub struct DefineScopeStatement { impl DefineScopeStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -747,13 +776,17 @@ pub struct DefineParamStatement { impl DefineParamStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -807,13 +840,17 @@ pub struct DefineTableStatement { } impl DefineTableStatement { - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -852,7 +889,7 @@ impl DefineTableStatement { what: Values(vec![Value::Table(v.clone())]), ..UpdateStatement::default() }; - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, doc).await?; } } // Ok all good @@ -1006,13 +1043,17 @@ pub struct DefineEventStatement { impl DefineEventStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -1086,13 +1127,17 @@ pub struct DefineFieldStatement { impl DefineFieldStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -1242,13 +1287,17 @@ pub struct DefineIndexStatement { impl DefineIndexStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -1279,7 +1328,7 @@ impl DefineIndexStatement { what: Values(vec![Value::Table(self.what.clone().into())]), ..UpdateStatement::default() }; - stm.compute(ctx, opt).await?; + stm.compute(ctx, opt, txn, doc).await?; // Ok all good Ok(Value::None) } diff --git a/lib/src/sql/statements/delete.rs b/lib/src/sql/statements/delete.rs index 055331e5..4007bae7 100644 --- a/lib/src/sql/statements/delete.rs +++ b/lib/src/sql/statements/delete.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::cond::{cond, Cond}; @@ -42,7 +43,13 @@ impl DeleteStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -53,7 +60,7 @@ impl DeleteStatement { let opt = &opt.new_with_futures(false); // Loop over the delete targets for w in self.what.0.iter() { - let v = w.compute(ctx, opt).await?; + let v = w.compute(ctx, opt, txn, doc).await?; match v { Value::Table(v) => i.ingest(Iterable::Table(v)), Value::Thing(v) => i.ingest(Iterable::Thing(v)), @@ -109,7 +116,7 @@ impl DeleteStatement { // Assign the statement let stm = Statement::from(self); // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } diff --git a/lib/src/sql/statements/ifelse.rs b/lib/src/sql/statements/ifelse.rs index 01ff62e4..a2d0854a 100644 --- a/lib/src/sql/statements/ifelse.rs +++ b/lib/src/sql/statements/ifelse.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -29,15 +30,21 @@ 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<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { for (ref cond, ref then) in &self.exprs { - let v = cond.compute(ctx, opt).await?; + let v = cond.compute(ctx, opt, txn, doc).await?; if v.is_truthy() { - return then.compute(ctx, opt).await; + return then.compute(ctx, opt, txn, doc).await; } } match self.close { - Some(ref v) => v.compute(ctx, opt).await, + Some(ref v) => v.compute(ctx, opt, txn, doc).await, None => Ok(Value::None), } } diff --git a/lib/src/sql/statements/info.rs b/lib/src/sql/statements/info.rs index 77f8c0a7..0aa92a3a 100644 --- a/lib/src/sql/statements/info.rs +++ b/lib/src/sql/statements/info.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -24,7 +25,13 @@ pub enum InfoStatement { impl InfoStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Allowed to run? match self { InfoStatement::Kv => { @@ -34,8 +41,6 @@ impl InfoStatement { opt.check(Level::Kv)?; // Create the result set let mut res = Object::default(); - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the statement @@ -52,8 +57,6 @@ impl InfoStatement { opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Create the result set @@ -84,8 +87,6 @@ impl InfoStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Create the result set @@ -140,8 +141,6 @@ impl InfoStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Create the result set @@ -160,8 +159,6 @@ impl InfoStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Create the result set diff --git a/lib/src/sql/statements/insert.rs b/lib/src/sql/statements/insert.rs index 40bb0c78..ba9bf0ed 100644 --- a/lib/src/sql/statements/insert.rs +++ b/lib/src/sql/statements/insert.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::data::{single, update, values, Data}; @@ -45,7 +46,13 @@ impl InsertStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -63,8 +70,8 @@ impl InsertStatement { let mut o = Value::base(); // Set each field from the expression for (k, v) in v.iter() { - let v = v.compute(ctx, opt).await?; - o.set(ctx, opt, k, v).await?; + let v = v.compute(ctx, opt, txn, None).await?; + o.set(ctx, opt, txn, k, v).await?; } // Specify the new table record id let id = o.rid().generate(&self.into, true)?; @@ -74,7 +81,7 @@ impl InsertStatement { } // Check if this is a modern statement Data::SingleExpression(v) => { - let v = v.compute(ctx, opt).await?; + let v = v.compute(ctx, opt, txn, doc).await?; match v { Value::Array(v) => { for v in v { @@ -102,7 +109,7 @@ impl InsertStatement { // Assign the statement let stm = Statement::from(self); // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } diff --git a/lib/src/sql/statements/kill.rs b/lib/src/sql/statements/kill.rs index 1cc57028..3e36e3c2 100644 --- a/lib/src/sql/statements/kill.rs +++ b/lib/src/sql/statements/kill.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -18,15 +19,19 @@ pub struct KillStatement { impl KillStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // Allowed to run? opt.realtime()?; // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::No)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Fetch the live query key diff --git a/lib/src/sql/statements/live.rs b/lib/src/sql/statements/live.rs index 4b1407f5..ce21a8ac 100644 --- a/lib/src/sql/statements/live.rs +++ b/lib/src/sql/statements/live.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::cond::{cond, Cond}; @@ -32,19 +33,23 @@ pub struct LiveStatement { impl LiveStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Allowed to run? opt.realtime()?; // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::No)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Process the live query table - match self.what.compute(ctx, opt).await? { + match self.what.compute(ctx, opt, txn, doc).await? { Value::Table(tb) => { // Clone the current statement let mut stm = self.clone(); diff --git a/lib/src/sql/statements/output.rs b/lib/src/sql/statements/output.rs index 11e9b065..0a9f8801 100644 --- a/lib/src/sql/statements/output.rs +++ b/lib/src/sql/statements/output.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; @@ -24,15 +25,21 @@ impl OutputStatement { self.what.writeable() } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Ensure futures are processed let opt = &opt.new_with_futures(true); // Process the output value - let mut val = self.what.compute(ctx, opt).await?; + let mut val = self.what.compute(ctx, opt, txn, doc).await?; // Fetch any if let Some(fetchs) = &self.fetch { for fetch in fetchs.iter() { - val.fetch(ctx, opt, fetch).await?; + val.fetch(ctx, opt, txn, fetch).await?; } } // diff --git a/lib/src/sql/statements/relate.rs b/lib/src/sql/statements/relate.rs index f315eac7..c37c477c 100644 --- a/lib/src/sql/statements/relate.rs +++ b/lib/src/sql/statements/relate.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::array::array; use crate::sql::comment::mightbespace; @@ -55,7 +56,13 @@ impl RelateStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -67,7 +74,7 @@ impl RelateStatement { // Loop over the from targets let from = { let mut out = Vec::new(); - match self.from.compute(ctx, opt).await? { + match self.from.compute(ctx, opt, txn, doc).await? { Value::Thing(v) => out.push(v), Value::Array(v) => { for v in v { @@ -109,7 +116,7 @@ impl RelateStatement { // Loop over the with targets let with = { let mut out = Vec::new(); - match self.with.compute(ctx, opt).await? { + match self.with.compute(ctx, opt, txn, doc).await? { Value::Thing(v) => out.push(v), Value::Array(v) => { for v in v { @@ -158,7 +165,7 @@ impl RelateStatement { // The relation does not have a specific record id Value::Table(tb) => match &self.data { // There is a data clause so check for a record id - Some(data) => match data.rid(ctx, opt, tb).await { + Some(data) => match data.rid(ctx, opt, txn, tb).await { // There was a problem creating the record id Err(e) => return Err(e), // There is an id field so use the record id @@ -175,7 +182,7 @@ impl RelateStatement { // Assign the statement let stm = Statement::from(self); // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } diff --git a/lib/src/sql/statements/remove.rs b/lib/src/sql/statements/remove.rs index e0b0f874..e386243b 100644 --- a/lib/src/sql/statements/remove.rs +++ b/lib/src/sql/statements/remove.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; -use crate::dbs::Level; use crate::dbs::Options; +use crate::dbs::{Level, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::base::{base, base_or_scope, Base}; use crate::sql::comment::{mightbespace, shouldbespace}; @@ -38,20 +39,26 @@ pub enum RemoveStatement { impl RemoveStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { match self { - Self::Namespace(ref v) => v.compute(ctx, opt).await, - Self::Database(ref v) => v.compute(ctx, opt).await, - Self::Function(ref v) => v.compute(ctx, opt).await, - Self::Login(ref v) => v.compute(ctx, opt).await, - Self::Token(ref v) => v.compute(ctx, opt).await, - Self::Scope(ref v) => v.compute(ctx, opt).await, - Self::Param(ref v) => v.compute(ctx, opt).await, - Self::Table(ref v) => v.compute(ctx, opt).await, - Self::Event(ref v) => v.compute(ctx, opt).await, - Self::Field(ref v) => v.compute(ctx, opt).await, - Self::Index(ref v) => v.compute(ctx, opt).await, - Self::Analyzer(ref v) => v.compute(ctx, opt).await, + Self::Namespace(ref v) => v.compute(ctx, opt, txn).await, + Self::Database(ref v) => v.compute(ctx, opt, txn).await, + Self::Function(ref v) => v.compute(ctx, opt, txn).await, + Self::Login(ref v) => v.compute(ctx, opt, txn).await, + Self::Token(ref v) => v.compute(ctx, opt, txn).await, + Self::Scope(ref v) => v.compute(ctx, opt, txn).await, + Self::Param(ref v) => v.compute(ctx, opt, txn).await, + Self::Table(ref v) => v.compute(ctx, opt, txn).await, + Self::Event(ref v) => v.compute(ctx, opt, txn).await, + Self::Field(ref v) => v.compute(ctx, opt, txn).await, + Self::Index(ref v) => v.compute(ctx, opt, txn).await, + Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await, } } } @@ -103,13 +110,16 @@ pub struct RemoveNamespaceStatement { impl RemoveNamespaceStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // No need for NS/DB opt.needs(Level::Kv)?; // Allowed to run? opt.check(Level::Kv)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -154,13 +164,16 @@ pub struct RemoveDatabaseStatement { impl RemoveDatabaseStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected NS? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -205,13 +218,16 @@ pub struct RemoveFunctionStatement { impl RemoveFunctionStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -260,13 +276,16 @@ pub struct RemoveAnalyzerStatement { } impl RemoveAnalyzerStatement { - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -310,15 +329,18 @@ pub struct RemoveLoginStatement { impl RemoveLoginStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { match self.base { Base::Ns => { // Selected NS? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Kv)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -332,8 +354,6 @@ impl RemoveLoginStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -384,15 +404,18 @@ pub struct RemoveTokenStatement { impl RemoveTokenStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { match &self.base { Base::Ns => { // Selected NS? opt.needs(Level::Ns)?; // Allowed to run? opt.check(Level::Kv)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -406,8 +429,6 @@ impl RemoveTokenStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Ns)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -421,8 +442,6 @@ impl RemoveTokenStatement { opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -472,13 +491,16 @@ pub struct RemoveScopeStatement { impl RemoveScopeStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -523,13 +545,16 @@ pub struct RemoveParamStatement { impl RemoveParamStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -572,13 +597,16 @@ pub struct RemoveTableStatement { impl RemoveTableStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -624,13 +652,16 @@ pub struct RemoveEventStatement { impl RemoveEventStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -682,13 +713,16 @@ pub struct RemoveFieldStatement { impl RemoveFieldStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition @@ -741,13 +775,16 @@ pub struct RemoveIndexStatement { impl RemoveIndexStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? opt.check(Level::Db)?; - // Clone transaction - let txn = ctx.try_clone_transaction()?; // Claim transaction let mut run = txn.lock().await; // Delete the definition diff --git a/lib/src/sql/statements/select.rs b/lib/src/sql/statements/select.rs index 0e3819af..94e6bd30 100644 --- a/lib/src/sql/statements/select.rs +++ b/lib/src/sql/statements/select.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::idx::planner::QueryPlanner; use crate::sql::comment::shouldbespace; @@ -72,7 +73,13 @@ impl SelectStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -86,10 +93,10 @@ impl SelectStatement { let mut planner = QueryPlanner::new(opt, &self.cond); // Loop over the select targets for w in self.what.0.iter() { - let v = w.compute(ctx, opt).await?; + let v = w.compute(ctx, opt, txn, doc).await?; match v { Value::Table(t) => { - i.ingest(planner.get_iterable(ctx, t).await?); + i.ingest(planner.get_iterable(ctx, txn, t).await?); } Value::Thing(v) => i.ingest(Iterable::Thing(v)), Value::Range(v) => i.ingest(Iterable::Range(*v)), @@ -124,10 +131,10 @@ impl SelectStatement { let mut ctx = Context::new(ctx); ctx.set_query_executors(ex); // Output the results - i.output(&ctx, opt, &stm).await + i.output(&ctx, opt, txn, &stm).await } else { // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } } diff --git a/lib/src/sql/statements/set.rs b/lib/src/sql/statements/set.rs index d94b0149..e851efe3 100644 --- a/lib/src/sql/statements/set.rs +++ b/lib/src/sql/statements/set.rs @@ -1,5 +1,7 @@ use crate::ctx::Context; use crate::dbs::Options; +use crate::dbs::Transaction; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::mightbespace; use crate::sql::comment::shouldbespace; @@ -25,8 +27,14 @@ impl SetStatement { self.what.writeable() } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { - self.what.compute(ctx, opt).await + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { + self.what.compute(ctx, opt, txn, doc).await } } diff --git a/lib/src/sql/statements/show.rs b/lib/src/sql/statements/show.rs index feaec408..e3b07579 100644 --- a/lib/src/sql/statements/show.rs +++ b/lib/src/sql/statements/show.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; use crate::dbs::Options; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::common::take_u64; @@ -27,7 +28,12 @@ pub struct ShowStatement { impl ShowStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + _ctx: &Context<'_>, + _opt: &Options, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { Err(Error::FeatureNotYetImplemented { feature: "change feed", }) diff --git a/lib/src/sql/statements/sleep.rs b/lib/src/sql/statements/sleep.rs index 07e18d94..09240507 100644 --- a/lib/src/sql/statements/sleep.rs +++ b/lib/src/sql/statements/sleep.rs @@ -1,6 +1,7 @@ use crate::ctx::Context; use crate::dbs::Level; use crate::dbs::Options; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::duration::duration; @@ -18,7 +19,12 @@ pub struct SleepStatement { impl SleepStatement { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + _doc: Option<&CursorDoc<'_>>, + ) -> Result { // No need for NS/DB opt.needs(Level::Kv)?; // Allowed to run? @@ -87,9 +93,9 @@ mod tests { let sql = "SLEEP 500ms"; let time = SystemTime::now(); let opt = Options::default().with_auth(Arc::new(Auth::Kv)); - let (ctx, _) = mock().await; + let (ctx, _, _) = mock().await; let (_, stm) = sleep(sql).unwrap(); - let value = stm.compute(&ctx, &opt).await.unwrap(); + let value = stm.compute(&ctx, &opt, None).await.unwrap(); assert!(time.elapsed().unwrap() >= time::Duration::microseconds(500)); assert_eq!(value, Value::None); } diff --git a/lib/src/sql/statements/update.rs b/lib/src/sql/statements/update.rs index 95e3489c..f1212a9c 100644 --- a/lib/src/sql/statements/update.rs +++ b/lib/src/sql/statements/update.rs @@ -1,9 +1,10 @@ use crate::ctx::Context; -use crate::dbs::Iterable; use crate::dbs::Iterator; use crate::dbs::Level; use crate::dbs::Options; use crate::dbs::Statement; +use crate::dbs::{Iterable, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::comment::shouldbespace; use crate::sql::cond::{cond, Cond}; @@ -43,7 +44,13 @@ impl UpdateStatement { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Selected DB? opt.needs(Level::Db)?; // Allowed to run? @@ -54,7 +61,7 @@ impl UpdateStatement { let opt = &opt.new_with_futures(false); // Loop over the update targets for w in self.what.0.iter() { - let v = w.compute(ctx, opt).await?; + let v = w.compute(ctx, opt, txn, doc).await?; match v { Value::Table(v) => i.ingest(Iterable::Table(v)), Value::Thing(v) => i.ingest(Iterable::Thing(v)), @@ -110,7 +117,7 @@ impl UpdateStatement { // Assign the statement let stm = Statement::from(self); // Output the results - i.output(ctx, opt, &stm).await + i.output(ctx, opt, txn, &stm).await } } diff --git a/lib/src/sql/subquery.rs b/lib/src/sql/subquery.rs index f1a76cf6..0147011f 100644 --- a/lib/src/sql/subquery.rs +++ b/lib/src/sql/subquery.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::common::{closeparentheses, openparentheses}; use crate::sql::ending::subquery as ending; @@ -59,25 +60,31 @@ impl Subquery { } } /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { // Prevent deep recursion let opt = &opt.dive(2)?; // Process the subquery match self { - Self::Value(ref v) => v.compute(ctx, opt).await, - Self::Ifelse(ref v) => v.compute(ctx, opt).await, - Self::Output(ref v) => v.compute(ctx, opt).await, + Self::Value(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Ifelse(ref v) => v.compute(ctx, opt, txn, doc).await, + Self::Output(ref v) => v.compute(ctx, opt, txn, doc).await, Self::Select(ref v) => { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result @@ -93,13 +100,13 @@ impl Subquery { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result @@ -115,13 +122,13 @@ impl Subquery { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result @@ -137,13 +144,13 @@ impl Subquery { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result @@ -159,13 +166,13 @@ impl Subquery { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result @@ -181,13 +188,13 @@ impl Subquery { // Is this a single output? let one = v.single(); // Duplicate context - let mut child_ctx = Context::new(ctx); + let mut ctx = Context::new(ctx); // Add parent document - if let Some(doc) = ctx.doc() { - child_ctx.add_value("parent", doc); + if let Some(doc) = doc { + ctx.add_value("parent", doc.doc.as_ref()); } // Process subquery - match v.compute(&child_ctx, opt).await? { + match v.compute(&ctx, opt, txn, doc).await? { // This is a single record result Value::Array(mut a) if one => match a.len() { // There was at least one result diff --git a/lib/src/sql/thing.rs b/lib/src/sql/thing.rs index fc89bb58..8b136dfb 100644 --- a/lib/src/sql/thing.rs +++ b/lib/src/sql/thing.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::error::IResult; use crate::sql::escape::escape_rid; @@ -102,10 +103,16 @@ impl fmt::Display for Thing { impl Thing { /// Process this type returning a computed simple Value - pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&CursorDoc<'_>>, + ) -> Result { Ok(Value::Thing(Thing { tb: self.tb.clone(), - id: self.id.compute(ctx, opt).await?, + id: self.id.compute(ctx, opt, txn, doc).await?, })) } } diff --git a/lib/src/sql/value/cut.rs b/lib/src/sql/value/cut.rs index 85c118b8..705b62c7 100644 --- a/lib/src/sql/value/cut.rs +++ b/lib/src/sql/value/cut.rs @@ -102,121 +102,121 @@ mod tests { #[tokio::test] async fn del_none() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_reset() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_basic() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_wrong() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_other() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_fields_flat() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_where_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_where_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/decrement.rs b/lib/src/sql/value/decrement.rs index b176ff8a..805db7ac 100644 --- a/lib/src/sql/value/decrement.rs +++ b/lib/src/sql/value/decrement.rs @@ -1,5 +1,5 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; use crate::err::Error; use crate::sql::number::Number; use crate::sql::part::Part; @@ -11,21 +11,22 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], val: Value, ) -> Result<(), Error> { - match self.get(ctx, opt, path).await? { + match self.get(ctx, opt, txn, None, path).await? { Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, path, Value::from(v - x)).await, + Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await, _ => Ok(()), }, Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, path, Value::from(v - x)).await, - x => self.set(ctx, opt, path, Value::from(v - x)).await, + Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await, + x => self.set(ctx, opt, txn, path, Value::from(v - x)).await, }, Value::None => match val { Value::Number(x) => { - self.set(ctx, opt, path, Value::from(Number::from(0) - x)).await + self.set(ctx, opt, txn, path, Value::from(Number::from(0) - x)).await } _ => Ok(()), }, @@ -44,51 +45,51 @@ mod tests { #[tokio::test] async fn decrement_none() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("other"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 100, other: -10 }"); - val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn decrement_number() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 90 }"); - val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn decrement_array_number() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test[1]"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 190, 300] }"); - val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn decrement_array_value() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 300] }"); - val.decrement(&ctx, &opt, &idi, Value::from(200)).await.unwrap(); + val.decrement(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn decrement_array_array() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [200] }"); - val.decrement(&ctx, &opt, &idi, Value::parse("[100, 300]")).await.unwrap(); + val.decrement(&ctx, &opt, &txn, &idi, Value::parse("[100, 300]")).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/del.rs b/lib/src/sql/value/del.rs index d11b23c8..a076ce19 100644 --- a/lib/src/sql/value/del.rs +++ b/lib/src/sql/value/del.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::exe::try_join_all_buffered; use crate::sql::array::Abolish; @@ -17,6 +18,7 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], ) -> Result<(), Error> { match path.first() { @@ -30,7 +32,7 @@ impl Value { Ok(()) } _ => match v.get_mut(f.as_str()) { - Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await, + Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await, _ => Ok(()), }, }, @@ -40,7 +42,7 @@ impl Value { Ok(()) } _ => match v.get_mut(&i.to_string()) { - Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await, + Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await, _ => Ok(()), }, }, @@ -55,7 +57,7 @@ impl Value { } _ => { let path = path.next(); - let futs = v.iter_mut().map(|v| v.del(ctx, opt, path)); + let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path)); try_join_all_buffered(futs).await?; Ok(()) } @@ -69,7 +71,7 @@ impl Value { Ok(()) } _ => match v.first_mut() { - Some(v) => v.del(ctx, opt, path.next()).await, + Some(v) => v.del(ctx, opt, txn, path.next()).await, None => Ok(()), }, }, @@ -82,7 +84,7 @@ impl Value { Ok(()) } _ => match v.last_mut() { - Some(v) => v.del(ctx, opt, path.next()).await, + Some(v) => v.del(ctx, opt, txn, path.next()).await, None => Ok(()), }, }, @@ -94,7 +96,7 @@ impl Value { Ok(()) } _ => match v.get_mut(i.to_usize()) { - Some(v) => v.del(ctx, opt, path.next()).await, + Some(v) => v.del(ctx, opt, txn, path.next()).await, None => Ok(()), }, }, @@ -104,9 +106,8 @@ impl Value { // iterate in reverse, and call swap_remove let mut m = HashSet::new(); for (i, v) in v.iter().enumerate() { - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(v); - if w.compute(&child_ctx, opt).await?.is_truthy() { + let cur = CursorDoc::new(None, None, v); + if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { m.insert(i); }; } @@ -116,17 +117,16 @@ impl Value { _ => { let path = path.next(); for v in v.iter_mut() { - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(v); - if w.compute(&child_ctx, opt).await?.is_truthy() { - v.del(ctx, opt, path).await?; + let cur = CursorDoc::new(None, None, v); + if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { + v.del(ctx, opt, txn, path).await?; } } Ok(()) } }, _ => { - let futs = v.iter_mut().map(|v| v.del(ctx, opt, path)); + let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path)); try_join_all_buffered(futs).await?; Ok(()) } @@ -150,121 +150,121 @@ mod tests { #[tokio::test] async fn del_none() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_reset() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_basic() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_wrong() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_other() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_fields_flat() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_where_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn del_array_where_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + val.del(&ctx, &opt, &txn, &idi).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/extend.rs b/lib/src/sql/value/extend.rs index 4ae2cb66..ee3cbe8a 100644 --- a/lib/src/sql/value/extend.rs +++ b/lib/src/sql/value/extend.rs @@ -1,5 +1,5 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; use crate::err::Error; use crate::sql::array::Uniq; use crate::sql::part::Part; @@ -10,17 +10,18 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], val: Value, ) -> Result<(), Error> { - match self.get(ctx, opt, path).await? { + match self.get(ctx, opt, txn, None, path).await? { Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, path, Value::from((v + x).uniq())).await, - x => self.set(ctx, opt, path, Value::from((v + x).uniq())).await, + 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, }, Value::None => match val { - Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await, - x => self.set(ctx, opt, path, Value::from(vec![x])).await, + Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await, + x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await, }, _ => Ok(()), } @@ -37,21 +38,21 @@ mod tests { #[tokio::test] async fn extend_array_value() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 200, 300] }"); - val.extend(&ctx, &opt, &idi, Value::from(200)).await.unwrap(); + val.extend(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn extend_array_array() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 200, 300, 400, 500] }"); - val.extend(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); + val.extend(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/fetch.rs b/lib/src/sql/value/fetch.rs index a55b0384..5783cea1 100644 --- a/lib/src/sql/value/fetch.rs +++ b/lib/src/sql/value/fetch.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::edges::Edges; use crate::sql::field::{Field, Fields}; @@ -17,6 +18,7 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], ) -> Result<(), Error> { match path.first() { @@ -25,53 +27,52 @@ impl Value { // Current path part is an object Value::Object(v) => match p { Part::Graph(_) => match v.rid() { - Some(v) => Value::Thing(v).fetch(ctx, opt, path.next()).await, + Some(v) => Value::Thing(v).fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, Part::Field(f) => match v.get_mut(f as &str) { - Some(v) => v.fetch(ctx, opt, path.next()).await, + Some(v) => v.fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, Part::Index(i) => match v.get_mut(&i.to_string()) { - Some(v) => v.fetch(ctx, opt, path.next()).await, + Some(v) => v.fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, - Part::All => self.fetch(ctx, opt, path.next()).await, + Part::All => self.fetch(ctx, opt, txn, path.next()).await, _ => Ok(()), }, // Current path part is an array Value::Array(v) => match p { Part::All => { let path = path.next(); - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path)); + let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); try_join_all(futs).await?; Ok(()) } Part::First => match v.first_mut() { - Some(v) => v.fetch(ctx, opt, path.next()).await, + Some(v) => v.fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, Part::Last => match v.last_mut() { - Some(v) => v.fetch(ctx, opt, path.next()).await, + Some(v) => v.fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, Part::Index(i) => match v.get_mut(i.to_usize()) { - Some(v) => v.fetch(ctx, opt, path.next()).await, + Some(v) => v.fetch(ctx, opt, txn, path.next()).await, None => Ok(()), }, Part::Where(w) => { let path = path.next(); for v in v.iter_mut() { - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(v); - if w.compute(&child_ctx, opt).await?.is_truthy() { - v.fetch(ctx, opt, path).await?; + let cur = CursorDoc::new(None, None, v); + if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { + v.fetch(ctx, opt, txn, path).await?; } } Ok(()) } _ => { - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path)); + let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); try_join_all(futs).await?; Ok(()) } @@ -95,10 +96,10 @@ impl Value { ..SelectStatement::default() }; *self = stm - .compute(ctx, opt) + .compute(ctx, opt, txn, None) .await? .all() - .get(ctx, opt, path.next()) + .get(ctx, opt, txn, None, path.next()) .await? .flatten() .ok()?; @@ -111,7 +112,7 @@ impl Value { what: Values(vec![Value::from(val)]), ..SelectStatement::default() }; - *self = stm.compute(ctx, opt).await?.first(); + *self = stm.compute(ctx, opt, txn, None).await?.first(); Ok(()) } } @@ -123,7 +124,7 @@ impl Value { None => match self { // Current path part is an array Value::Array(v) => { - let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path)); + let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path)); try_join_all(futs).await?; Ok(()) } @@ -137,7 +138,7 @@ impl Value { what: Values(vec![Value::from(val)]), ..SelectStatement::default() }; - *self = stm.compute(ctx, opt).await?.first(); + *self = stm.compute(ctx, opt, txn, None).await?.first(); Ok(()) } // Ignore everything else diff --git a/lib/src/sql/value/get.rs b/lib/src/sql/value/get.rs index 25d4334c..23ced18f 100644 --- a/lib/src/sql/value/get.rs +++ b/lib/src/sql/value/get.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::exe::try_join_all_buffered; use crate::sql::edges::Edges; @@ -21,6 +22,8 @@ impl Value { &self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, + doc: Option<&'async_recursion CursorDoc<'_>>, path: &[Part], ) -> Result { match path.first() { @@ -30,15 +33,15 @@ impl Value { Value::Geometry(v) => match p { // If this is the 'type' field then continue Part::Field(f) if f.is_type() => { - Value::from(v.as_type()).get(ctx, opt, path.next()).await + Value::from(v.as_type()).get(ctx, opt, txn, doc, path.next()).await } // If this is the 'coordinates' field then continue Part::Field(f) if f.is_coordinates() && v.is_geometry() => { - v.as_coordinates().get(ctx, opt, path.next()).await + v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await } // If this is the 'geometries' field then continue Part::Field(f) if f.is_geometries() && v.is_collection() => { - v.as_coordinates().get(ctx, opt, path.next()).await + v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await } // otherwise return none _ => Ok(Value::None), @@ -54,9 +57,9 @@ impl Value { // Ensure the future is processed let fut = &opt.new_with_futures(true); // Get the future return value - let val = v.compute(ctx, fut).await?; + let val = v.compute(ctx, fut, txn, doc).await?; // Fetch the embedded field - val.get(ctx, opt, path).await + val.get(ctx, opt, txn, doc, path).await } } } @@ -67,58 +70,57 @@ impl Value { Some(Value::Thing(Thing { id: Id::Object(v), .. - })) => Value::Object(v.clone()).get(ctx, opt, 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, path.next()).await, - Some(v) => v.get(ctx, opt, 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, 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, path.next()).await, + Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, None => Ok(Value::None), }, - Part::All => self.get(ctx, opt, 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, 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, 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, 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, path.next()).await, + Some(v) => v.get(ctx, opt, txn, doc, path.next()).await, None => Ok(Value::None), }, Part::Where(w) => { let path = path.next(); let mut a = Vec::new(); for v in v.iter() { - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(v); - if w.compute(&child_ctx, opt).await?.is_truthy() { - a.push(v.get(&child_ctx, opt, path).await?) + let cur = Some(CursorDoc::new(None, None, v)); + if w.compute(ctx, opt, txn, cur.as_ref()).await?.is_truthy() { + a.push(v.get(ctx, opt, txn, cur.as_ref(), path).await?) } } Ok(a.into()) } _ => { - let futs = v.iter().map(|v| v.get(ctx, opt, path)); + let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path)); try_join_all_buffered(futs).await.map(Into::into) } }, @@ -137,7 +139,11 @@ impl Value { what: Values(vec![Value::from(val)]), ..SelectStatement::default() }; - stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await + stm.compute(ctx, opt, txn, None) + .await? + .first() + .get(ctx, opt, txn, None, path) + .await } } } @@ -165,18 +171,18 @@ impl Value { }; match path.len() { 1 => stm - .compute(ctx, opt) + .compute(ctx, opt, txn, None) .await? .all() - .get(ctx, opt, ID.as_ref()) + .get(ctx, opt, txn, None, ID.as_ref()) .await? .flatten() .ok(), _ => stm - .compute(ctx, opt) + .compute(ctx, opt, txn, None) .await? .all() - .get(ctx, opt, path.next()) + .get(ctx, opt, txn, None, path.next()) .await? .flatten() .ok(), @@ -189,7 +195,11 @@ impl Value { what: Values(vec![Value::from(val)]), ..SelectStatement::default() }; - stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await + stm.compute(ctx, opt, txn, None) + .await? + .first() + .get(ctx, opt, txn, None, path) + .await } }, } @@ -215,28 +225,28 @@ mod tests { #[tokio::test] async fn get_none() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn get_basic() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(123)); } #[tokio::test] async fn get_thing() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!( res, Value::from(Thing { @@ -248,19 +258,19 @@ mod tests { #[tokio::test] async fn get_array() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(456)); } #[tokio::test] async fn get_array_thing() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!( res, Value::from(Thing { @@ -272,46 +282,46 @@ mod tests { #[tokio::test] async fn get_array_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(36)); } #[tokio::test] async fn get_array_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(vec![34, 36])); } #[tokio::test] async fn get_array_fields_flat() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(vec![34, 36])); } #[tokio::test] async fn get_array_where_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!(res, Value::from(vec![36])); } #[tokio::test] async fn get_array_where_fields() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!( res, Value::from(vec![Value::from(map! { @@ -322,10 +332,10 @@ mod tests { #[tokio::test] async fn get_future_embedded_field() { - let (ctx, opt) = mock().await; + 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, &idi).await.unwrap(); + let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap(); assert_eq!( res, Value::from(vec![Value::from(map! { @@ -336,12 +346,12 @@ mod tests { #[tokio::test] async fn get_future_embedded_field_with_reference() { - let (mut ctx, opt) = mock().await; + 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: { { something: something } } }"); - ctx.add_cursor_doc(&doc); - let res = val.get(&ctx, &opt, &idi).await.unwrap(); + let cur = CursorDoc::new(None, None, &doc); + let res = val.get(&ctx, &opt, &txn, Some(&cur), &idi).await.unwrap(); assert_eq!( res, Value::from(vec![Value::from(map! { diff --git a/lib/src/sql/value/increment.rs b/lib/src/sql/value/increment.rs index bc655f49..ede43e4a 100644 --- a/lib/src/sql/value/increment.rs +++ b/lib/src/sql/value/increment.rs @@ -1,5 +1,5 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; use crate::err::Error; use crate::sql::number::Number; use crate::sql::part::Part; @@ -11,24 +11,25 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], val: Value, ) -> Result<(), Error> { - match self.get(ctx, opt, path).await? { + match self.get(ctx, opt, txn, None, path).await? { Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, path, Value::from(v + x)).await, + Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await, _ => Ok(()), }, Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, path, Value::from(v + x)).await, - x => self.set(ctx, opt, path, Value::from(v + x)).await, + Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await, + x => self.set(ctx, opt, txn, path, Value::from(v + x)).await, }, Value::None => match val { Value::Number(x) => { - self.set(ctx, opt, path, Value::from(Number::from(0) + x)).await + self.set(ctx, opt, txn, path, Value::from(Number::from(0) + x)).await } - Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await, - x => self.set(ctx, opt, path, Value::from(vec![x])).await, + Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await, + x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await, }, _ => Ok(()), } @@ -45,51 +46,51 @@ mod tests { #[tokio::test] async fn increment_none() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("other"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 100, other: +10 }"); - val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn increment_number() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 110 }"); - val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn increment_array_number() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test[1]"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 210, 300] }"); - val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap(); + val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn increment_array_value() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 200, 300, 200] }"); - val.increment(&ctx, &opt, &idi, Value::from(200)).await.unwrap(); + val.increment(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn increment_array_array() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }"); - val.increment(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); + val.increment(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/set.rs b/lib/src/sql/value/set.rs index b117dd37..1277ee45 100644 --- a/lib/src/sql/value/set.rs +++ b/lib/src/sql/value/set.rs @@ -1,5 +1,6 @@ use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::exe::try_join_all_buffered; use crate::sql::part::Next; @@ -15,6 +16,7 @@ impl Value { &mut self, ctx: &Context<'_>, opt: &Options, + txn: &Transaction, path: &[Part], val: Value, ) -> Result<(), Error> { @@ -24,28 +26,28 @@ impl Value { // Current path part is an object Value::Object(v) => match p { Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) { - Some(v) if v.is_some() => v.set(ctx, opt, 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, path.next(), val).await?; + obj.set(ctx, opt, txn, path.next(), val).await?; v.insert(g.to_raw(), obj); Ok(()) } }, Part::Field(f) => match v.get_mut(f as &str) { - Some(v) if v.is_some() => v.set(ctx, opt, 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, path.next(), val).await?; + obj.set(ctx, opt, txn, path.next(), val).await?; v.insert(f.to_raw(), obj); Ok(()) } }, Part::Index(i) => match v.get_mut(&i.to_string()) { - Some(v) if v.is_some() => v.set(ctx, opt, 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, path.next(), val).await?; + obj.set(ctx, opt, txn, path.next(), val).await?; v.insert(i.to_string(), obj); Ok(()) } @@ -56,35 +58,34 @@ impl Value { Value::Array(v) => match p { Part::All => { let path = path.next(); - let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone())); + let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone())); try_join_all_buffered(futs).await?; Ok(()) } Part::First => match v.first_mut() { - Some(v) => v.set(ctx, opt, path.next(), val).await, + Some(v) => v.set(ctx, opt, txn, path.next(), val).await, None => Ok(()), }, Part::Last => match v.last_mut() { - Some(v) => v.set(ctx, opt, path.next(), val).await, + Some(v) => v.set(ctx, opt, txn, path.next(), val).await, None => Ok(()), }, Part::Index(i) => match v.get_mut(i.to_usize()) { - Some(v) => v.set(ctx, opt, path.next(), val).await, + Some(v) => v.set(ctx, opt, txn, path.next(), val).await, None => Ok(()), }, Part::Where(w) => { let path = path.next(); for v in v.iter_mut() { - let mut child_ctx = Context::new(ctx); - child_ctx.add_cursor_doc(v); - if w.compute(&child_ctx, opt).await?.is_truthy() { - v.set(ctx, opt, path, val.clone()).await?; + let cur = CursorDoc::new(None, None, v); + if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() { + v.set(ctx, opt, txn, path, val.clone()).await?; } } Ok(()) } _ => { - let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone())); + let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone())); try_join_all_buffered(futs).await?; Ok(()) } @@ -92,12 +93,12 @@ impl Value { // Current path part is empty Value::Null => { *self = Value::base(); - self.set(ctx, opt, path, val).await + self.set(ctx, opt, txn, path, val).await } // Current path part is empty Value::None => { *self = Value::base(); - self.set(ctx, opt, path, val).await + self.set(ctx, opt, txn, path, val).await } // Ignore everything else _ => Ok(()), @@ -121,141 +122,141 @@ mod tests { #[tokio::test] async fn set_none() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::default(); let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let res = Value::parse("999"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_empty() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test"); let mut val = Value::None; let res = Value::parse("{ test: 999 }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_blank() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test.something"); let mut val = Value::None; let res = Value::parse("{ test: { something: 999 } }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_reset() { - let (ctx, opt) = mock().await; + 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("{ test: 999 }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_basic() { - let (ctx, opt) = mock().await; + 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, something: 999 } }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_allow() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test.something.allow"); let mut val = Value::parse("{ test: { other: null } }"); let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_wrong() { - let (ctx, opt) = mock().await; + 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.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_other() { - let (ctx, opt) = mock().await; + 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: { something: 999 }, something: 123 } }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_array() { - let (ctx, opt) = mock().await; + 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, 999, 789] } }"); - val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_array_field() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test.something[1].age"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }"); - val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_array_fields() { - let (ctx, opt) = mock().await; + 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, &idi, Value::from(21)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_array_fields_flat() { - let (ctx, opt) = mock().await; + 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, &idi, Value::from(21)).await.unwrap(); + 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) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test.something[WHERE age > 35].age"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }"); - val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap(); assert_eq!(res, val); } #[tokio::test] async fn set_array_where_fields() { - let (ctx, opt) = mock().await; + let (ctx, opt, txn) = mock().await; let idi = Idiom::parse("test.something[WHERE age > 35]"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let res = Value::parse("{ test: { something: [{ age: 34 }, 21] } }"); - val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap(); + val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap(); assert_eq!(res, val); } } diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index b0b29121..b3fd7f59 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -1,7 +1,8 @@ #![allow(clippy::derive_ord_xor_partial_ord)] use crate::ctx::Context; -use crate::dbs::Options; +use crate::dbs::{Options, Transaction}; +use crate::doc::CursorDoc; use crate::err::Error; use crate::sql::array::Uniq; use crate::sql::array::{array, Array}; @@ -2484,21 +2485,27 @@ impl Value { /// 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(&self, ctx: &Context<'_>, opt: &Options) -> Result { + pub(crate) async fn compute( + &self, + ctx: &Context<'_>, + opt: &Options, + txn: &Transaction, + doc: Option<&'async_recursion CursorDoc<'_>>, + ) -> Result { match self { - Value::Cast(v) => v.compute(ctx, opt).await, - Value::Thing(v) => v.compute(ctx, opt).await, - Value::Block(v) => v.compute(ctx, opt).await, - Value::Range(v) => v.compute(ctx, opt).await, - Value::Param(v) => v.compute(ctx, opt).await, - Value::Idiom(v) => v.compute(ctx, opt).await, - Value::Array(v) => v.compute(ctx, opt).await, - Value::Object(v) => v.compute(ctx, opt).await, - Value::Future(v) => v.compute(ctx, opt).await, - Value::Constant(v) => v.compute(ctx, opt).await, - Value::Function(v) => v.compute(ctx, opt).await, - Value::Subquery(v) => v.compute(ctx, opt).await, - Value::Expression(v) => v.compute(ctx, opt).await, + Value::Cast(v) => v.compute(ctx, opt, txn, doc).await, + Value::Thing(v) => v.compute(ctx, opt, txn, doc).await, + Value::Block(v) => v.compute(ctx, opt, txn, doc).await, + Value::Range(v) => v.compute(ctx, opt, txn, doc).await, + Value::Param(v) => v.compute(ctx, opt, txn, doc).await, + Value::Idiom(v) => v.compute(ctx, opt, txn, doc).await, + Value::Array(v) => v.compute(ctx, opt, txn, doc).await, + Value::Object(v) => v.compute(ctx, opt, txn, doc).await, + Value::Future(v) => v.compute(ctx, opt, txn, doc).await, + Value::Constant(v) => v.compute(ctx, opt, txn, doc).await, + Value::Function(v) => v.compute(ctx, opt, txn, doc).await, + Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await, + Value::Expression(v) => v.compute(ctx, opt, txn, doc).await, _ => Ok(self.to_owned()), } } diff --git a/lib/tests/matches.rs b/lib/tests/matches.rs index cdbb3e2f..7578ed5b 100644 --- a/lib/tests/matches.rs +++ b/lib/tests/matches.rs @@ -92,14 +92,20 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error Ok(()) } -#[tokio::test] -async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> { - let sql = r" +async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(), Error> { + let sql = format!( + r" CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr']; DEFINE ANALYZER simple TOKENIZERS blank,class; DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS; - SELECT id, search::highlight('', '', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' EXPLAIN; - "; + SELECT id, search::highlight('', '', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {} EXPLAIN; + ", + if parallel { + "PARALLEL" + } else { + "" + } + ); 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).await?; @@ -141,6 +147,16 @@ async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> { Ok(()) } +#[tokio::test] +async fn select_where_matches_using_index_and_arrays_non_parallel() -> Result<(), Error> { + select_where_matches_using_index_and_arrays(false).await +} + +#[tokio::test] +async fn select_where_matches_using_index_and_arrays_with_parallel() -> Result<(), Error> { + select_where_matches_using_index_and_arrays(true).await +} + #[tokio::test] async fn select_where_matches_using_index_offsets() -> Result<(), Error> { let sql = r"