QueryPlanner / indexing / Context / Cursor doc (#2229)

This commit is contained in:
Emmanuel Keller 2023-07-06 15:57:42 +01:00 committed by GitHub
parent 4b690c763b
commit e9eeb9aca7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
97 changed files with 1624 additions and 1817 deletions

1
Cargo.lock generated
View file

@ -4523,7 +4523,6 @@ dependencies = [
"async-channel", "async-channel",
"async-executor", "async-executor",
"async-recursion", "async-recursion",
"async-trait",
"base64 0.21.2", "base64 0.21.2",
"bcrypt", "bcrypt",
"bincode", "bincode",

View file

@ -54,7 +54,6 @@ targets = []
addr = { version = "0.15.6", default-features = false, features = ["std"] } addr = { version = "0.15.6", default-features = false, features = ["std"] }
argon2 = "0.5.0" argon2 = "0.5.0"
ascii = { version = "0.3.2", package = "any_ascii" } ascii = { version = "0.3.2", package = "any_ascii" }
async-trait = "0.1.69"
async-recursion = "1.0.4" async-recursion = "1.0.4"
base64_lib = { version = "0.21.2", package = "base64" } base64_lib = { version = "0.21.2", package = "base64" }
bcrypt = "0.14.0" bcrypt = "0.14.0"

View file

@ -1,12 +1,8 @@
use crate::ctx::canceller::Canceller; use crate::ctx::canceller::Canceller;
use crate::ctx::reason::Reason; use crate::ctx::reason::Reason;
use crate::dbs::Notification; 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::idx::planner::executor::QueryExecutor;
use crate::sql::value::Value; use crate::sql::value::Value;
use crate::sql::Thing;
use channel::Sender; use channel::Sender;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
@ -36,18 +32,10 @@ pub struct Context<'a> {
cancelled: Arc<AtomicBool>, cancelled: Arc<AtomicBool>,
// A collection of read only values stored in this context. // A collection of read only values stored in this context.
values: HashMap<Cow<'static, str>, Cow<'a, Value>>, values: HashMap<Cow<'static, str>, Cow<'a, Value>>,
// Stores the current transaction if available
transaction: Option<Transaction>,
// Stores the notification channel if available // Stores the notification channel if available
notifications: Option<Sender<Notification>>, notifications: Option<Sender<Notification>>,
// An optional query executor // An optional query executor
query_executors: Option<Arc<HashMap<String, QueryExecutor>>>, query_executors: Option<Arc<HashMap<String, QueryExecutor>>>,
// An optional record id
thing: Option<&'a Thing>,
// An optional doc id
doc_id: Option<DocId>,
// An optional cursor document
cursor_doc: Option<&'a Value>,
} }
impl<'a> Default for Context<'a> { impl<'a> Default for Context<'a> {
@ -63,8 +51,6 @@ impl<'a> Debug for Context<'a> {
.field("deadline", &self.deadline) .field("deadline", &self.deadline)
.field("cancelled", &self.cancelled) .field("cancelled", &self.cancelled)
.field("values", &self.values) .field("values", &self.values)
.field("thing", &self.thing)
.field("doc", &self.cursor_doc)
.finish() .finish()
} }
} }
@ -77,12 +63,8 @@ impl<'a> Context<'a> {
parent: None, parent: None,
deadline: None, deadline: None,
cancelled: Arc::new(AtomicBool::new(false)), cancelled: Arc::new(AtomicBool::new(false)),
transaction: None,
notifications: None, notifications: None,
query_executors: None, query_executors: None,
thing: None,
doc_id: None,
cursor_doc: None,
} }
} }
@ -93,12 +75,8 @@ impl<'a> Context<'a> {
parent: Some(parent), parent: Some(parent),
deadline: parent.deadline, deadline: parent.deadline,
cancelled: Arc::new(AtomicBool::new(false)), cancelled: Arc::new(AtomicBool::new(false)),
transaction: parent.transaction.clone(),
notifications: parent.notifications.clone(), notifications: parent.notifications.clone(),
query_executors: parent.query_executors.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) 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 /// Add the LIVE query notification channel to the context, so that we
/// can send notifications to any subscribers. /// can send notifications to any subscribers.
pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) { pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) {
self.notifications = chn.cloned() 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 /// Set the query executors
pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) { pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) {
self.query_executors = Some(Arc::new(executors)); 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())) 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<Transaction, Error> {
self.transaction.clone().ok_or(Error::Unreachable)
}
pub fn notifications(&self) -> Option<Sender<Notification>> { pub fn notifications(&self) -> Option<Sender<Notification>> {
self.notifications.clone() self.notifications.clone()
} }
pub fn thing(&self) -> Option<&Thing> {
self.thing
}
pub fn doc_id(&self) -> Option<DocId> {
self.doc_id
}
pub fn doc(&self) -> Option<&Value> {
self.cursor_doc
}
pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> { pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> {
if let Some(qe) = &self.query_executors { if let Some(qe) = &self.query_executors {
qe.get(tb) qe.get(tb)

View file

@ -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<Thing>, 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<Thing>, 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<Thing>, 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<Thing>, 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<Thing>, 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<Thing>, 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<Vec<u8>> = 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<Thing>, 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<Vec<u8>> = 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<Thing>, 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::<Vec<_>>(),
// /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::<Vec<_>>(),
// /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::<Vec<_>>(),
},
};
//
for (beg, end) in keys.iter() {
// Prepare the next holder key
let mut nxt: Option<Vec<u8>> = 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<Thing>, 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(),
})
}
}
}

View file

@ -34,6 +34,10 @@ impl<'a> Executor<'a> {
} }
} }
fn txn(&self) -> Transaction {
self.txn.clone().expect("unreachable: txn was None after successful begin")
}
/// # Return /// # Return
/// - true if a new transaction has begun /// - true if a new transaction has begun
/// - false if /// - false if
@ -275,10 +279,7 @@ impl<'a> Executor<'a> {
// Check if the variable is a protected variable // Check if the variable is a protected variable
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) { let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
// The variable isn't protected and can be stored // The variable isn't protected and can be stored
false => { false => stm.compute(&ctx, &opt, &self.txn(), None).await,
ctx.add_transaction(self.txn.as_ref());
stm.compute(&ctx, &opt).await
}
// The user tried to set a protected variable // The user tried to set a protected variable
true => Err(Error::InvalidParam { true => Err(Error::InvalidParam {
// Move the parameter name, as we no longer need it // Move the parameter name, as we no longer need it
@ -338,16 +339,15 @@ impl<'a> Executor<'a> {
true => Err(Error::TxFailure), true => Err(Error::TxFailure),
// The transaction began successfully // The transaction began successfully
false => { false => {
let mut ctx = Context::new(&ctx);
// Process the statement // Process the statement
let res = match stm.timeout() { let res = match stm.timeout() {
// There is a timeout clause // There is a timeout clause
Some(timeout) => { Some(timeout) => {
// Set statement timeout // Set statement timeout
let mut ctx = Context::new(&ctx);
ctx.add_timeout(timeout); ctx.add_timeout(timeout);
ctx.add_transaction(self.txn.as_ref());
// Process the statement // Process the statement
let res = stm.compute(&ctx, &opt).await; let res = stm.compute(&ctx, &opt, &self.txn(), None).await;
// Catch statement timeout // Catch statement timeout
match ctx.is_timedout() { match ctx.is_timedout() {
true => Err(Error::QueryTimedout), true => Err(Error::QueryTimedout),
@ -355,10 +355,7 @@ impl<'a> Executor<'a> {
} }
} }
// There is no timeout clause // There is no timeout clause
None => { None => stm.compute(&ctx, &opt, &self.txn(), None).await,
ctx.add_transaction(self.txn.as_ref());
stm.compute(&ctx, &opt).await
}
}; };
// Catch global timeout // Catch global timeout
let res = match ctx.is_timedout() { let res = match ctx.is_timedout() {

View file

@ -1,9 +1,11 @@
use crate::ctx::Canceller; use crate::ctx::Canceller;
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::docids::DocId;
use crate::idx::planner::plan::Plan; use crate::idx::planner::plan::Plan;
use crate::sql::array::Array; use crate::sql::array::Array;
use crate::sql::edges::Edges; use crate::sql::edges::Edges;
@ -74,6 +76,7 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Log the statement // Log the statement
@ -82,29 +85,29 @@ impl Iterator {
let mut cancel_ctx = Context::new(ctx); let mut cancel_ctx = Context::new(ctx);
self.run = cancel_ctx.add_cancel(); self.run = cancel_ctx.add_cancel();
// Process the query LIMIT clause // 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 // 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 // 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 // Process prepared values
self.iterate(&cancel_ctx, opt, stm).await?; self.iterate(&cancel_ctx, opt, txn, stm).await?;
// Return any document errors // Return any document errors
if let Some(e) = self.error.take() { if let Some(e) = self.error.take() {
return Err(e); return Err(e);
} }
// Process any SPLIT clause // Process any SPLIT clause
self.output_split(ctx, opt, stm).await?; self.output_split(ctx, opt, txn, stm).await?;
// Process any GROUP clause // Process any GROUP clause
self.output_group(ctx, opt, stm).await?; self.output_group(ctx, opt, txn, stm).await?;
// Process any ORDER clause // Process any ORDER clause
self.output_order(ctx, opt, stm).await?; self.output_order(ctx, opt, txn, stm).await?;
// Process any START clause // Process any START clause
self.output_start(ctx, opt, stm).await?; self.output_start(ctx, opt, txn, stm).await?;
// Process any LIMIT clause // Process any LIMIT clause
self.output_limit(ctx, opt, stm).await?; self.output_limit(ctx, opt, txn, stm).await?;
// Process any FETCH clause // 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 // Add the EXPLAIN clause to the result
if let Some(e) = explanation { if let Some(e) = explanation {
self.results.push(e); self.results.push(e);
@ -118,10 +121,11 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(v) = stm.limit() { 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(()) Ok(())
} }
@ -131,10 +135,11 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(v) = stm.start() { 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(()) Ok(())
} }
@ -144,6 +149,7 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(splits) = stm.split() { if let Some(splits) = stm.split() {
@ -162,7 +168,7 @@ impl Iterator {
// Make a copy of object // Make a copy of object
let mut obj = obj.clone(); let mut obj = obj.clone();
// Set the value at the path // 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 // Add the object to the results
self.results.push(obj); self.results.push(obj);
} }
@ -171,7 +177,7 @@ impl Iterator {
// Make a copy of object // Make a copy of object
let mut obj = obj.clone(); let mut obj = obj.clone();
// Set the value at the path // 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 // Add the object to the results
self.results.push(obj); self.results.push(obj);
} }
@ -187,6 +193,7 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(fields) = stm.expr() { if let Some(fields) = stm.expr() {
@ -234,20 +241,21 @@ impl Iterator {
.unwrap_or_else(|| Cow::Owned(expr.to_idiom())); .unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
match expr { match expr {
Value::Function(f) if f.is_aggregate() => { Value::Function(f) if f.is_aggregate() => {
let x = vals.all().get(ctx, opt, idiom.as_ref()).await?; let x =
let x = f.aggregate(x).compute(ctx, opt).await?; vals.all().get(ctx, opt, txn, None, idiom.as_ref()).await?;
obj.set(ctx, opt, idiom.as_ref(), x).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 x = vals.first();
let mut child_ctx = Context::new(ctx);
child_ctx.add_cursor_doc(&x);
let x = if let Some(alias) = alias { 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 { } 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, &mut self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(orders) = stm.order() { if let Some(orders) = stm.order() {
@ -303,6 +312,7 @@ impl Iterator {
&mut self, &mut self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(v) = self.start { if let Some(v) = self.start {
@ -316,6 +326,7 @@ impl Iterator {
&mut self, &mut self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(v) = self.limit { if let Some(v) = self.limit {
@ -329,6 +340,7 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(fetchs) = stm.fetch() { if let Some(fetchs) = stm.fetch() {
@ -336,7 +348,7 @@ impl Iterator {
// Loop over each result value // Loop over each result value
for obj in &mut self.results { for obj in &mut self.results {
// Fetch the value at the path // 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, &mut self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Option<Value>, Error> { ) -> Result<Option<Value>, Error> {
Ok(if stm.explain() { Ok(if stm.explain() {
@ -405,13 +418,14 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Prevent deep recursion // Prevent deep recursion
let opt = &opt.dive(4)?; let opt = &opt.dive(4)?;
// Process all prepared values // Process all prepared values
for v in mem::take(&mut self.entries) { 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 // Everything processed ok
Ok(()) Ok(())
@ -423,6 +437,7 @@ impl Iterator {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Prevent deep recursion // Prevent deep recursion
@ -433,7 +448,7 @@ impl Iterator {
false => { false => {
// Process all prepared values // Process all prepared values
for v in mem::take(&mut self.entries) { 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 // Everything processed ok
Ok(()) Ok(())
@ -452,7 +467,7 @@ impl Iterator {
let adocs = async { let adocs = async {
// Process all prepared values // Process all prepared values
for v in vals { 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 // Ensure we detach the spawned task
.detach(); .detach();
} }
@ -464,8 +479,8 @@ impl Iterator {
// Create an async closure for received values // Create an async closure for received values
let avals = async { let avals = async {
// Process all received values // Process all received values
while let Ok((k, v)) = docs.recv().await { while let Ok((k, d, v)) = docs.recv().await {
e.spawn(Document::compute(ctx, opt, stm, chn.clone(), k, v)) e.spawn(Document::compute(ctx, opt, txn, stm, chn.clone(), k, d, v))
// Ensure we detach the spawned task // Ensure we detach the spawned task
.detach(); .detach();
} }
@ -494,11 +509,15 @@ impl Iterator {
} }
/// Process a new record Thing and Value /// Process a new record Thing and Value
#[allow(clippy::too_many_arguments)]
pub async fn process( pub async fn process(
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
thg: Option<Thing>,
doc_id: Option<DocId>,
val: Operable, val: Operable,
) { ) {
// Check current context // Check current context
@ -512,15 +531,15 @@ impl Iterator {
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)), Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
}; };
// Setup a new document // 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 // Process the document
let res = match stm { let res = match stm {
Statement::Select(_) => doc.select(ctx, opt, stm).await, Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
Statement::Create(_) => doc.create(ctx, opt, stm).await, Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
Statement::Update(_) => doc.update(ctx, opt, stm).await, Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
Statement::Relate(_) => doc.relate(ctx, opt, stm).await, Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
Statement::Delete(_) => doc.delete(ctx, opt, stm).await, Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
Statement::Insert(_) => doc.insert(ctx, opt, stm).await, Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
_ => unreachable!(), _ => unreachable!(),
}; };
// Process the result // Process the result

View file

@ -4,7 +4,6 @@
//! and executors to process the operations. This module also gives a `context` to the transaction. //! and executors to process the operations. This module also gives a `context` to the transaction.
mod auth; mod auth;
mod executor; mod executor;
mod iterate;
mod iterator; mod iterator;
mod notification; mod notification;
mod options; mod options;
@ -26,13 +25,8 @@ pub(crate) use self::statement::*;
pub(crate) use self::transaction::*; pub(crate) use self::transaction::*;
pub(crate) use self::variables::*; pub(crate) use self::variables::*;
#[cfg(not(target_arch = "wasm32"))]
mod channel;
#[cfg(not(target_arch = "wasm32"))]
pub use self::channel::*;
pub mod cl; pub mod cl;
mod processor;
#[cfg(test)] #[cfg(test)]
pub(crate) mod test; pub(crate) mod test;

View file

@ -1,17 +1,13 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable; use crate::dbs::{Iterable, Iterator, Operable, Options, Statement, Transaction};
use crate::dbs::Iterator;
use crate::dbs::Operable;
use crate::dbs::Options;
use crate::dbs::Statement;
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::docids::DocId;
use crate::idx::planner::plan::Plan; use crate::idx::planner::plan::Plan;
use crate::key::graph; use crate::key::{graph, thing};
use crate::key::thing;
use crate::sql::dir::Dir; use crate::sql::dir::Dir;
use crate::sql::thing::Thing; use crate::sql::{Edges, Range, Table, Thing, Value};
use crate::sql::value::Value; #[cfg(not(target_arch = "wasm32"))]
use crate::sql::{Edges, Range, Table}; use channel::Sender;
use std::ops::Bound; use std::ops::Bound;
impl Iterable { impl Iterable {
@ -19,50 +15,105 @@ impl Iterable {
self, self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
ite: &mut Iterator, 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<Thing>, Option<DocId>, 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<Thing>, Option<DocId>, 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<Thing>,
doc_id: Option<DocId>,
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> { ) -> Result<(), Error> {
if ctx.is_ok() { if ctx.is_ok() {
match self { match iterable {
Iterable::Value(v) => Self::iterate_value(ctx, opt, stm, v, ite).await, Iterable::Value(v) => self.process_value(ctx, opt, txn, stm, v).await?,
Iterable::Thing(v) => Self::iterate_thing(ctx, opt, stm, v, ite).await?, Iterable::Thing(v) => self.process_thing(ctx, opt, txn, stm, v).await?,
Iterable::Table(v) => Self::iterate_table(ctx, opt, stm, v, ite).await?, Iterable::Table(v) => self.process_table(ctx, opt, txn, stm, v).await?,
Iterable::Range(v) => Self::iterate_range(ctx, opt, stm, v, ite).await?, Iterable::Range(v) => self.process_range(ctx, opt, txn, stm, v).await?,
Iterable::Edges(e) => Self::iterate_edge(ctx, opt, stm, e, ite).await?, Iterable::Edges(e) => self.process_edge(ctx, opt, txn, stm, e).await?,
Iterable::Index(t, p) => Self::iterate_index(ctx, opt, stm, t, p, ite).await?, Iterable::Index(t, p) => self.process_index(ctx, opt, txn, stm, t, p).await?,
Iterable::Mergeable(v, o) => { 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) => { 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(()) Ok(())
} }
async fn iterate_value( async fn process_value(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
v: Value, v: Value,
ite: &mut Iterator, ) -> Result<(), Error> {
) {
// Pass the value through // Pass the value through
let val = Operable::Value(v); let val = Operable::Value(v);
// Process the document record // 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<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
v: Thing, v: Thing,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store // Fetch the data from the store
@ -73,25 +124,21 @@ impl Iterable {
Some(v) => Value::from(v), Some(v) => Value::from(v),
None => Value::None, None => Value::None,
}); });
// Get the optional query executor
let mut child_ctx = Context::new(ctx);
child_ctx.add_thing(&v);
// Process the document record // 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 // Everything ok
Ok(()) Ok(())
} }
async fn iterate_mergeable( async fn process_mergeable(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
v: Thing, v: Thing,
o: Value, o: Value,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store // Fetch the data from the store
@ -104,26 +151,23 @@ impl Iterable {
}; };
// Create a new operable value // Create a new operable value
let val = Operable::Mergeable(x, o); 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 // 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 // Everything ok
Ok(()) Ok(())
} }
async fn iterate_relatable( #[allow(clippy::too_many_arguments)]
async fn process_relatable(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
f: Thing, f: Thing,
v: Thing, v: Thing,
w: Thing, w: Thing,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Fetch the data from the store // Fetch the data from the store
@ -136,24 +180,20 @@ impl Iterable {
}; };
// Create a new operable value // Create a new operable value
let val = Operable::Relatable(f, x, w); 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 // 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 // Everything ok
Ok(()) Ok(())
} }
async fn iterate_table( async fn process_table(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
v: Table, v: Table,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
// Prepare the start and end keys // Prepare the start and end keys
@ -201,10 +241,8 @@ impl Iterable {
let rid = Thing::from((key.tb, key.id)); let rid = Thing::from((key.tb, key.id));
// Create a new operable value // Create a new operable value
let val = Operable::Value(val); let val = Operable::Value(val);
let mut child_ctx = Context::new(ctx);
child_ctx.add_thing(&rid);
// Process the record // Process the record
ite.process(&child_ctx, opt, stm, val).await; self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
} }
continue; continue;
} }
@ -214,15 +252,14 @@ impl Iterable {
Ok(()) Ok(())
} }
async fn iterate_range( async fn process_range(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
v: Range, v: Range,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
// Prepare the range start key // Prepare the range start key
@ -285,12 +322,10 @@ impl Iterable {
let key: crate::key::thing::Thing = (&k).into(); let key: crate::key::thing::Thing = (&k).into();
let val: crate::sql::value::Value = (&v).into(); let val: crate::sql::value::Value = (&v).into();
let rid = Thing::from((key.tb, key.id)); let rid = Thing::from((key.tb, key.id));
let mut ctx = Context::new(ctx);
ctx.add_thing(&rid);
// Create a new operable value // Create a new operable value
let val = Operable::Value(val); let val = Operable::Value(val);
// Process the record // Process the record
ite.process(&ctx, opt, stm, val).await; self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
} }
continue; continue;
} }
@ -300,12 +335,13 @@ impl Iterable {
Ok(()) Ok(())
} }
async fn iterate_edge( async fn process_edge(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
e: Edges, e: Edges,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Pull out options // Pull out options
let ns = opt.ns(); let ns = opt.ns();
@ -390,13 +426,13 @@ impl Iterable {
None => { None => {
let min = beg.clone(); let min = beg.clone();
let max = end.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) => { Some(ref mut beg) => {
beg.push(0x00); beg.push(0x00);
let min = beg.clone(); let min = beg.clone();
let max = end.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 // If there are key-value entries then fetch them
@ -421,17 +457,15 @@ impl Iterable {
let gra: crate::key::graph::Graph = (&k).into(); let gra: crate::key::graph::Graph = (&k).into();
// Fetch the data from the store // Fetch the data from the store
let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk); 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 rid = Thing::from((gra.ft, gra.fk));
let mut ctx = Context::new(ctx);
ctx.add_thing(&rid);
// Parse the data from the store // Parse the data from the store
let val = Operable::Value(match val { let val = Operable::Value(match val {
Some(v) => Value::from(v), Some(v) => Value::from(v),
None => Value::None, None => Value::None,
}); });
// Process the record // Process the record
ite.process(&ctx, opt, stm, val).await; self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
} }
continue; continue;
} }
@ -442,22 +476,21 @@ impl Iterable {
Ok(()) Ok(())
} }
async fn iterate_index( async fn process_index(
&mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
table: Table, table: Table,
plan: Plan, plan: Plan,
ite: &mut Iterator,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check that the table exists // Check that the table exists
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?; txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?;
let exe = ctx.get_query_executor(&table.0); let exe = ctx.get_query_executor(&table.0);
if let Some(exe) = exe { if let Some(exe) = exe {
let mut iterator = plan.new_iterator(opt, &txn, exe).await?; let mut iterator = plan.new_iterator(opt, txn, exe).await?;
let mut things = iterator.next_batch(&txn, 1000).await?; let mut things = iterator.next_batch(txn, 1000).await?;
while !things.is_empty() { while !things.is_empty() {
// Check if the context is finished // Check if the context is finished
if ctx.is_done() { if ctx.is_done() {
@ -479,20 +512,17 @@ impl Iterable {
let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id); let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id);
let val = txn.lock().await.get(key.clone()).await?; let val = txn.lock().await.get(key.clone()).await?;
let rid = Thing::from((key.tb, key.id)); 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 // Parse the data from the store
let val = Operable::Value(match val { let val = Operable::Value(match val {
Some(v) => Value::from(v), Some(v) => Value::from(v),
None => Value::None, None => Value::None,
}); });
// Process the document record // 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 // Collect the next batch of ids
things = iterator.next_batch(&txn, 1000).await?; things = iterator.next_batch(txn, 1000).await?;
} }
// Everything ok // Everything ok
Ok(()) Ok(())

View file

@ -1,15 +1,14 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::{Auth, Options}; use crate::dbs::{Auth, Options, Transaction};
use crate::kvs::Datastore; use crate::kvs::Datastore;
use futures::lock::Mutex; use futures::lock::Mutex;
use std::sync::Arc; use std::sync::Arc;
pub async fn mock<'a>() -> (Context<'a>, Options) { pub async fn mock<'a>() -> (Context<'a>, Options, Transaction) {
let mut ctx = Context::default(); let ctx = Context::default();
let opt = Options::default().with_auth(Arc::new(Auth::Kv)); let opt = Options::default().with_auth(Arc::new(Auth::Kv));
let kvs = Datastore::new("memory").await.unwrap(); let kvs = Datastore::new("memory").await.unwrap();
let txn = kvs.transaction(true, false).await.unwrap(); let txn = kvs.transaction(true, false).await.unwrap();
let txn = Arc::new(Mutex::new(txn)); let txn = Arc::new(Mutex::new(txn));
ctx.add_transaction(Some(&txn)); (ctx, opt, txn)
(ctx, opt)
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::permission::Permission; use crate::sql::permission::Permission;
@ -10,16 +10,15 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if this record exists // Check if this record exists
if self.id.is_some() { if self.id.is_some() {
// Should we run permissions checks? // Should we run permissions checks?
if opt.perms && opt.auth.perms() { if opt.perms && opt.auth.perms() {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Get the table // Get the table
let tb = self.tb(opt, &txn).await?; let tb = self.tb(opt, txn).await?;
// Get the permission clause // Get the permission clause
let perms = if stm.is_delete() { let perms = if stm.is_delete() {
&tb.permissions.delete &tb.permissions.delete
@ -37,10 +36,8 @@ impl<'a> Document<'a> {
Permission::Specific(e) => { Permission::Specific(e) => {
// Disable permissions // Disable permissions
let opt = &opt.new_with_perms(false); let opt = &opt.new_with_perms(false);
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(&self.current);
// Process the PERMISSION clause // 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); return Err(Error::Ignore);
} }
} }

View file

@ -1,7 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::data::Data; use crate::sql::data::Data;
@ -13,57 +13,50 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Set default field values // Set default field values
self.current.to_mut().def(rid); self.current.doc.to_mut().def(rid);
// The statement has a data clause // The statement has a data clause
if let Some(v) = stm.data() { if let Some(v) = stm.data() {
match v { match v {
Data::PatchExpression(data) => { Data::PatchExpression(data) => {
let mut current_ctx = Context::new(ctx); let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current); self.current.doc.to_mut().patch(data)?
let data = data.compute(&current_ctx, opt).await?;
self.current.to_mut().patch(data)?
} }
Data::MergeExpression(data) => { Data::MergeExpression(data) => {
let mut current_ctx = Context::new(ctx); let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current); self.current.doc.to_mut().merge(data)?
let data = data.compute(&current_ctx, opt).await?;
self.current.to_mut().merge(data)?
} }
Data::ReplaceExpression(data) => { Data::ReplaceExpression(data) => {
let mut current_ctx = Context::new(ctx); let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current); self.current.doc.to_mut().replace(data)?
let data = data.compute(&current_ctx, opt).await?;
self.current.to_mut().replace(data)?
} }
Data::ContentExpression(data) => { Data::ContentExpression(data) => {
let mut current_ctx = Context::new(ctx); let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current); self.current.doc.to_mut().replace(data)?
let data = data.compute(&current_ctx, opt).await?;
self.current.to_mut().replace(data)?
} }
Data::SetExpression(x) => { Data::SetExpression(x) => {
for x in x.iter() { for x in x.iter() {
let mut current_ctx = Context::new(ctx); let v = x.2.compute(ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current);
let v = x.2.compute(&current_ctx, opt).await?;
match x.1 { match x.1 {
Operator::Equal => match v { Operator::Equal => match v {
Value::None => self.current.to_mut().del(ctx, opt, &x.0).await?, Value::None => {
_ => self.current.to_mut().set(ctx, opt, &x.0, v).await?, 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 => { 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 => { 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 => { 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!(), _ => unreachable!(),
} }
@ -71,7 +64,7 @@ impl<'a> Document<'a> {
} }
Data::UnsetExpression(i) => { Data::UnsetExpression(i) => {
for i in i.iter() { 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) => { Data::UpdateExpression(x) => {
@ -83,22 +76,22 @@ impl<'a> Document<'a> {
} }
// Process ON DUPLICATE KEY clause // Process ON DUPLICATE KEY clause
for x in x.iter() { for x in x.iter() {
let mut current_ctx = Context::new(&ctx); let v = x.2.compute(&ctx, opt, txn, Some(&self.current)).await?;
current_ctx.add_cursor_doc(&self.current);
let v = x.2.compute(&current_ctx, opt).await?;
match x.1 { match x.1 {
Operator::Equal => match v { Operator::Equal => match v {
Value::None => self.current.to_mut().del(&ctx, opt, &x.0).await?, Value::None => {
_ => self.current.to_mut().set(&ctx, opt, &x.0, v).await?, 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 => { 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 => { 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 => { 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!(), _ => unreachable!(),
} }
@ -108,7 +101,7 @@ impl<'a> Document<'a> {
}; };
}; };
// Set default field values // Set default field values
self.current.to_mut().def(rid); self.current.doc.to_mut().def(rid);
// Carry on // Carry on
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
@ -9,14 +9,13 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check where condition // Check where condition
if let Some(cond) = stm.conds() { if let Some(cond) = stm.conds() {
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(&self.current);
// Check if the expression is truthy // 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 // Ignore this document
return Err(Error::Ignore); return Err(Error::Ignore);
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::idiom::Idiom; use crate::sql::idiom::Idiom;
@ -10,43 +10,42 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Get the table // Get the table
let tb = self.tb(opt, &txn).await?; let tb = self.tb(opt, txn).await?;
// This table is schemafull // This table is schemafull
if tb.full { if tb.full {
// Create a vector to store the keys // Create a vector to store the keys
let mut keys: Vec<Idiom> = vec![]; let mut keys: Vec<Idiom> = vec![];
// Loop through all field statements // 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? // Is this a schemaless field?
match fd.flex { match fd.flex {
false => { false => {
// Loop over this field in the document // 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); keys.push(k);
} }
} }
true => { true => {
// Loop over every field under this field in the document // 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); keys.push(k);
} }
} }
} }
} }
// Loop over every field in the document // 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) { if !keys.contains(fd) {
match fd { match fd {
fd if fd.is_id() => continue, fd if fd.is_id() => continue,
fd if fd.is_in() => continue, fd if fd.is_in() => continue,
fd if fd.is_out() => continue, fd if fd.is_out() => continue,
fd if fd.is_meta() => 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?,
} }
} }
} }

View file

@ -1,28 +1,28 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Operable;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::dbs::{Operable, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::docids::DocId;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
use crate::sql::value::Value; use crate::sql::value::Value;
use channel::Sender; use channel::Sender;
impl<'a> Document<'a> { impl<'a> Document<'a> {
#[allow(dead_code)] #[allow(dead_code)]
#[allow(clippy::too_many_arguments)]
pub(crate) async fn compute( pub(crate) async fn compute(
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
chn: Sender<Result<Value, Error>>, chn: Sender<Result<Value, Error>>,
thg: Option<Thing>, thg: Option<Thing>,
doc_id: Option<DocId>,
val: Operable, val: Operable,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut ctx = Context::new(ctx);
if let Some(t) = &thg {
ctx.add_thing(t);
}
// Setup a new workable // Setup a new workable
let ins = match val { let ins = match val {
Operable::Value(v) => (v, Workable::Normal), Operable::Value(v) => (v, Workable::Normal),
@ -30,15 +30,15 @@ impl<'a> Document<'a> {
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)), Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
}; };
// Setup a new document // 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 // Process the statement
let res = match stm { let res = match stm {
Statement::Select(_) => doc.select(&ctx, opt, stm).await, Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
Statement::Create(_) => doc.create(&ctx, opt, stm).await, Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
Statement::Update(_) => doc.update(&ctx, opt, stm).await, Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
Statement::Relate(_) => doc.relate(&ctx, opt, stm).await, Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
Statement::Delete(_) => doc.delete(&ctx, opt, stm).await, Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
Statement::Insert(_) => doc.insert(&ctx, opt, stm).await, Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
_ => unreachable!(), _ => unreachable!(),
}; };
// Send back the result // Send back the result

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,31 +10,32 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check if exists // Check if exists
self.exist(ctx, opt, stm).await?; self.exist(ctx, opt, txn, stm).await?;
// Alter record data // Alter record data
self.alter(ctx, opt, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data // Reset fields data
self.reset(ctx, opt, stm).await?; self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Store index data // Store index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Store record data // Store record data
self.store(ctx, opt, stm).await?; self.store(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,25 +10,26 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check where clause // Check where clause
self.check(ctx, opt, stm).await?; self.check(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Erase document // Erase document
self.erase(ctx, opt, stm).await?; self.erase(ctx, opt, stm).await?;
// Purge index data // Purge index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Purge record data // Purge record data
self.purge(ctx, opt, stm).await?; self.purge(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }

View file

@ -3,6 +3,7 @@ use crate::dbs::Options;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::docids::DocId;
use crate::sql::statements::define::DefineEventStatement; use crate::sql::statements::define::DefineEventStatement;
use crate::sql::statements::define::DefineFieldStatement; use crate::sql::statements::define::DefineFieldStatement;
use crate::sql::statements::define::DefineIndexStatement; use crate::sql::statements::define::DefineIndexStatement;
@ -17,8 +18,24 @@ use std::sync::Arc;
pub(crate) struct Document<'a> { pub(crate) struct Document<'a> {
pub(super) id: Option<&'a Thing>, pub(super) id: Option<&'a Thing>,
pub(super) extras: Workable, pub(super) extras: Workable,
pub(super) current: Cow<'a, Value>, pub(super) initial: CursorDoc<'a>,
pub(super) initial: Cow<'a, Value>, 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<DocId>,
}
impl<'a> CursorDoc<'a> {
pub(crate) fn new(rid: Option<&'a Thing>, doc_id: Option<DocId>, doc: &'a Value) -> Self {
Self {
rid,
doc: Cow::Borrowed(doc),
doc_id,
}
}
} }
impl<'a> Debug for Document<'a> { impl<'a> Debug for Document<'a> {
@ -29,17 +46,22 @@ impl<'a> Debug for Document<'a> {
impl<'a> From<&Document<'a>> for Vec<u8> { impl<'a> From<&Document<'a>> for Vec<u8> {
fn from(val: &Document<'a>) -> Vec<u8> { fn from(val: &Document<'a>) -> Vec<u8> {
val.current.as_ref().into() val.current.doc.as_ref().into()
} }
} }
impl<'a> Document<'a> { 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<DocId>,
val: &'a Value,
extras: Workable,
) -> Self {
Document { Document {
id, id,
extras: ext, extras,
current: Cow::Borrowed(val), current: CursorDoc::new(id, doc_id, val),
initial: Cow::Borrowed(val), initial: CursorDoc::new(id, doc_id, val),
} }
} }
} }
@ -47,11 +69,11 @@ impl<'a> Document<'a> {
impl<'a> Document<'a> { impl<'a> Document<'a> {
/// Check if document has changed /// Check if document has changed
pub fn changed(&self) -> bool { pub fn changed(&self) -> bool {
self.initial != self.current self.initial.doc != self.current.doc
} }
/// Check if document has changed /// Check if document has changed
pub fn is_new(&self) -> bool { pub fn is_new(&self) -> bool {
self.initial.is_none() self.initial.doc.is_none()
} }
/// Get the table for this document /// Get the table for this document
pub async fn tb( pub async fn tb(

View file

@ -1,7 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::paths::EDGE; use crate::sql::paths::EDGE;
@ -13,14 +13,13 @@ use crate::sql::Dir;
impl<'a> Document<'a> { impl<'a> Document<'a> {
pub async fn edges( pub async fn edges(
&mut self, &mut self,
ctx: &Context<'_>, _ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check if the table is a view // Check if the table is a view
if self.tb(opt, &txn).await?.drop { if self.tb(opt, txn).await?.drop {
return Ok(()); return Ok(());
} }
// Claim transaction // 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); let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
run.set(key, vec![]).await?; run.set(key, vec![]).await?;
// Store the edges on the record // Store the edges on the record
self.current.to_mut().put(&*EDGE, Value::Bool(true)); self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
self.current.to_mut().put(&*IN, l.clone().into()); self.current.doc.to_mut().put(&*IN, l.clone().into());
self.current.to_mut().put(&*OUT, r.clone().into()); self.current.doc.to_mut().put(&*OUT, r.clone().into());
} }
// Carry on // Carry on
Ok(()) Ok(())

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Transaction;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
@ -9,12 +10,13 @@ impl<'a> Document<'a> {
&self, &self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if this record exists // Check if this record exists
if self.id.is_some() { if self.id.is_some() {
// There is no current record // There is no current record
if self.current.is_none() { if self.current.doc.is_none() {
// Ignore this requested record // Ignore this requested record
return Err(Error::Ignore); return Err(Error::Ignore);
} }

View file

@ -11,6 +11,6 @@ impl<'a> Document<'a> {
_opt: &Options, _opt: &Options,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.current.to_mut().clear() self.current.doc.to_mut().clear()
} }
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check events // Check events
@ -23,10 +24,8 @@ impl<'a> Document<'a> {
} }
// Don't run permissions // Don't run permissions
let opt = &opt.new_with_perms(false); let opt = &opt.new_with_perms(false);
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Loop through all event statements // 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 // Get the event action
let met = if stm.is_delete() { let met = if stm.is_delete() {
Value::from("DELETE") Value::from("DELETE")
@ -38,16 +37,15 @@ impl<'a> Document<'a> {
// Configure the context // Configure the context
let mut ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
ctx.add_value("event", met); ctx.add_value("event", met);
ctx.add_value("value", self.current.deref()); ctx.add_value("value", self.current.doc.deref());
ctx.add_value("after", self.current.deref()); ctx.add_value("after", self.current.doc.deref());
ctx.add_value("before", self.initial.deref()); ctx.add_value("before", self.initial.doc.deref());
ctx.add_cursor_doc(&self.current);
// Process conditional clause // 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 // Execute event if value is truthy
if val.is_truthy() { if val.is_truthy() {
for v in ev.then.iter() { for v in ev.then.iter() {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, Some(&self.current)).await?;
} }
} }
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
@ -9,12 +9,13 @@ impl<'a> Document<'a> {
&self, &self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if this record exists // Check if this record exists
if let Some(id) = &self.id { if let Some(id) = &self.id {
// If there is a current value // If there is a current value
if self.current.is_some() { if self.current.doc.is_some() {
// The record already exists // The record already exists
return Err(Error::RecordExists { return Err(Error::RecordExists {
thing: id.to_string(), thing: id.to_string(),

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::permission::Permission; use crate::sql::permission::Permission;
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check fields // Check fields
@ -20,15 +21,13 @@ impl<'a> Document<'a> {
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Get the user applied input // Get the user applied input
let inp = self.initial.changed(self.current.as_ref()); let inp = self.initial.doc.changed(self.current.doc.as_ref());
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Loop through all field statements // 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 // 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 // Get the initial value
let old = self.initial.pick(&k); let old = self.initial.doc.pick(&k);
// Get the input value // Get the input value
let inp = inp.pick(&k); let inp = inp.pick(&k);
// Check for a TYPE clause // Check for a TYPE clause
@ -58,9 +57,8 @@ impl<'a> Document<'a> {
ctx.add_value("value", &val); ctx.add_value("value", &val);
ctx.add_value("after", &val); ctx.add_value("after", &val);
ctx.add_value("before", &old); ctx.add_value("before", &old);
ctx.add_cursor_doc(&self.current);
// Process the VALUE clause // 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 // Check for a TYPE clause
if let Some(kind) = &fd.kind { if let Some(kind) = &fd.kind {
@ -87,9 +85,8 @@ impl<'a> Document<'a> {
ctx.add_value("value", &val); ctx.add_value("value", &val);
ctx.add_value("after", &val); ctx.add_value("after", &val);
ctx.add_value("before", &old); ctx.add_value("before", &old);
ctx.add_cursor_doc(&self.current);
// Process the ASSERT clause // 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 { return Err(Error::FieldValue {
thing: rid.to_string(), thing: rid.to_string(),
field: fd.name.clone(), field: fd.name.clone(),
@ -119,9 +116,8 @@ impl<'a> Document<'a> {
ctx.add_value("value", &val); ctx.add_value("value", &val);
ctx.add_value("after", &val); ctx.add_value("after", &val);
ctx.add_value("before", &old); ctx.add_value("before", &old);
ctx.add_cursor_doc(&self.current);
// Process the PERMISSION clause // 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 val = old
} }
} }
@ -129,8 +125,8 @@ impl<'a> Document<'a> {
} }
// Set the value of the field // Set the value of the field
match val { match val {
Value::None => self.current.to_mut().del(ctx, opt, &k).await?, Value::None => self.current.doc.to_mut().del(ctx, opt, txn, &k).await?,
_ => self.current.to_mut().set(ctx, opt, &k, val).await?, _ => self.current.doc.to_mut().set(ctx, opt, txn, &k, val).await?,
}; };
} }
} }

View file

@ -1,7 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::doc::Document; use crate::dbs::{Options, Transaction};
use crate::doc::{CursorDoc, Document};
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::FtIndex; use crate::idx::ft::FtIndex;
use crate::idx::IndexKeyBase; use crate::idx::IndexKeyBase;
@ -9,7 +9,7 @@ use crate::sql::array::Array;
use crate::sql::index::Index; use crate::sql::index::Index;
use crate::sql::scoring::Scoring; use crate::sql::scoring::Scoring;
use crate::sql::statements::DefineIndexStatement; use crate::sql::statements::DefineIndexStatement;
use crate::sql::{Ident, Thing, Value}; use crate::sql::{Ident, Thing};
use crate::{key, kvs}; use crate::{key, kvs};
impl<'a> Document<'a> { impl<'a> Document<'a> {
@ -17,6 +17,7 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check indexes // Check indexes
@ -27,21 +28,19 @@ impl<'a> Document<'a> {
if !opt.force && !self.changed() { if !opt.force && !self.changed() {
return Ok(()); return Ok(());
} }
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check if the table is a view // Check if the table is a view
if self.tb(opt, &txn).await?.drop { if self.tb(opt, txn).await?.drop {
return Ok(()); return Ok(());
} }
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Loop through all index statements // 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 // 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 // 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 // Update the index entries
if opt.force || o != n { if opt.force || o != n {
@ -75,17 +74,16 @@ impl<'a> Document<'a> {
async fn build_opt_array( async fn build_opt_array(
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
ix: &DefineIndexStatement, ix: &DefineIndexStatement,
value: &Value, doc: &CursorDoc<'_>,
) -> Result<Option<Array>, Error> { ) -> Result<Option<Array>, Error> {
if !value.is_some() { if !doc.doc.is_some() {
return Ok(None); return Ok(None);
} }
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(value);
let mut o = Array::with_capacity(ix.cols.len()); let mut o = Array::with_capacity(ix.cols.len());
for i in ix.cols.iter() { 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); o.push(v);
} }
Ok(Some(o)) Ok(Some(o))

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,63 +10,64 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check current record // Check current record
match self.current.is_some() { match self.current.doc.is_some() {
// Run INSERT clause // Run INSERT clause
false => { false => {
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Merge record data // Merge record data
self.merge(ctx, opt, stm).await?; self.merge(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data // Reset fields data
self.reset(ctx, opt, stm).await?; self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Store index data // Store index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Store record data // Store record data
self.store(ctx, opt, stm).await?; self.store(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
// Run UPDATE clause // Run UPDATE clause
true => { true => {
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Alter record data // Alter record data
self.alter(ctx, opt, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data // Reset fields data
self.reset(ctx, opt, stm).await?; self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Store index data // Store index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Store record data // Store record data
self.store(ctx, opt, stm).await?; self.store(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }
} }

View file

@ -1,8 +1,8 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Action;
use crate::dbs::Notification; use crate::dbs::Notification;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Action, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::Value; use crate::sql::Value;
@ -12,14 +12,13 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if forced // Check if forced
if !opt.force && !self.changed() { if !opt.force && !self.changed() {
return Ok(()); return Ok(());
} }
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Check if we can send notifications // Check if we can send notifications
@ -27,11 +26,11 @@ impl<'a> Document<'a> {
// Clone the sending channel // Clone the sending channel
let chn = chn.clone(); let chn = chn.clone();
// Loop through all index statements // 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 // Create a new statement
let lq = Statement::from(lv); let lq = Statement::from(lv);
// Check LIVE SELECT where condition // 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; continue;
} }
// Check what type of data change this is // Check what type of data change this is
@ -54,7 +53,7 @@ impl<'a> Document<'a> {
chn.send(Notification { chn.send(Notification {
id: lv.id.0, id: lv.id.0,
action: Action::Create, action: Action::Create,
result: self.pluck(ctx, opt, &lq).await?, result: self.pluck(ctx, opt, txn, &lq).await?,
}) })
.await?; .await?;
} else { } else {
@ -66,7 +65,7 @@ impl<'a> Document<'a> {
chn.send(Notification { chn.send(Notification {
id: lv.id.0, id: lv.id.0,
action: Action::Update, action: Action::Update,
result: self.pluck(ctx, opt, &lq).await?, result: self.pluck(ctx, opt, txn, &lq).await?,
}) })
.await?; .await?;
} else { } else {

View file

@ -1,7 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
@ -10,21 +10,20 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Set default field values // Set default field values
self.current.to_mut().def(rid); self.current.doc.to_mut().def(rid);
// This is an INSERT statement // This is an INSERT statement
if let Workable::Insert(v) = &self.extras { if let Workable::Insert(v) = &self.extras {
let mut ctx = Context::new(ctx); let v = v.compute(ctx, opt, txn, Some(&self.current)).await?;
ctx.add_cursor_doc(&self.current); self.current.doc.to_mut().merge(v)?;
let v = v.compute(&ctx, opt).await?;
self.current.to_mut().merge(v)?;
} }
// Set default field values // Set default field values
self.current.to_mut().def(rid); self.current.doc.to_mut().def(rid);
// Carry on // Carry on
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::idiom::Idiom; use crate::sql::idiom::Idiom;
@ -14,6 +14,7 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Ensure futures are run // Ensure futures are run
@ -23,56 +24,34 @@ impl<'a> Document<'a> {
Some(v) => match v { Some(v) => match v {
Output::None => Err(Error::Ignore), Output::None => Err(Error::Ignore),
Output::Null => Ok(Value::Null), Output::Null => Ok(Value::Null),
Output::Diff => Ok(self.initial.diff(&self.current, Idiom::default()).into()), Output::Diff => {
Output::After => { Ok(self.initial.doc.diff(self.current.doc.as_ref(), Idiom::default()).into())
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(&self.current);
self.current.compute(&ctx, opt).await
} }
Output::After => self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await,
Output::Before => { Output::Before => {
let mut ctx = Context::new(ctx); self.initial.doc.compute(ctx, opt, txn, Some(&self.initial)).await
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
} }
Output::Fields(v) => v.compute(ctx, opt, txn, Some(&self.current), false).await,
}, },
None => match stm { None => match stm {
Statement::Live(s) => match s.expr.len() { Statement::Live(s) => match s.expr.len() {
0 => Ok(self.initial.diff(&self.current, Idiom::default()).into()), 0 => Ok(self.initial.doc.diff(&self.current.doc, Idiom::default()).into()),
_ => { _ => s.expr.compute(ctx, opt, txn, Some(&self.current), false).await,
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(&self.current);
s.expr.compute(&ctx, opt, false).await
}
}, },
Statement::Select(s) => { Statement::Select(s) => {
let mut ctx = Context::new(ctx); s.expr.compute(ctx, opt, txn, Some(&self.current), s.group.is_some()).await
ctx.add_cursor_doc(&self.current);
s.expr.compute(&ctx, opt, s.group.is_some()).await
} }
Statement::Create(_) => { Statement::Create(_) => {
let mut ctx = Context::new(ctx); self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
ctx.add_cursor_doc(&self.current);
self.current.compute(&ctx, opt).await
} }
Statement::Update(_) => { Statement::Update(_) => {
let mut ctx = Context::new(ctx); self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
ctx.add_cursor_doc(&self.current);
self.current.compute(&ctx, opt).await
} }
Statement::Relate(_) => { Statement::Relate(_) => {
let mut ctx = Context::new(ctx); self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
ctx.add_cursor_doc(&self.current);
self.current.compute(&ctx, opt).await
} }
Statement::Insert(_) => { Statement::Insert(_) => {
let mut ctx = Context::new(ctx); self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
ctx.add_cursor_doc(&self.current);
self.current.compute(&ctx, opt).await
} }
_ => Err(Error::Ignore), _ => Err(Error::Ignore),
}, },
@ -81,28 +60,29 @@ impl<'a> Document<'a> {
if self.id.is_some() { if self.id.is_some() {
// Should we run permissions checks? // Should we run permissions checks?
if opt.perms && opt.auth.perms() { if opt.perms && opt.auth.perms() {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Loop through all field statements // 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 // Loop over each field in document
for k in out.each(&fd.name).iter() { for k in out.each(&fd.name).iter() {
// Process the field permissions // Process the field permissions
match &fd.permissions.select { match &fd.permissions.select {
Permission::Full => (), Permission::Full => (),
Permission::None => out.del(ctx, opt, k).await?, Permission::None => out.del(ctx, opt, txn, k).await?,
Permission::Specific(e) => { Permission::Specific(e) => {
// Disable permissions // Disable permissions
let opt = &opt.new_with_perms(false); let opt = &opt.new_with_perms(false);
// Get the current value // Get the current value
let val = self.current.pick(k); let val = self.current.doc.pick(k);
// Configure the context // Configure the context
let mut ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
ctx.add_value("value", &val); ctx.add_value("value", &val);
ctx.add_cursor_doc(&self.current);
// Process the PERMISSION clause // Process the PERMISSION clause
if !e.compute(&ctx, opt).await?.is_truthy() { if !e
out.del(&ctx, opt, k).await? .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 // Remove metadata fields on output
out.del(ctx, opt, &*META).await?; out.del(ctx, opt, txn, &*META).await?;
// Output result // Output result
Ok(out) Ok(out)
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::dir::Dir; use crate::sql::dir::Dir;
@ -17,16 +17,15 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if forced // Check if forced
if !opt.force && !self.changed() { if !opt.force && !self.changed() {
return Ok(()); return Ok(());
} }
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check if the table is a view // Check if the table is a view
if self.tb(opt, &txn).await?.drop { if self.tb(opt, txn).await?.drop {
return Ok(()); return Ok(());
} }
// Clone transaction // Clone transaction
@ -39,7 +38,11 @@ impl<'a> Document<'a> {
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id); let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
run.del(key).await?; run.del(key).await?;
// Purge the record edges // 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)) => { (Value::Bool(true), Value::Thing(ref l), Value::Thing(ref r)) => {
// Get temporary edge references // Get temporary edge references
let (ref o, ref i) = (Dir::Out, Dir::In); let (ref o, ref i) = (Dir::Out, Dir::In);
@ -69,7 +72,7 @@ impl<'a> Document<'a> {
..DeleteStatement::default() ..DeleteStatement::default()
}; };
// Execute the delete statement // Execute the delete statement
stm.compute(ctx, opt).await?; stm.compute(ctx, opt, txn, None).await?;
} }
} }
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Alter record data // Alter record data
self.alter(ctx, opt, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data // Reset fields data
self.reset(ctx, opt, stm).await?; self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Store record edges // Store record edges
self.edges(ctx, opt, stm).await?; self.edges(ctx, opt, txn, stm).await?;
// Store index data // Store index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Store record data // Store record data
self.store(ctx, opt, stm).await?; self.store(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Transaction;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::paths::EDGE; use crate::sql::paths::EDGE;
@ -13,17 +14,18 @@ impl<'a> Document<'a> {
&mut self, &mut self,
_ctx: &Context<'_>, _ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Get the record id // Get the record id
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Set default field values // Set default field values
self.current.to_mut().def(rid); self.current.doc.to_mut().def(rid);
// Ensure edge fields are reset // Ensure edge fields are reset
if self.initial.pick(&*EDGE).is_true() { if self.initial.doc.pick(&*EDGE).is_true() {
self.current.to_mut().put(&*EDGE, Value::Bool(true)); self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
self.current.to_mut().put(&*IN, self.initial.pick(&*IN)); self.current.doc.to_mut().put(&*IN, self.initial.doc.pick(&*IN));
self.current.to_mut().put(&*OUT, self.initial.pick(&*OUT)); self.current.doc.to_mut().put(&*OUT, self.initial.doc.pick(&*OUT));
} }
// Carry on // Carry on
Ok(()) Ok(())

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,15 +10,16 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check if record exists // Check if record exists
self.empty(ctx, opt, stm).await?; self.empty(ctx, opt, txn, stm).await?;
// Check where clause // Check where clause
self.check(ctx, opt, stm).await?; self.check(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }

View file

@ -1,24 +1,23 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
impl<'a> Document<'a> { impl<'a> Document<'a> {
pub async fn store( pub async fn store(
&self, &self,
ctx: &Context<'_>, _ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check if forced // Check if forced
if !opt.force && !self.changed() { if !opt.force && !self.changed() {
return Ok(()); return Ok(());
} }
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Check if the table is a view // Check if the table is a view
if self.tb(opt, &txn).await?.drop { if self.tb(opt, txn).await?.drop {
return Ok(()); return Ok(());
} }
// Claim transaction // Claim transaction

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::data::Data; use crate::sql::data::Data;
@ -33,6 +33,7 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Check tables // Check tables
@ -55,43 +56,41 @@ impl<'a> Document<'a> {
} else { } else {
Action::Update Action::Update
}; };
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Loop through all foreign table statements // 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 // Get the table definition
let tb = ft.view.as_ref().unwrap(); let tb = ft.view.as_ref().unwrap();
// Check if there is a GROUP BY clause // Check if there is a GROUP BY clause
match &tb.group { match &tb.group {
// There is a GROUP BY clause specified // There is a GROUP BY clause specified
Some(group) => { Some(group) => {
let mut initial_ctx = Context::new(ctx);
initial_ctx.add_cursor_doc(&self.initial);
// Set the previous record id // Set the previous record id
let old = Thing { let old = Thing {
tb: ft.name.to_raw(), tb: ft.name.to_raw(),
id: try_join_all(group.iter().map(|v| v.compute(&initial_ctx, opt))) id: try_join_all(
.await? group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.initial))),
.into_iter() )
.collect::<Vec<_>>() .await?
.into(), .into_iter()
.collect::<Vec<_>>()
.into(),
}; };
let mut current_ctx = Context::new(ctx);
current_ctx.add_cursor_doc(&self.current);
// Set the current record id // Set the current record id
let rid = Thing { let rid = Thing {
tb: ft.name.to_raw(), tb: ft.name.to_raw(),
id: try_join_all(group.iter().map(|v| v.compute(&current_ctx, opt))) id: try_join_all(
.await? group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.current))),
.into_iter() )
.collect::<Vec<_>>() .await?
.into(), .into_iter()
.collect::<Vec<_>>()
.into(),
}; };
// Check if a WHERE clause is specified // Check if a WHERE clause is specified
match &tb.cond { match &tb.cond {
// There is a WHERE clause specified // There is a WHERE clause specified
Some(cond) => { Some(cond) => {
match cond.compute(&current_ctx, opt).await? { match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
v if v.is_truthy() => { v if v.is_truthy() => {
if !opt.force && act != Action::Create { if !opt.force && act != Action::Create {
// Delete the old value // Delete the old value
@ -99,11 +98,13 @@ impl<'a> Document<'a> {
// Modify the value in the table // Modify the value in the table
let stm = UpdateStatement { let stm = UpdateStatement {
what: Values(vec![Value::from(old)]), 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() ..UpdateStatement::default()
}; };
// Execute the statement // Execute the statement
stm.compute(ctx, opt).await?; stm.compute(ctx, opt, txn, None).await?;
} }
if act != Action::Delete { if act != Action::Delete {
// Update the new value // Update the new value
@ -111,11 +112,13 @@ impl<'a> Document<'a> {
// Modify the value in the table // Modify the value in the table
let stm = UpdateStatement { let stm = UpdateStatement {
what: Values(vec![Value::from(rid)]), 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() ..UpdateStatement::default()
}; };
// Execute the statement // 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 // Modify the value in the table
let stm = UpdateStatement { let stm = UpdateStatement {
what: Values(vec![Value::from(old)]), 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() ..UpdateStatement::default()
}; };
// Execute the statement // 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 // Modify the value in the table
let stm = UpdateStatement { let stm = UpdateStatement {
what: Values(vec![Value::from(old)]), 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() ..UpdateStatement::default()
}; };
// Execute the statement // Execute the statement
stm.compute(ctx, opt).await?; stm.compute(ctx, opt, txn, None).await?;
} }
if act != Action::Delete { if act != Action::Delete {
// Update the new value // Update the new value
@ -154,11 +159,11 @@ impl<'a> Document<'a> {
// Modify the value in the table // Modify the value in the table
let stm = UpdateStatement { let stm = UpdateStatement {
what: Values(vec![Value::from(rid)]), 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() ..UpdateStatement::default()
}; };
// Execute the statement // 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(), id: rid.id.clone(),
}; };
// Use the current record data // Use the current record data
let mut ctx = Context::new(ctx);
ctx.add_cursor_doc(&self.current);
// Check if a WHERE clause is specified // Check if a WHERE clause is specified
match &tb.cond { match &tb.cond {
// There is a WHERE clause specified // There is a WHERE clause specified
Some(cond) => { Some(cond) => {
match cond.compute(&ctx, opt).await? { match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
v if v.is_truthy() => { v if v.is_truthy() => {
// Define the statement // Define the statement
let stm = match act { let stm = match act {
@ -190,13 +193,21 @@ impl<'a> Document<'a> {
_ => Query::Update(UpdateStatement { _ => Query::Update(UpdateStatement {
what: Values(vec![Value::from(rid)]), what: Values(vec![Value::from(rid)]),
data: Some(Data::ReplaceExpression( data: Some(Data::ReplaceExpression(
tb.expr.compute(&ctx, opt, false).await?, tb.expr
.compute(
ctx,
opt,
txn,
Some(&self.current),
false,
)
.await?,
)), )),
..UpdateStatement::default() ..UpdateStatement::default()
}), }),
}; };
// Execute the statement // Execute the statement
stm.compute(&ctx, opt).await?; stm.compute(ctx, opt, txn, None).await?;
} }
_ => { _ => {
// Delete the value in the table // Delete the value in the table
@ -205,7 +216,7 @@ impl<'a> Document<'a> {
..DeleteStatement::default() ..DeleteStatement::default()
}; };
// Execute the statement // 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 { _ => Query::Update(UpdateStatement {
what: Values(vec![Value::from(rid)]), what: Values(vec![Value::from(rid)]),
data: Some(Data::ReplaceExpression( data: Some(Data::ReplaceExpression(
tb.expr.compute(&ctx, opt, false).await?, tb.expr
.compute(ctx, opt, txn, Some(&self.current), false)
.await?,
)), )),
..UpdateStatement::default() ..UpdateStatement::default()
}), }),
}; };
// Execute the statement // Execute the statement
stm.compute(&ctx, opt).await?; stm.compute(ctx, opt, txn, None).await?;
} }
} }
} }
@ -242,16 +255,16 @@ impl<'a> Document<'a> {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
act: Action, act: Action,
exp: &Fields, exp: &Fields,
) -> Result<Data, Error> { ) -> Result<Data, Error> {
// //
let mut ops: Ops = vec![]; let mut ops: Ops = vec![];
// Create a new context with the initial or the current doc // Create a new context with the initial or the current doc
let mut ctx = Context::new(ctx); let doc = match act {
match act { Action::Delete => Some(&self.initial),
Action::Delete => ctx.add_cursor_doc(self.initial.as_ref()), Action::Update => Some(&self.current),
Action::Update => ctx.add_cursor_doc(self.current.as_ref()),
_ => unreachable!(), _ => unreachable!(),
}; };
// //
@ -266,29 +279,29 @@ impl<'a> Document<'a> {
match expr { match expr {
Value::Function(f) if f.is_rolling() => match f.name() { Value::Function(f) if f.is_rolling() => match f.name() {
"count" => { "count" => {
let val = f.compute(&ctx, opt).await?; let val = f.compute(ctx, opt, txn, doc).await?;
self.chg(&mut ops, &act, idiom, val); self.chg(&mut ops, &act, idiom, val);
} }
"math::sum" => { "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); self.chg(&mut ops, &act, idiom, val);
} }
"math::min" => { "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); self.min(&mut ops, &act, idiom, val);
} }
"math::max" => { "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); self.max(&mut ops, &act, idiom, val);
} }
"math::mean" => { "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); self.mean(&mut ops, &act, idiom, val);
} }
_ => unreachable!(), _ => unreachable!(),
}, },
_ => { _ => {
let val = expr.compute(&ctx, opt).await?; let val = expr.compute(ctx, opt, txn, doc).await?;
self.set(&mut ops, idiom, val); self.set(&mut ops, idiom, val);
} }
} }

View file

@ -1,6 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Options, Transaction};
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
stm: &Statement<'_>, stm: &Statement<'_>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Check where clause // Check where clause
self.check(ctx, opt, stm).await?; self.check(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Alter record data // Alter record data
self.alter(ctx, opt, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data // Reset fields data
self.reset(ctx, opt, stm).await?; self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
self.allow(ctx, opt, stm).await?; self.allow(ctx, opt, txn, stm).await?;
// Store index data // Store index data
self.index(ctx, opt, stm).await?; self.index(ctx, opt, txn, stm).await?;
// Store record data // Store record data
self.store(ctx, opt, stm).await?; self.store(ctx, opt, txn, stm).await?;
// Run table queries // Run table queries
self.table(ctx, opt, stm).await?; self.table(ctx, opt, txn, stm).await?;
// Run lives queries // Run lives queries
self.lives(ctx, opt, stm).await?; self.lives(ctx, opt, txn, stm).await?;
// Run event queries // Run event queries
self.event(ctx, opt, stm).await?; self.event(ctx, opt, txn, stm).await?;
// Yield document // Yield document
self.pluck(ctx, opt, stm).await self.pluck(ctx, opt, txn, stm).await
} }
} }

View file

@ -1,5 +1,7 @@
//! Executes functions from SQL. If there is an SQL function it will be defined in this module. //! Executes functions from SQL. If there is an SQL function it will be defined in this module.
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Transaction;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -29,7 +31,13 @@ pub mod r#type;
pub mod util; pub mod util;
/// Attempts to run any function /// Attempts to run any function
pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> { pub async fn run(
ctx: &Context<'_>,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
name: &str,
args: Vec<Value>,
) -> Result<Value, Error> {
if name.eq("sleep") if name.eq("sleep")
|| name.starts_with("search") || name.starts_with("search")
|| name.starts_with("http") || name.starts_with("http")
@ -38,7 +46,7 @@ pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Valu
|| name.starts_with("crypto::pbkdf2") || name.starts_with("crypto::pbkdf2")
|| name.starts_with("crypto::scrypt") || name.starts_with("crypto::scrypt")
{ {
asynchronous(ctx, name, args).await asynchronous(ctx, Some(txn), doc, name, args).await
} else { } else {
synchronous(ctx, name, args) synchronous(ctx, name, args)
} }
@ -266,7 +274,13 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
} }
/// Attempts to run any asynchronous function. /// Attempts to run any asynchronous function.
pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> { pub async fn asynchronous(
ctx: &Context<'_>,
txn: Option<&Transaction>,
doc: Option<&CursorDoc<'_>>,
name: &str,
args: Vec<Value>,
) -> Result<Value, Error> {
// Wrappers return a function as opposed to a value so that the dispatch! method can always // Wrappers return a function as opposed to a value so that the dispatch! method can always
// perform a function call. // perform a function call.
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -302,9 +316,9 @@ pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Re
"http::patch" => http::patch(ctx).await, "http::patch" => http::patch(ctx).await,
"http::delete" => http::delete(ctx).await, "http::delete" => http::delete(ctx).await,
// //
"search::score" => search::score(ctx).await, "search::score" => search::score((ctx, txn, doc)).await,
"search::highlight" => search::highlight(ctx).await, "search::highlight" => search::highlight((ctx,txn, doc)).await,
"search::offsets" => search::offsets(ctx).await, "search::offsets" => search::offsets((ctx, txn, doc)).await,
// //
"sleep" => sleep::sleep(ctx).await, "sleep" => sleep::sleep(ctx).await,
) )

View file

@ -1,4 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Transaction;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::TryAdd; use crate::sql::value::TryAdd;
use crate::sql::value::TryDiv; use crate::sql::value::TryDiv;
@ -165,13 +167,18 @@ pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> {
Ok(a.intersects(b).into()) Ok(a.intersects(b).into())
} }
pub(crate) async fn matches(ctx: &Context<'_>, e: &Expression) -> Result<Value, Error> { pub(crate) async fn matches(
if let Some(thg) = ctx.thing() { ctx: &Context<'_>,
if let Some(exe) = ctx.get_query_executor(&thg.tb) { txn: &Transaction,
// Clone transaction doc: Option<&CursorDoc<'_>>,
let txn = ctx.try_clone_transaction()?; e: &Expression,
// Check the matches ) -> Result<Value, Error> {
return exe.matches(&txn, thg, e).await; 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)) Ok(Value::Bool(false))

View file

@ -5,7 +5,8 @@ use super::modules;
use super::modules::loader; use super::modules::loader;
use super::modules::resolver; use super::modules::resolver;
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::value::Value; use crate::sql::value::Value;
use js::async_with; use js::async_with;
@ -19,6 +20,8 @@ use js::Module;
pub async fn run( pub async fn run(
ctx: &Context<'_>, ctx: &Context<'_>,
_opt: &Options, _opt: &Options,
_txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
src: &str, src: &str,
arg: Vec<Value>, arg: Vec<Value>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
@ -26,8 +29,6 @@ pub async fn run(
if ctx.is_done() { if ctx.is_done() {
return Ok(Value::None); return Ok(Value::None);
} }
// Get the optional doc
let doc = ctx.doc();
// Create an JavaScript context // Create an JavaScript context
let run = js::AsyncRuntime::new().unwrap(); let run = js::AsyncRuntime::new().unwrap();
// Explicitly set max stack size to 256 KiB // Explicitly set max stack size to 256 KiB
@ -68,6 +69,8 @@ pub async fn run(
let res = ctx.compile("script", src)?; let res = ctx.compile("script", src)?;
// Attempt to fetch the main export // Attempt to fetch the main export
let fnc = res.get::<_, Function>("default")?; let fnc = res.get::<_, Function>("default")?;
// Extract the doc if any
let doc = doc.map(|v|v.doc.as_ref());
// Execute the main function // Execute the main function
let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?; let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?;
promise.await promise.await

View file

@ -68,7 +68,7 @@ async fn fut(js_ctx: js::Ctx<'_>, name: &str, args: Vec<Value>) -> Result<Value>
// Create a default context // Create a default context
let ctx = Context::background(); let ctx = Context::background();
// Process the called function // 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 // Convert any response error
res.map_err(|err| { res.map_err(|err| {
js::Exception::from_message(js_ctx, &err.to_string()) js::Exception::from_message(js_ctx, &err.to_string())

View file

@ -1,37 +1,54 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Transaction;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::Value; use crate::sql::Value;
pub async fn score(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> { pub async fn score(
if let Some(thg) = ctx.thing() { (ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
if let Some(exe) = ctx.get_query_executor(&thg.tb) { (match_ref,): (Value,),
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),
) -> Result<Value, Error> { ) -> Result<Value, Error> {
if let Some(doc) = ctx.doc() { if let Some(txn) = txn {
if let Some(thg) = ctx.thing() { if let Some(doc) = doc {
if let Some(exe) = ctx.get_query_executor(&thg.tb) { if let Some(thg) = doc.rid {
let txn = ctx.try_clone_transaction()?; if let Some(exe) = ctx.get_query_executor(&thg.tb) {
return exe.highlight(txn, thg, prefix, suffix, &match_ref, doc).await; return exe.score(txn, &match_ref, thg, doc.doc_id).await;
}
} }
} }
} }
Ok(Value::None) Ok(Value::None)
} }
pub async fn offsets(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> { pub async fn highlight(
if let Some(thg) = ctx.thing() { (ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
if let Some(exe) = ctx.get_query_executor(&thg.tb) { (prefix, suffix, match_ref): (Value, Value, Value),
let txn = ctx.try_clone_transaction()?; ) -> Result<Value, Error> {
return exe.offsets(txn, thg, &match_ref).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
.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<Value, Error> {
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) Ok(Value::None)

View file

@ -1,7 +1,6 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::btree::Payload; use crate::idx::btree::Payload;
use crate::kvs::Key; use crate::kvs::Key;
use async_trait::async_trait;
use fst::{IntoStreamer, Map, MapBuilder, Streamer}; use fst::{IntoStreamer, Map, MapBuilder, Streamer};
use radix_trie::{SubTrie, Trie, TrieCommon}; use radix_trie::{SubTrie, Trie, TrieCommon};
use serde::{de, ser, Deserialize, Serialize}; use serde::{de, ser, Deserialize, Serialize};
@ -361,7 +360,6 @@ impl Display for TrieKeys {
} }
} }
#[async_trait]
impl BKeys for TrieKeys { impl BKeys for TrieKeys {
fn with_key_val(key: Key, payload: Payload) -> Result<Self, Error> { fn with_key_val(key: Key, payload: Payload) -> Result<Self, Error> {
let mut trie_keys = Self { let mut trie_keys = Self {

View file

@ -1,9 +1,8 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::bkeys::BKeys; use crate::idx::bkeys::BKeys;
use crate::idx::SerdeState; use crate::idx::{IndexKeyBase, SerdeState};
use crate::kvs::{Key, Transaction}; use crate::kvs::{Key, Transaction};
use crate::sql::{Object, Value}; use crate::sql::{Object, Value};
use async_trait::async_trait;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::VecDeque; use std::collections::VecDeque;
@ -12,13 +11,39 @@ use std::fmt::Debug;
pub(crate) type NodeId = u64; pub(crate) type NodeId = u64;
pub(super) type Payload = u64; pub(super) type Payload = u64;
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[derive(Clone)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub(super) enum KeyProvider {
pub(super) trait KeyProvider { DocIds(IndexKeyBase),
fn get_node_key(&self, node_id: NodeId) -> Key; DocLengths(IndexKeyBase),
fn get_state_key(&self) -> Key { Postings(IndexKeyBase),
panic!("Not supported") 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<BK>(&self, tx: &mut Transaction, id: NodeId) -> Result<StoredNode<BK>, Error> async fn load_node<BK>(&self, tx: &mut Transaction, id: NodeId) -> Result<StoredNode<BK>, Error>
where where
BK: BKeys + Serialize + DeserializeOwned, BK: BKeys + Serialize + DeserializeOwned,
@ -34,11 +59,8 @@ pub(super) trait KeyProvider {
} }
} }
pub(super) struct BTree<K> pub(super) struct BTree {
where keys: KeyProvider,
K: KeyProvider + Clone,
{
keys: K,
state: State, state: State,
full_size: u32, full_size: u32,
updated: bool, updated: bool,
@ -164,11 +186,8 @@ where
median_key: Key, median_key: Key,
} }
impl<K> BTree<K> impl BTree {
where pub(super) fn new(keys: KeyProvider, state: State) -> Self {
K: KeyProvider + Clone + Sync,
{
pub(super) fn new(keys: K, state: State) -> Self {
Self { Self {
keys, keys,
full_size: state.minimum_degree * 2 - 1, full_size: state.minimum_degree * 2 - 1,
@ -730,18 +749,6 @@ mod tests {
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use test_log::test; 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] #[test]
fn test_btree_state_serde() { fn test_btree_state_serde() {
let s = State::new(3); let s = State::new(3);
@ -766,15 +773,14 @@ mod tests {
let _: Node<TrieKeys> = Node::try_from_val(val).unwrap(); let _: Node<TrieKeys> = Node::try_from_val(val).unwrap();
} }
async fn insertions_test<F, BK, K>( async fn insertions_test<F, BK>(
tx: &mut Transaction, tx: &mut Transaction,
t: &mut BTree<K>, t: &mut BTree,
samples_size: usize, samples_size: usize,
sample_provider: F, sample_provider: F,
) where ) where
F: Fn(usize) -> (Key, Payload), F: Fn(usize) -> (Key, Payload),
BK: BKeys + Serialize + DeserializeOwned + Default, BK: BKeys + Serialize + DeserializeOwned + Default,
K: KeyProvider + Clone + Sync,
{ {
for i in 0..samples_size { for i in 0..samples_size {
let (key, payload) = sample_provider(i); let (key, payload) = sample_provider(i);
@ -791,10 +797,10 @@ mod tests {
#[test(tokio::test)] #[test(tokio::test)]
async fn test_btree_fst_small_order_sequential_insertions() { 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 ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).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(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
assert_eq!( assert_eq!(
@ -810,10 +816,10 @@ mod tests {
#[test(tokio::test)] #[test(tokio::test)]
async fn test_btree_trie_small_order_sequential_insertions() { 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 ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).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(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
assert_eq!( assert_eq!(
@ -831,11 +837,11 @@ mod tests {
async fn test_btree_fst_small_order_random_insertions() { async fn test_btree_fst_small_order_random_insertions() {
let ds = Datastore::new("memory").await.unwrap(); let ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).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<usize> = (0..100).collect(); let mut samples: Vec<usize> = (0..100).collect();
let mut rng = thread_rng(); let mut rng = thread_rng();
samples.shuffle(&mut 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(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
let s = t.statistics::<FstKeys>(&mut tx).await.unwrap(); let s = t.statistics::<FstKeys>(&mut tx).await.unwrap();
@ -846,12 +852,11 @@ mod tests {
async fn test_btree_trie_small_order_random_insertions() { async fn test_btree_trie_small_order_random_insertions() {
let ds = Datastore::new("memory").await.unwrap(); let ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).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<usize> = (0..100).collect(); let mut samples: Vec<usize> = (0..100).collect();
let mut rng = thread_rng(); let mut rng = thread_rng();
samples.shuffle(&mut rng); samples.shuffle(&mut rng);
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])) insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
.await;
tx.commit().await.unwrap(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
let s = t.statistics::<TrieKeys>(&mut tx).await.unwrap(); let s = t.statistics::<TrieKeys>(&mut tx).await.unwrap();
@ -862,8 +867,8 @@ mod tests {
async fn test_btree_fst_keys_large_order_sequential_insertions() { async fn test_btree_fst_keys_large_order_sequential_insertions() {
let ds = Datastore::new("memory").await.unwrap(); let ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap();
let mut t = BTree::new(TestKeyProvider {}, State::new(60)); let mut t = BTree::new(KeyProvider::Debug, State::new(60));
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 10000, get_key_value).await; insertions_test::<_, FstKeys>(&mut tx, &mut t, 10000, get_key_value).await;
tx.commit().await.unwrap(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
assert_eq!( assert_eq!(
@ -881,8 +886,8 @@ mod tests {
async fn test_btree_trie_keys_large_order_sequential_insertions() { async fn test_btree_trie_keys_large_order_sequential_insertions() {
let ds = Datastore::new("memory").await.unwrap(); let ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap();
let mut t = BTree::new(TestKeyProvider {}, State::new(60)); let mut t = BTree::new(KeyProvider::Debug, State::new(60));
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 10000, get_key_value).await; insertions_test::<_, TrieKeys>(&mut tx, &mut t, 10000, get_key_value).await;
tx.commit().await.unwrap(); tx.commit().await.unwrap();
let mut tx = ds.transaction(false, false).await.unwrap(); let mut tx = ds.transaction(false, false).await.unwrap();
assert_eq!( assert_eq!(
@ -908,8 +913,8 @@ mod tests {
{ {
let ds = Datastore::new("memory").await.unwrap(); let ds = Datastore::new("memory").await.unwrap();
let mut tx = ds.transaction(true, false).await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap();
let mut t = BTree::new(TestKeyProvider {}, State::new(default_minimum_degree)); let mut t = BTree::new(KeyProvider::Debug, State::new(default_minimum_degree));
insertions_test::<_, BK, _>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| { insertions_test::<_, BK>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| {
(REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload) (REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload)
}) })
.await; .await;
@ -1006,7 +1011,7 @@ mod tests {
// This check node splitting. CLRS: Figure 18.7, page 498. // This check node splitting. CLRS: Figure 18.7, page 498.
async fn clrs_insertion_test() { async fn clrs_insertion_test() {
let ds = Datastore::new("memory").await.unwrap(); 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 tx = ds.transaction(true, false).await.unwrap();
for (key, payload) in CLRS_EXAMPLE { for (key, payload) in CLRS_EXAMPLE {
t.insert::<TrieKeys>(&mut tx, key.into(), payload).await.unwrap(); t.insert::<TrieKeys>(&mut tx, key.into(), payload).await.unwrap();
@ -1090,7 +1095,7 @@ mod tests {
BK: BKeys + Serialize + DeserializeOwned + Default, BK: BKeys + Serialize + DeserializeOwned + Default,
{ {
let ds = Datastore::new("memory").await.unwrap(); 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 tx = ds.transaction(true, false).await.unwrap();
for (key, payload) in CLRS_EXAMPLE { for (key, payload) in CLRS_EXAMPLE {
t.insert::<BK>(&mut tx, key.into(), payload).await.unwrap(); t.insert::<BK>(&mut tx, key.into(), payload).await.unwrap();
@ -1180,7 +1185,7 @@ mod tests {
BK: BKeys + Serialize + DeserializeOwned + Default, BK: BKeys + Serialize + DeserializeOwned + Default,
{ {
let ds = Datastore::new("memory").await.unwrap(); 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 tx = ds.transaction(true, false).await.unwrap();
let mut expected_keys = HashMap::new(); let mut expected_keys = HashMap::new();
@ -1191,13 +1196,13 @@ mod tests {
tx.commit().await.unwrap(); tx.commit().await.unwrap();
let mut tx = ds.transaction(true, false).await.unwrap(); let mut tx = ds.transaction(true, false).await.unwrap();
print_tree::<BK, _>(&mut tx, &t).await; print_tree::<BK>(&mut tx, &t).await;
for (key, _) in CLRS_EXAMPLE { for (key, _) in CLRS_EXAMPLE {
debug!("------------------------"); debug!("------------------------");
debug!("Delete {}", key); debug!("Delete {}", key);
t.delete::<BK>(&mut tx, key.into()).await.unwrap(); t.delete::<BK>(&mut tx, key.into()).await.unwrap();
print_tree::<BK, _>(&mut tx, &t).await; print_tree::<BK>(&mut tx, &t).await;
// Check that every expected keys are still found in the tree // Check that every expected keys are still found in the tree
expected_keys.remove(key); expected_keys.remove(key);
@ -1259,9 +1264,8 @@ mod tests {
} }
} }
async fn print_tree<BK, K>(tx: &mut Transaction, t: &BTree<K>) async fn print_tree<BK>(tx: &mut Transaction, t: &BTree)
where where
K: KeyProvider + Clone + Sync,
BK: BKeys + Serialize + DeserializeOwned, BK: BKeys + Serialize + DeserializeOwned,
{ {
debug!("----------------------------------"); debug!("----------------------------------");
@ -1289,10 +1293,7 @@ mod tests {
} }
} }
impl<K> BTree<K> impl BTree {
where
K: KeyProvider + Clone + Sync,
{
/// This is for debugging /// This is for debugging
async fn inspect_nodes<BK, F>( async fn inspect_nodes<BK, F>(
&self, &self,

View file

@ -1,6 +1,6 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::bkeys::TrieKeys; 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::idx::{btree, IndexKeyBase, SerdeState};
use crate::kvs::{Key, Transaction}; use crate::kvs::{Key, Transaction};
use roaring::RoaringTreemap; use roaring::RoaringTreemap;
@ -13,7 +13,7 @@ pub(crate) const NO_DOC_ID: u64 = u64::MAX;
pub(crate) struct DocIds { pub(crate) struct DocIds {
state_key: Key, state_key: Key,
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
btree: BTree<DocIdsKeyProvider>, btree: BTree,
available_ids: Option<RoaringTreemap>, available_ids: Option<RoaringTreemap>,
next_doc_id: DocId, next_doc_id: DocId,
updated: bool, updated: bool,
@ -25,9 +25,7 @@ impl DocIds {
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
default_btree_order: u32, default_btree_order: u32,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let keys = DocIdsKeyProvider { let keys = KeyProvider::DocIds(index_key_base.clone());
index_key_base: index_key_base.clone(),
};
let state_key: Key = keys.get_state_key(); let state_key: Key = keys.get_state_key();
let state: State = if let Some(val) = tx.get(state_key.clone()).await? { let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
State::try_from_val(val)? 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)] #[cfg(test)]
mod tests { mod tests {
use crate::idx::ft::docids::{DocIds, Resolved}; use crate::idx::ft::docids::{DocIds, Resolved};

View file

@ -1,6 +1,6 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::bkeys::TrieKeys; 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::ft::docids::DocId;
use crate::idx::{btree, IndexKeyBase, SerdeState}; use crate::idx::{btree, IndexKeyBase, SerdeState};
use crate::kvs::{Key, Transaction}; use crate::kvs::{Key, Transaction};
@ -9,7 +9,7 @@ pub(super) type DocLength = u64;
pub(super) struct DocLengths { pub(super) struct DocLengths {
state_key: Key, state_key: Key,
btree: BTree<DocLengthsKeyProvider>, btree: BTree,
} }
impl DocLengths { impl DocLengths {
@ -18,9 +18,7 @@ impl DocLengths {
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
default_btree_order: u32, default_btree_order: u32,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let keys = DocLengthsKeyProvider { let keys = KeyProvider::DocLengths(index_key_base);
index_key_base,
};
let state_key: Key = keys.get_state_key(); let state_key: Key = keys.get_state_key();
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? { let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
btree::State::try_from_val(val)? 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)] #[cfg(test)]
mod tests { mod tests {
use crate::idx::ft::doclength::DocLengths; use crate::idx::ft::doclength::DocLengths;

View file

@ -1,6 +1,6 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::bkeys::TrieKeys; 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::docids::DocId;
use crate::idx::ft::terms::TermId; use crate::idx::ft::terms::TermId;
use crate::idx::{btree, IndexKeyBase, SerdeState}; use crate::idx::{btree, IndexKeyBase, SerdeState};
@ -11,7 +11,7 @@ pub(super) type TermFrequency = u64;
pub(super) struct Postings { pub(super) struct Postings {
state_key: Key, state_key: Key,
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
btree: BTree<PostingsKeyProvider>, btree: BTree,
} }
impl Postings { impl Postings {
@ -20,9 +20,7 @@ impl Postings {
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
order: u32, order: u32,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let keys = PostingsKeyProvider { let keys = KeyProvider::Postings(index_key_base.clone());
index_key_base: index_key_base.clone(),
};
let state_key: Key = keys.get_state_key(); let state_key: Key = keys.get_state_key();
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? { let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
btree::State::try_from_val(val)? 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)] #[cfg(test)]
mod tests { mod tests {
use crate::idx::ft::postings::Postings; use crate::idx::ft::postings::Postings;

View file

@ -1,6 +1,6 @@
use crate::err::Error; use crate::err::Error;
use crate::idx::bkeys::FstKeys; 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::idx::{btree, IndexKeyBase, SerdeState};
use crate::kvs::{Key, Transaction}; use crate::kvs::{Key, Transaction};
use roaring::RoaringTreemap; use roaring::RoaringTreemap;
@ -11,7 +11,7 @@ pub(crate) type TermId = u64;
pub(super) struct Terms { pub(super) struct Terms {
state_key: Key, state_key: Key,
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
btree: BTree<TermsKeyProvider>, btree: BTree,
available_ids: Option<RoaringTreemap>, available_ids: Option<RoaringTreemap>,
next_term_id: TermId, next_term_id: TermId,
updated: bool, updated: bool,
@ -23,9 +23,7 @@ impl Terms {
index_key_base: IndexKeyBase, index_key_base: IndexKeyBase,
default_btree_order: u32, default_btree_order: u32,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let keys = TermsKeyProvider { let keys = KeyProvider::Terms(index_key_base.clone());
index_key_base: index_key_base.clone(),
};
let state_key: Key = keys.get_state_key(); let state_key: Key = keys.get_state_key();
let state: State = if let Some(val) = tx.get(state_key.clone()).await? { let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
State::try_from_val(val)? 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)] #[cfg(test)]
mod tests { mod tests {
use crate::idx::ft::postings::TermFrequency; use crate::idx::ft::postings::TermFrequency;

View file

@ -177,7 +177,7 @@ impl QueryExecutor {
pub(crate) async fn highlight( pub(crate) async fn highlight(
&self, &self,
txn: Transaction, txn: &Transaction,
thg: &Thing, thg: &Thing,
prefix: Value, prefix: Value,
suffix: Value, suffix: Value,
@ -195,7 +195,7 @@ impl QueryExecutor {
pub(crate) async fn offsets( pub(crate) async fn offsets(
&self, &self,
txn: Transaction, txn: &Transaction,
thg: &Thing, thg: &Thing,
match_ref: &Value, match_ref: &Value,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
@ -208,7 +208,7 @@ impl QueryExecutor {
pub(crate) async fn score( pub(crate) async fn score(
&self, &self,
txn: Transaction, txn: &Transaction,
match_ref: &Value, match_ref: &Value,
rid: &Thing, rid: &Thing,
mut doc_id: Option<DocId>, mut doc_id: Option<DocId>,

View file

@ -3,7 +3,7 @@ pub(crate) mod plan;
mod tree; mod tree;
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::{Iterable, Options}; use crate::dbs::{Iterable, Options, Transaction};
use crate::err::Error; use crate::err::Error;
use crate::idx::planner::executor::QueryExecutor; use crate::idx::planner::executor::QueryExecutor;
use crate::idx::planner::plan::{Plan, PlanBuilder}; use crate::idx::planner::plan::{Plan, PlanBuilder};
@ -30,17 +30,17 @@ impl<'a> QueryPlanner<'a> {
pub(crate) async fn get_iterable( pub(crate) async fn get_iterable(
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
txn: &Transaction,
t: Table, t: Table,
) -> Result<Iterable, Error> { ) -> Result<Iterable, Error> {
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((node, im)) = res {
if let Some(plan) = AllAndStrategy::build(&node)? { 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); self.executors.insert(t.0.clone(), e);
return Ok(Iterable::Index(t, plan)); 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); self.executors.insert(t.0.clone(), e);
} }
Ok(Iterable::Table(t)) Ok(Iterable::Table(t))

View file

@ -11,7 +11,6 @@ use crate::sql::index::Index;
use crate::sql::scoring::Scoring; use crate::sql::scoring::Scoring;
use crate::sql::statements::DefineIndexStatement; use crate::sql::statements::DefineIndexStatement;
use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value}; use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value};
use async_trait::async_trait;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
@ -54,7 +53,7 @@ impl Plan {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
exe: &QueryExecutor, exe: &QueryExecutor,
) -> Result<Box<dyn ThingIterator>, Error> { ) -> Result<ThingIterator, Error> {
self.i.new_iterator(opt, txn, exe).await self.i.new_iterator(opt, txn, exe).await
} }
@ -128,11 +127,11 @@ impl IndexOption {
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
exe: &QueryExecutor, exe: &QueryExecutor,
) -> Result<Box<dyn ThingIterator>, Error> { ) -> Result<ThingIterator, Error> {
match &self.ix().index { match &self.ix().index {
Index::Idx => { Index::Idx => {
if self.op() == &Operator::Equal { if self.op() == &Operator::Equal {
return Ok(Box::new(NonUniqueEqualThingIterator::new( return Ok(ThingIterator::NonUniqueEqual(NonUniqueEqualThingIterator::new(
opt, opt,
self.ix(), self.ix(),
self.value(), self.value(),
@ -141,7 +140,7 @@ impl IndexOption {
} }
Index::Uniq => { Index::Uniq => {
if self.op() == &Operator::Equal { if self.op() == &Operator::Equal {
return Ok(Box::new(UniqueEqualThingIterator::new( return Ok(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(
opt, opt,
self.ix(), self.ix(),
self.value(), self.value(),
@ -156,7 +155,7 @@ impl IndexOption {
} => { } => {
if let Operator::Matches(_) = self.op() { if let Operator::Matches(_) = self.op() {
let td = exe.pre_match_terms_docs(); 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) MatchesThingIterator::new(opt, txn, self.ix(), az, *hl, sc, *order, td)
.await?, .await?,
)); ));
@ -167,23 +166,37 @@ impl IndexOption {
} }
} }
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] pub(crate) enum ThingIterator {
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] NonUniqueEqual(NonUniqueEqualThingIterator),
pub(crate) trait ThingIterator: Send { UniqueEqual(UniqueEqualThingIterator),
async fn next_batch( Matches(MatchesThingIterator),
}
impl ThingIterator {
pub(crate) async fn next_batch(
&mut self, &mut self,
tx: &Transaction, tx: &Transaction,
size: u32, size: u32,
) -> Result<Vec<(Thing, DocId)>, Error>; ) -> Result<Vec<(Thing, DocId)>, 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<u8>, beg: Vec<u8>,
end: Vec<u8>, end: Vec<u8>,
} }
impl NonUniqueEqualThingIterator { impl NonUniqueEqualThingIterator {
fn new(opt: &Options, ix: &DefineIndexStatement, v: &Value) -> Result<Self, Error> { fn new(
opt: &Options,
ix: &DefineIndexStatement,
v: &Value,
) -> Result<NonUniqueEqualThingIterator, Error> {
let v = Array::from(v.clone()); let v = Array::from(v.clone());
let beg = key::index::prefix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v); 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); let end = key::index::suffix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
@ -192,11 +205,7 @@ impl NonUniqueEqualThingIterator {
end, 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( async fn next_batch(
&mut self, &mut self,
txn: &Transaction, txn: &Transaction,
@ -214,7 +223,7 @@ impl ThingIterator for NonUniqueEqualThingIterator {
} }
} }
struct UniqueEqualThingIterator { pub(crate) struct UniqueEqualThingIterator {
key: Option<Key>, key: Option<Key>,
} }
@ -226,11 +235,7 @@ impl UniqueEqualThingIterator {
key: Some(key), 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( async fn next_batch(
&mut self, &mut self,
txn: &Transaction, txn: &Transaction,
@ -245,7 +250,7 @@ impl ThingIterator for UniqueEqualThingIterator {
} }
} }
struct MatchesThingIterator { pub(crate) struct MatchesThingIterator {
hits: Option<HitsIterator>, hits: Option<HitsIterator>,
} }
@ -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( async fn next_batch(
&mut self, &mut self,
txn: &Transaction, txn: &Transaction,

View file

@ -79,7 +79,7 @@ impl<'a> TreeBuilder<'a> {
Value::Bool(_) => Node::Scalar(v.to_owned()), Value::Bool(_) => Node::Scalar(v.to_owned()),
Value::Subquery(s) => self.eval_subquery(s).await?, Value::Subquery(s) => self.eval_subquery(s).await?,
Value::Param(p) => { 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? self.eval_value(&v).await?
} }
_ => Node::Unsupported, _ => Node::Unsupported,

View file

@ -447,8 +447,6 @@ impl Datastore {
let txn = Arc::new(Mutex::new(txn)); let txn = Arc::new(Mutex::new(txn));
// Create a default context // Create a default context
let mut ctx = Context::default(); let mut ctx = Context::default();
// Add the transaction
ctx.add_transaction(Some(&txn));
// Set the global query timeout // Set the global query timeout
if let Some(timeout) = self.query_timeout { if let Some(timeout) = self.query_timeout {
ctx.add_timeout(timeout); ctx.add_timeout(timeout);
@ -462,7 +460,7 @@ impl Datastore {
// Store the query variables // Store the query variables
let ctx = vars.attach(ctx)?; let ctx = vars.attach(ctx)?;
// Compute the value // Compute the value
let res = val.compute(&ctx, &opt).await?; let res = val.compute(&ctx, &opt, &txn, None).await?;
// Store any data // Store any data
match val.writeable() { match val.writeable() {
true => txn.lock().await.commit().await?, true => txn.lock().await.commit().await?,

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::common::{closebracket, commas, openbracket}; use crate::sql::common::{closebracket, commas, openbracket};
@ -117,10 +118,16 @@ impl Array {
impl Array { impl Array {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
let mut x = Self::with_capacity(self.len()); let mut x = Self::with_capacity(self.len());
for v in self.iter() { for v in self.iter() {
match v.compute(ctx, opt).await { match v.compute(ctx, opt, txn, doc).await {
Ok(v) => x.push(v), Ok(v) => x.push(v),
Err(e) => return Err(e), Err(e) => return Err(e),
}; };

View file

@ -1,6 +1,7 @@
use crate::cnf::PROTECTED_PARAM_NAMES; use crate::cnf::PROTECTED_PARAM_NAMES;
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::{comment, mightbespace}; use crate::sql::comment::{comment, mightbespace};
use crate::sql::common::{closebraces, colons, openbraces}; use crate::sql::common::{closebraces, colons, openbraces};
@ -51,7 +52,13 @@ impl Block {
self.iter().any(Entry::writeable) self.iter().any(Entry::writeable)
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Duplicate context // Duplicate context
let mut ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Loop over the statements // Loop over the statements
@ -61,7 +68,7 @@ impl Block {
// Check if the variable is a protected variable // Check if the variable is a protected variable
let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) { let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) {
// The variable isn't protected and can be stored // 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 // The user tried to set a protected variable
true => { true => {
return Err(Error::InvalidParam { return Err(Error::InvalidParam {
@ -73,31 +80,31 @@ impl Block {
ctx.add_value(v.name.to_owned(), val); ctx.add_value(v.name.to_owned(), val);
} }
Entry::Ifelse(v) => { Entry::Ifelse(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Select(v) => { Entry::Select(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Create(v) => { Entry::Create(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Update(v) => { Entry::Update(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Delete(v) => { Entry::Delete(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Relate(v) => { Entry::Relate(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Insert(v) => { Entry::Insert(v) => {
v.compute(&ctx, opt).await?; v.compute(&ctx, opt, txn, doc).await?;
} }
Entry::Output(v) => { Entry::Output(v) => {
return v.compute(&ctx, opt).await; return v.compute(&ctx, opt, txn, doc).await;
} }
Entry::Value(v) => { Entry::Value(v) => {
return v.compute(&ctx, opt).await; return v.compute(&ctx, opt, txn, doc).await;
} }
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -36,11 +37,17 @@ impl Cast {
impl Cast { impl Cast {
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&'async_recursion CursorDoc<'_>>,
) -> Result<Value, Error> {
// Prevent long cast chains // Prevent long cast chains
let opt = &opt.dive(1)?; let opt = &opt.dive(1)?;
// Compute the value to be cast and convert it // 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)
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::value::Value; use crate::sql::value::Value;
@ -78,7 +79,13 @@ impl Constant {
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
_opt: &Options,
_txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
Ok(match self.value() { Ok(match self.value() {
ConstantValue::Datetime(d) => d.into(), ConstantValue::Datetime(d) => d.into(),
ConstantValue::Float(f) => f.into(), ConstantValue::Float(f) => f.into(),

View file

@ -1,5 +1,5 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
@ -43,25 +43,26 @@ impl Data {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
tb: &Table, tb: &Table,
) -> Result<Thing, Error> { ) -> Result<Thing, Error> {
match self { match self {
Self::MergeExpression(v) => { Self::MergeExpression(v) => {
// This MERGE expression has an 'id' field // 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) => { Self::ReplaceExpression(v) => {
// This REPLACE expression has an 'id' field // 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) => { Self::ContentExpression(v) => {
// This CONTENT expression has an 'id' field // 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()) { Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) {
Some((_, _, v)) => { Some((_, _, v)) => {
// This SET expression has an 'id' field // 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 // This SET expression had no 'id' field
_ => Ok(tb.generate()), _ => Ok(tb.generate()),

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::fnc; use crate::fnc;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
@ -101,13 +102,19 @@ impl Expression {
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
let (l, o, r) = match self { let (l, o, r) = match self {
Self::Unary { Self::Unary {
o, o,
v, v,
} => { } => {
let operand = v.compute(ctx, opt).await?; let operand = v.compute(ctx, opt, txn, doc).await?;
return match o { return match o {
Operator::Neg => fnc::operate::neg(operand), Operator::Neg => fnc::operate::neg(operand),
Operator::Not => fnc::operate::not(operand), Operator::Not => fnc::operate::not(operand),
@ -121,7 +128,7 @@ impl Expression {
} => (l, o, r), } => (l, o, r),
}; };
let l = l.compute(ctx, opt).await?; let l = l.compute(ctx, opt, txn, doc).await?;
match o { match o {
Operator::Or => { Operator::Or => {
if let true = l.is_truthy() { if let true = l.is_truthy() {
@ -145,7 +152,7 @@ impl Expression {
} }
_ => {} // Continue _ => {} // Continue
} }
let r = r.compute(ctx, opt).await?; let r = r.compute(ctx, opt, txn, doc).await?;
match o { match o {
Operator::Or => fnc::operate::or(l, r), Operator::Or => fnc::operate::or(l, r),
Operator::And => fnc::operate::and(l, r), Operator::And => fnc::operate::and(l, r),
@ -181,7 +188,7 @@ impl Expression {
Operator::NoneInside => fnc::operate::inside_none(&l, &r), Operator::NoneInside => fnc::operate::inside_none(&l, &r),
Operator::Outside => fnc::operate::outside(&l, &r), Operator::Outside => fnc::operate::outside(&l, &r),
Operator::Intersects => fnc::operate::intersects(&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!(), _ => unreachable!(),
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::common::commas; use crate::sql::common::commas;
@ -75,17 +76,31 @@ impl Fields {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
group: bool, group: bool,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
// Ensure futures are run // 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<Value, Error> {
let opt = &opt.new_with_futures(true); 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 // Process the desired output
let mut out = match self.is_all() { 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(), false => Value::base(),
}; };
for v in self.other() { for v in self.other() {
@ -104,13 +119,13 @@ impl Fields {
Value::Function(f) if group && f.is_aggregate() => { Value::Function(f) if group && f.is_aggregate() => {
let x = match f.args().len() { let x = match f.args().len() {
// If no function arguments, then compute the result // 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 // 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 // Check if this is a single VALUE field expression
match self.single().is_some() { 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, true => out = x,
} }
} }
@ -123,11 +138,15 @@ impl Fields {
// Use the last fetched value for each fetch // Use the last fetched value for each fetch
let x = match res.last() { let x = match res.last() {
Some((_, r)) => r, Some((_, r)) => r,
None => doc, None => doc.doc.as_ref(),
}; };
// Continue fetching the next idiom part // Continue fetching the next idiom part
let x = let x = x
x.get(&ctx, opt, v).await?.compute(&ctx, opt).await?.flatten(); .get(ctx, opt, txn, Some(doc), v)
.await?
.compute(ctx, opt, txn, Some(doc))
.await?
.flatten();
// Add the result to the temporary store // Add the result to the temporary store
res.push((v, x)); res.push((v, x));
} }
@ -137,23 +156,24 @@ impl Fields {
// This is an alias expression part // This is an alias expression part
Some(a) => { Some(a) => {
if let Some(i) = alias { 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 // This is the end of the expression
None => { 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 // 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 // Check if this is a single VALUE field expression
match self.single().is_some() { 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, true => out = x,
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::fnc; use crate::fnc;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
@ -131,7 +132,13 @@ impl Function {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&'async_recursion CursorDoc<'_>>,
) -> Result<Value, Error> {
// Prevent long function chains // Prevent long function chains
let opt = &opt.dive(1)?; let opt = &opt.dive(1)?;
// Ensure futures are run // Ensure futures are run
@ -140,15 +147,13 @@ impl Function {
match self { match self {
Self::Normal(s, x) => { Self::Normal(s, x) => {
// Compute the function arguments // 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 // Run the normal function
fnc::run(ctx, s, a).await fnc::run(ctx, txn, doc, s, a).await
} }
Self::Custom(s, x) => { Self::Custom(s, x) => {
// Get the function definition // Get the function definition
let val = { let val = {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Get the function definition // Get the function definition
@ -165,7 +170,7 @@ impl Function {
}); });
} }
// Compute the function arguments // 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 // Duplicate context
let mut ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Process the function arguments // Process the function arguments
@ -173,16 +178,16 @@ impl Function {
ctx.add_value(name.to_raw(), val.coerce_to(&kind)?); ctx.add_value(name.to_raw(), val.coerce_to(&kind)?);
} }
// Run the custom function // Run the custom function
val.block.compute(&ctx, opt).await val.block.compute(&ctx, opt, txn, doc).await
} }
#[allow(unused_variables)] #[allow(unused_variables)]
Self::Script(s, x) => { Self::Script(s, x) => {
#[cfg(feature = "scripting")] #[cfg(feature = "scripting")]
{ {
// Compute the function arguments // 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 // 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"))] #[cfg(not(feature = "scripting"))]
{ {

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::block::{block, Block}; use crate::sql::block::{block, Block};
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
@ -24,12 +25,18 @@ impl From<Value> for Future {
impl Future { impl Future {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Prevent long future chains // Prevent long future chains
let opt = &opt.dive(1)?; let opt = &opt.dive(1)?;
// Process the future if enabled // Process the future if enabled
match opt.futures { 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()), false => Ok(self.clone().into()),
} }
} }

View file

@ -1,6 +1,7 @@
use crate::cnf::ID_CHARS; use crate::cnf::ID_CHARS;
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::array::{array, Array}; use crate::sql::array::{array, Array};
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -166,15 +167,21 @@ impl Display for Id {
impl Id { impl Id {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Id, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Id, Error> {
match self { match self {
Id::Number(v) => Ok(Id::Number(*v)), Id::Number(v) => Ok(Id::Number(*v)),
Id::String(v) => Ok(Id::String(v.clone())), 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)), Value::Object(v) => Ok(Id::Object(v)),
_ => unreachable!(), _ => 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)), Value::Array(v) => Ok(Id::Array(v)),
_ => unreachable!(), _ => unreachable!(),
}, },

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::common::commas; use crate::sql::common::commas;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -127,21 +128,29 @@ impl Idiom {
self.0.iter().any(|v| v.writeable()) self.0.iter().any(|v| v.writeable())
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self.first() { match self.first() {
// The starting part is a value // The starting part is a value
Some(Part::Value(v)) => { Some(Part::Value(v)) => {
v.compute(ctx, opt) v.compute(ctx, opt, txn, doc)
.await? .await?
.get(ctx, opt, self.as_ref().next()) .get(ctx, opt, txn, doc, self.as_ref().next())
.await? .await?
.compute(ctx, opt) .compute(ctx, opt, txn, doc)
.await .await
} }
// Otherwise use the current document // Otherwise use the current document
_ => match ctx.doc() { _ => match doc {
// There is a current document // 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 // There isn't any document
None => Ok(Value::None), None => Ok(Value::None),
}, },

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -15,8 +16,14 @@ use std::fmt;
pub struct Limit(pub Value); pub struct Limit(pub Value);
impl Limit { impl Limit {
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> { pub(crate) async fn process(
match self.0.compute(ctx, opt).await { &self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<usize, Error> {
match self.0.compute(ctx, opt, txn, doc).await {
// This is a valid limiting number // This is a valid limiting number
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
// An invalid value was specified // An invalid value was specified

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::common::{commas, val_char}; use crate::sql::common::{commas, val_char};
@ -124,10 +125,16 @@ impl Object {
impl Object { impl Object {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
let mut x = BTreeMap::new(); let mut x = BTreeMap::new();
for (k, v) in self.iter() { 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), Ok(v) => x.insert(k.clone(), v),
Err(e) => return Err(e), Err(e) => return Err(e),
}; };

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::ident::{ident, Ident}; use crate::sql::ident::{ident, Ident};
@ -43,24 +44,28 @@ impl Deref for Param {
impl Param { impl Param {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Find the variable by name // Find the variable by name
match self.as_str() { match self.as_str() {
// This is a special param // This is a special param
"this" | "self" => match ctx.doc() { "this" | "self" => match doc {
// The base document exists // 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 // The base document does not exist
None => Ok(Value::None), None => Ok(Value::None),
}, },
// This is a normal param // This is a normal param
v => match ctx.value(v) { v => match ctx.value(v) {
// The param has been set locally // 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 // The param has not been set locally
None => { None => {
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Get the param definition // Get the param definition

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::id::{id, Id}; use crate::sql::id::{id, Id};
@ -48,17 +49,23 @@ impl TryFrom<&str> for Range {
impl Range { impl Range {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
Ok(Value::Range(Box::new(Range { Ok(Value::Range(Box::new(Range {
tb: self.tb.clone(), tb: self.tb.clone(),
beg: match &self.beg { beg: match &self.beg {
Bound::Included(id) => Bound::Included(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).await?), Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
Bound::Unbounded => Bound::Unbounded, Bound::Unbounded => Bound::Unbounded,
}, },
end: match &self.end { end: match &self.end {
Bound::Included(id) => Bound::Included(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).await?), Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
Bound::Unbounded => Bound::Unbounded, Bound::Unbounded => Bound::Unbounded,
}, },
}))) })))

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -15,8 +16,14 @@ use std::fmt;
pub struct Start(pub Value); pub struct Start(pub Value);
impl Start { impl Start {
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> { pub(crate) async fn process(
match self.0.compute(ctx, opt).await { &self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<usize, Error> {
match self.0.compute(ctx, opt, txn, doc).await {
// This is a valid starting number // This is a valid starting number
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize), Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
// An invalid value was specified // An invalid value was specified

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::{comment, mightbespace}; use crate::sql::comment::{comment, mightbespace};
use crate::sql::common::colons; use crate::sql::common::colons;
@ -138,25 +139,31 @@ impl Statement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self { match self {
Self::Analyze(v) => v.compute(ctx, opt).await, Self::Analyze(v) => v.compute(ctx, opt, txn, doc).await,
Self::Create(v) => v.compute(ctx, opt).await, Self::Create(v) => v.compute(ctx, opt, txn, doc).await,
Self::Delete(v) => v.compute(ctx, opt).await, Self::Delete(v) => v.compute(ctx, opt, txn, doc).await,
Self::Define(v) => v.compute(ctx, opt).await, Self::Define(v) => v.compute(ctx, opt, txn, doc).await,
Self::Ifelse(v) => v.compute(ctx, opt).await, Self::Ifelse(v) => v.compute(ctx, opt, txn, doc).await,
Self::Info(v) => v.compute(ctx, opt).await, Self::Info(v) => v.compute(ctx, opt, txn, doc).await,
Self::Insert(v) => v.compute(ctx, opt).await, Self::Insert(v) => v.compute(ctx, opt, txn, doc).await,
Self::Kill(v) => v.compute(ctx, opt).await, Self::Kill(v) => v.compute(ctx, opt, txn, doc).await,
Self::Live(v) => v.compute(ctx, opt).await, Self::Live(v) => v.compute(ctx, opt, txn, doc).await,
Self::Output(v) => v.compute(ctx, opt).await, Self::Output(v) => v.compute(ctx, opt, txn, doc).await,
Self::Relate(v) => v.compute(ctx, opt).await, Self::Relate(v) => v.compute(ctx, opt, txn, doc).await,
Self::Remove(v) => v.compute(ctx, opt).await, Self::Remove(v) => v.compute(ctx, opt, txn, doc).await,
Self::Select(v) => v.compute(ctx, opt).await, Self::Select(v) => v.compute(ctx, opt, txn, doc).await,
Self::Set(v) => v.compute(ctx, opt).await, Self::Set(v) => v.compute(ctx, opt, txn, doc).await,
Self::Show(v) => v.compute(ctx, opt).await, Self::Show(v) => v.compute(ctx, opt, doc).await,
Self::Sleep(v) => v.compute(ctx, opt).await, Self::Sleep(v) => v.compute(ctx, opt, doc).await,
Self::Update(v) => v.compute(ctx, opt).await, Self::Update(v) => v.compute(ctx, opt, txn, doc).await,
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::idx::ft::FtIndex; use crate::idx::ft::FtIndex;
use crate::idx::IndexKeyBase; use crate::idx::IndexKeyBase;
@ -22,15 +23,19 @@ pub enum AnalyzeStatement {
impl AnalyzeStatement { impl AnalyzeStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self { match self {
AnalyzeStatement::Idx(tb, idx) => { AnalyzeStatement::Idx(tb, idx) => {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Read the index // Read the index

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::data::{data, Data}; use crate::sql::data::{data, Data};
@ -42,7 +43,13 @@ impl CreateStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -53,11 +60,11 @@ impl CreateStatement {
let opt = &opt.new_with_futures(false); let opt = &opt.new_with_futures(false);
// Loop over the create targets // Loop over the create targets
for w in self.what.0.iter() { 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 { match v {
Value::Table(v) => match &self.data { Value::Table(v) => match &self.data {
// There is a data clause so check for a record id // 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 // There was a problem creating the record id
Err(e) => return Err(e), Err(e) => return Err(e),
// There is an id field so use the record id // There is an id field so use the record id
@ -116,7 +123,7 @@ impl CreateStatement {
// Assign the statement // Assign the statement
let stm = Statement::from(self); let stm = Statement::from(self);
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::algorithm::{algorithm, Algorithm}; use crate::sql::algorithm::{algorithm, Algorithm};
use crate::sql::base::{base, base_or_scope, Base}; use crate::sql::base::{base, base_or_scope, Base};
@ -61,20 +62,26 @@ pub enum DefineStatement {
impl DefineStatement { impl DefineStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self { match self {
Self::Namespace(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).await, Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Function(ref v) => v.compute(ctx, opt).await, Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Login(ref v) => v.compute(ctx, opt).await, Self::Login(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Token(ref v) => v.compute(ctx, opt).await, Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Scope(ref v) => v.compute(ctx, opt).await, Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Param(ref v) => v.compute(ctx, opt).await, Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Table(ref v) => v.compute(ctx, opt).await, Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Event(ref v) => v.compute(ctx, opt).await, Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Field(ref v) => v.compute(ctx, opt).await, Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Index(ref v) => v.compute(ctx, opt).await, Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Analyzer(ref v) => v.compute(ctx, opt).await, Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
} }
} }
} }
@ -126,15 +133,19 @@ pub struct DefineNamespaceStatement {
impl DefineNamespaceStatement { impl DefineNamespaceStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// No need for NS/DB // No need for NS/DB
opt.needs(Level::Kv)?; opt.needs(Level::Kv)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Process the statement // Process the statement
let key = crate::key::ns::new(&self.name); let key = crate::key::ns::new(&self.name);
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
run.set(key, self).await?; run.set(key, self).await?;
@ -175,13 +186,17 @@ pub struct DefineDatabaseStatement {
impl DefineDatabaseStatement { impl DefineDatabaseStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected NS? // Selected NS?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -252,13 +267,17 @@ pub struct DefineFunctionStatement {
impl DefineFunctionStatement { impl DefineFunctionStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -330,13 +349,17 @@ pub struct DefineAnalyzerStatement {
} }
impl DefineAnalyzerStatement { impl DefineAnalyzerStatement {
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -400,15 +423,19 @@ pub struct DefineLoginStatement {
impl DefineLoginStatement { impl DefineLoginStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self.base { match self.base {
Base::Ns => { Base::Ns => {
// Selected DB? // Selected DB?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -423,8 +450,6 @@ impl DefineLoginStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -518,15 +543,19 @@ pub struct DefineTokenStatement {
impl DefineTokenStatement { impl DefineTokenStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match &self.base { match &self.base {
Base::Ns => { Base::Ns => {
// Selected DB? // Selected DB?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -541,8 +570,6 @@ impl DefineTokenStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -558,8 +585,6 @@ impl DefineTokenStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -633,13 +658,17 @@ pub struct DefineScopeStatement {
impl DefineScopeStatement { impl DefineScopeStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -747,13 +776,17 @@ pub struct DefineParamStatement {
impl DefineParamStatement { impl DefineParamStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -807,13 +840,17 @@ pub struct DefineTableStatement {
} }
impl DefineTableStatement { impl DefineTableStatement {
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -852,7 +889,7 @@ impl DefineTableStatement {
what: Values(vec![Value::Table(v.clone())]), what: Values(vec![Value::Table(v.clone())]),
..UpdateStatement::default() ..UpdateStatement::default()
}; };
stm.compute(ctx, opt).await?; stm.compute(ctx, opt, txn, doc).await?;
} }
} }
// Ok all good // Ok all good
@ -1006,13 +1043,17 @@ pub struct DefineEventStatement {
impl DefineEventStatement { impl DefineEventStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -1086,13 +1127,17 @@ pub struct DefineFieldStatement {
impl DefineFieldStatement { impl DefineFieldStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -1242,13 +1287,17 @@ pub struct DefineIndexStatement {
impl DefineIndexStatement { impl DefineIndexStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -1279,7 +1328,7 @@ impl DefineIndexStatement {
what: Values(vec![Value::Table(self.what.clone().into())]), what: Values(vec![Value::Table(self.what.clone().into())]),
..UpdateStatement::default() ..UpdateStatement::default()
}; };
stm.compute(ctx, opt).await?; stm.compute(ctx, opt, txn, doc).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::cond::{cond, Cond}; use crate::sql::cond::{cond, Cond};
@ -42,7 +43,13 @@ impl DeleteStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -53,7 +60,7 @@ impl DeleteStatement {
let opt = &opt.new_with_futures(false); let opt = &opt.new_with_futures(false);
// Loop over the delete targets // Loop over the delete targets
for w in self.what.0.iter() { 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 { match v {
Value::Table(v) => i.ingest(Iterable::Table(v)), Value::Table(v) => i.ingest(Iterable::Table(v)),
Value::Thing(v) => i.ingest(Iterable::Thing(v)), Value::Thing(v) => i.ingest(Iterable::Thing(v)),
@ -109,7 +116,7 @@ impl DeleteStatement {
// Assign the statement // Assign the statement
let stm = Statement::from(self); let stm = Statement::from(self);
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -29,15 +30,21 @@ impl IfelseStatement {
self.close.as_ref().map_or(false, |v| v.writeable()) self.close.as_ref().map_or(false, |v| v.writeable())
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
for (ref cond, ref then) in &self.exprs { 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() { if v.is_truthy() {
return then.compute(ctx, opt).await; return then.compute(ctx, opt, txn, doc).await;
} }
} }
match self.close { 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), None => Ok(Value::None),
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -24,7 +25,13 @@ pub enum InfoStatement {
impl InfoStatement { impl InfoStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Allowed to run? // Allowed to run?
match self { match self {
InfoStatement::Kv => { InfoStatement::Kv => {
@ -34,8 +41,6 @@ impl InfoStatement {
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Create the result set // Create the result set
let mut res = Object::default(); let mut res = Object::default();
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the statement // Process the statement
@ -52,8 +57,6 @@ impl InfoStatement {
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Create the result set // Create the result set
@ -84,8 +87,6 @@ impl InfoStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Create the result set // Create the result set
@ -140,8 +141,6 @@ impl InfoStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Create the result set // Create the result set
@ -160,8 +159,6 @@ impl InfoStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Create the result set // Create the result set

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::data::{single, update, values, Data}; use crate::sql::data::{single, update, values, Data};
@ -45,7 +46,13 @@ impl InsertStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -63,8 +70,8 @@ impl InsertStatement {
let mut o = Value::base(); let mut o = Value::base();
// Set each field from the expression // Set each field from the expression
for (k, v) in v.iter() { for (k, v) in v.iter() {
let v = v.compute(ctx, opt).await?; let v = v.compute(ctx, opt, txn, None).await?;
o.set(ctx, opt, k, v).await?; o.set(ctx, opt, txn, k, v).await?;
} }
// Specify the new table record id // Specify the new table record id
let id = o.rid().generate(&self.into, true)?; let id = o.rid().generate(&self.into, true)?;
@ -74,7 +81,7 @@ impl InsertStatement {
} }
// Check if this is a modern statement // Check if this is a modern statement
Data::SingleExpression(v) => { Data::SingleExpression(v) => {
let v = v.compute(ctx, opt).await?; let v = v.compute(ctx, opt, txn, doc).await?;
match v { match v {
Value::Array(v) => { Value::Array(v) => {
for v in v { for v in v {
@ -102,7 +109,7 @@ impl InsertStatement {
// Assign the statement // Assign the statement
let stm = Statement::from(self); let stm = Statement::from(self);
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -18,15 +19,19 @@ pub struct KillStatement {
impl KillStatement { impl KillStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Allowed to run? // Allowed to run?
opt.realtime()?; opt.realtime()?;
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::No)?; opt.check(Level::No)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Fetch the live query key // Fetch the live query key

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::cond::{cond, Cond}; use crate::sql::cond::{cond, Cond};
@ -32,19 +33,23 @@ pub struct LiveStatement {
impl LiveStatement { impl LiveStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Allowed to run? // Allowed to run?
opt.realtime()?; opt.realtime()?;
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::No)?; opt.check(Level::No)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Process the live query table // Process the live query table
match self.what.compute(ctx, opt).await? { match self.what.compute(ctx, opt, txn, doc).await? {
Value::Table(tb) => { Value::Table(tb) => {
// Clone the current statement // Clone the current statement
let mut stm = self.clone(); let mut stm = self.clone();

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
@ -24,15 +25,21 @@ impl OutputStatement {
self.what.writeable() self.what.writeable()
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Ensure futures are processed // Ensure futures are processed
let opt = &opt.new_with_futures(true); let opt = &opt.new_with_futures(true);
// Process the output value // 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 // Fetch any
if let Some(fetchs) = &self.fetch { if let Some(fetchs) = &self.fetch {
for fetch in fetchs.iter() { for fetch in fetchs.iter() {
val.fetch(ctx, opt, fetch).await?; val.fetch(ctx, opt, txn, fetch).await?;
} }
} }
// //

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::array::array; use crate::sql::array::array;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
@ -55,7 +56,13 @@ impl RelateStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -67,7 +74,7 @@ impl RelateStatement {
// Loop over the from targets // Loop over the from targets
let from = { let from = {
let mut out = Vec::new(); 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::Thing(v) => out.push(v),
Value::Array(v) => { Value::Array(v) => {
for v in v { for v in v {
@ -109,7 +116,7 @@ impl RelateStatement {
// Loop over the with targets // Loop over the with targets
let with = { let with = {
let mut out = Vec::new(); 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::Thing(v) => out.push(v),
Value::Array(v) => { Value::Array(v) => {
for v in v { for v in v {
@ -158,7 +165,7 @@ impl RelateStatement {
// The relation does not have a specific record id // The relation does not have a specific record id
Value::Table(tb) => match &self.data { Value::Table(tb) => match &self.data {
// There is a data clause so check for a record id // 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 // There was a problem creating the record id
Err(e) => return Err(e), Err(e) => return Err(e),
// There is an id field so use the record id // There is an id field so use the record id
@ -175,7 +182,7 @@ impl RelateStatement {
// Assign the statement // Assign the statement
let stm = Statement::from(self); let stm = Statement::from(self);
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::{Level, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::base::{base, base_or_scope, Base}; use crate::sql::base::{base, base_or_scope, Base};
use crate::sql::comment::{mightbespace, shouldbespace}; use crate::sql::comment::{mightbespace, shouldbespace};
@ -38,20 +39,26 @@ pub enum RemoveStatement {
impl RemoveStatement { impl RemoveStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
match self { match self {
Self::Namespace(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).await, Self::Database(ref v) => v.compute(ctx, opt, txn).await,
Self::Function(ref v) => v.compute(ctx, opt).await, Self::Function(ref v) => v.compute(ctx, opt, txn).await,
Self::Login(ref v) => v.compute(ctx, opt).await, Self::Login(ref v) => v.compute(ctx, opt, txn).await,
Self::Token(ref v) => v.compute(ctx, opt).await, Self::Token(ref v) => v.compute(ctx, opt, txn).await,
Self::Scope(ref v) => v.compute(ctx, opt).await, Self::Scope(ref v) => v.compute(ctx, opt, txn).await,
Self::Param(ref v) => v.compute(ctx, opt).await, Self::Param(ref v) => v.compute(ctx, opt, txn).await,
Self::Table(ref v) => v.compute(ctx, opt).await, Self::Table(ref v) => v.compute(ctx, opt, txn).await,
Self::Event(ref v) => v.compute(ctx, opt).await, Self::Event(ref v) => v.compute(ctx, opt, txn).await,
Self::Field(ref v) => v.compute(ctx, opt).await, Self::Field(ref v) => v.compute(ctx, opt, txn).await,
Self::Index(ref v) => v.compute(ctx, opt).await, Self::Index(ref v) => v.compute(ctx, opt, txn).await,
Self::Analyzer(ref v) => v.compute(ctx, opt).await, Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await,
} }
} }
} }
@ -103,13 +110,16 @@ pub struct RemoveNamespaceStatement {
impl RemoveNamespaceStatement { impl RemoveNamespaceStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// No need for NS/DB // No need for NS/DB
opt.needs(Level::Kv)?; opt.needs(Level::Kv)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -154,13 +164,16 @@ pub struct RemoveDatabaseStatement {
impl RemoveDatabaseStatement { impl RemoveDatabaseStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected NS? // Selected NS?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -205,13 +218,16 @@ pub struct RemoveFunctionStatement {
impl RemoveFunctionStatement { impl RemoveFunctionStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -260,13 +276,16 @@ pub struct RemoveAnalyzerStatement {
} }
impl RemoveAnalyzerStatement { impl RemoveAnalyzerStatement {
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -310,15 +329,18 @@ pub struct RemoveLoginStatement {
impl RemoveLoginStatement { impl RemoveLoginStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match self.base { match self.base {
Base::Ns => { Base::Ns => {
// Selected NS? // Selected NS?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -332,8 +354,6 @@ impl RemoveLoginStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -384,15 +404,18 @@ pub struct RemoveTokenStatement {
impl RemoveTokenStatement { impl RemoveTokenStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
match &self.base { match &self.base {
Base::Ns => { Base::Ns => {
// Selected NS? // Selected NS?
opt.needs(Level::Ns)?; opt.needs(Level::Ns)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Kv)?; opt.check(Level::Kv)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -406,8 +429,6 @@ impl RemoveTokenStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Ns)?; opt.check(Level::Ns)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -421,8 +442,6 @@ impl RemoveTokenStatement {
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -472,13 +491,16 @@ pub struct RemoveScopeStatement {
impl RemoveScopeStatement { impl RemoveScopeStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -523,13 +545,16 @@ pub struct RemoveParamStatement {
impl RemoveParamStatement { impl RemoveParamStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -572,13 +597,16 @@ pub struct RemoveTableStatement {
impl RemoveTableStatement { impl RemoveTableStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -624,13 +652,16 @@ pub struct RemoveEventStatement {
impl RemoveEventStatement { impl RemoveEventStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -682,13 +713,16 @@ pub struct RemoveFieldStatement {
impl RemoveFieldStatement { impl RemoveFieldStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition
@ -741,13 +775,16 @@ pub struct RemoveIndexStatement {
impl RemoveIndexStatement { impl RemoveIndexStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
opt.check(Level::Db)?; opt.check(Level::Db)?;
// Clone transaction
let txn = ctx.try_clone_transaction()?;
// Claim transaction // Claim transaction
let mut run = txn.lock().await; let mut run = txn.lock().await;
// Delete the definition // Delete the definition

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::idx::planner::QueryPlanner; use crate::idx::planner::QueryPlanner;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
@ -72,7 +73,13 @@ impl SelectStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -86,10 +93,10 @@ impl SelectStatement {
let mut planner = QueryPlanner::new(opt, &self.cond); let mut planner = QueryPlanner::new(opt, &self.cond);
// Loop over the select targets // Loop over the select targets
for w in self.what.0.iter() { 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 { match v {
Value::Table(t) => { 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::Thing(v) => i.ingest(Iterable::Thing(v)),
Value::Range(v) => i.ingest(Iterable::Range(*v)), Value::Range(v) => i.ingest(Iterable::Range(*v)),
@ -124,10 +131,10 @@ impl SelectStatement {
let mut ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
ctx.set_query_executors(ex); ctx.set_query_executors(ex);
// Output the results // Output the results
i.output(&ctx, opt, &stm).await i.output(&ctx, opt, txn, &stm).await
} else { } else {
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }
} }

View file

@ -1,5 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Transaction;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
@ -25,8 +27,14 @@ impl SetStatement {
self.what.writeable() self.what.writeable()
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
self.what.compute(ctx, opt).await &self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
self.what.compute(ctx, opt, txn, doc).await
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::common::take_u64; use crate::sql::common::take_u64;
@ -27,7 +28,12 @@ pub struct ShowStatement {
impl ShowStatement { impl ShowStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
_ctx: &Context<'_>,
_opt: &Options,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
Err(Error::FeatureNotYetImplemented { Err(Error::FeatureNotYetImplemented {
feature: "change feed", feature: "change feed",
}) })

View file

@ -1,6 +1,7 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::duration::duration; use crate::sql::duration::duration;
@ -18,7 +19,12 @@ pub struct SleepStatement {
impl SleepStatement { impl SleepStatement {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
_doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// No need for NS/DB // No need for NS/DB
opt.needs(Level::Kv)?; opt.needs(Level::Kv)?;
// Allowed to run? // Allowed to run?
@ -87,9 +93,9 @@ mod tests {
let sql = "SLEEP 500ms"; let sql = "SLEEP 500ms";
let time = SystemTime::now(); let time = SystemTime::now();
let opt = Options::default().with_auth(Arc::new(Auth::Kv)); let opt = Options::default().with_auth(Arc::new(Auth::Kv));
let (ctx, _) = mock().await; let (ctx, _, _) = mock().await;
let (_, stm) = sleep(sql).unwrap(); 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!(time.elapsed().unwrap() >= time::Duration::microseconds(500));
assert_eq!(value, Value::None); assert_eq!(value, Value::None);
} }

View file

@ -1,9 +1,10 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Iterable;
use crate::dbs::Iterator; use crate::dbs::Iterator;
use crate::dbs::Level; use crate::dbs::Level;
use crate::dbs::Options; use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::{Iterable, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::cond::{cond, Cond}; use crate::sql::cond::{cond, Cond};
@ -43,7 +44,13 @@ impl UpdateStatement {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Selected DB? // Selected DB?
opt.needs(Level::Db)?; opt.needs(Level::Db)?;
// Allowed to run? // Allowed to run?
@ -54,7 +61,7 @@ impl UpdateStatement {
let opt = &opt.new_with_futures(false); let opt = &opt.new_with_futures(false);
// Loop over the update targets // Loop over the update targets
for w in self.what.0.iter() { 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 { match v {
Value::Table(v) => i.ingest(Iterable::Table(v)), Value::Table(v) => i.ingest(Iterable::Table(v)),
Value::Thing(v) => i.ingest(Iterable::Thing(v)), Value::Thing(v) => i.ingest(Iterable::Thing(v)),
@ -110,7 +117,7 @@ impl UpdateStatement {
// Assign the statement // Assign the statement
let stm = Statement::from(self); let stm = Statement::from(self);
// Output the results // Output the results
i.output(ctx, opt, &stm).await i.output(ctx, opt, txn, &stm).await
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::common::{closeparentheses, openparentheses}; use crate::sql::common::{closeparentheses, openparentheses};
use crate::sql::ending::subquery as ending; use crate::sql::ending::subquery as ending;
@ -59,25 +60,31 @@ impl Subquery {
} }
} }
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
// Prevent deep recursion // Prevent deep recursion
let opt = &opt.dive(2)?; let opt = &opt.dive(2)?;
// Process the subquery // Process the subquery
match self { match self {
Self::Value(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).await, Self::Ifelse(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Output(ref v) => v.compute(ctx, opt).await, Self::Output(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Select(ref v) => { Self::Select(ref v) => {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result
@ -93,13 +100,13 @@ impl Subquery {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result
@ -115,13 +122,13 @@ impl Subquery {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result
@ -137,13 +144,13 @@ impl Subquery {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result
@ -159,13 +166,13 @@ impl Subquery {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result
@ -181,13 +188,13 @@ impl Subquery {
// Is this a single output? // Is this a single output?
let one = v.single(); let one = v.single();
// Duplicate context // Duplicate context
let mut child_ctx = Context::new(ctx); let mut ctx = Context::new(ctx);
// Add parent document // Add parent document
if let Some(doc) = ctx.doc() { if let Some(doc) = doc {
child_ctx.add_value("parent", doc); ctx.add_value("parent", doc.doc.as_ref());
} }
// Process subquery // Process subquery
match v.compute(&child_ctx, opt).await? { match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result // This is a single record result
Value::Array(mut a) if one => match a.len() { Value::Array(mut a) if one => match a.len() {
// There was at least one result // There was at least one result

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::escape::escape_rid; use crate::sql::escape::escape_rid;
@ -102,10 +103,16 @@ impl fmt::Display for Thing {
impl Thing { impl Thing {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
Ok(Value::Thing(Thing { Ok(Value::Thing(Thing {
tb: self.tb.clone(), tb: self.tb.clone(),
id: self.id.compute(ctx, opt).await?, id: self.id.compute(ctx, opt, txn, doc).await?,
})) }))
} }
} }

View file

@ -102,121 +102,121 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn del_none() { async fn del_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::default(); let idi = Idiom::default();
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_reset() { async fn del_reset() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ }"); let res = Value::parse("{ }");
val.del(&ctx, &opt, &idi).await.unwrap(); val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_basic() { async fn del_basic() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something"); let idi = Idiom::parse("test.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_wrong() { async fn del_wrong() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.wrong"); let idi = Idiom::parse("test.something.wrong");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_other() { async fn del_other() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other.something"); let idi = Idiom::parse("test.other.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array() { async fn del_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]"); let idi = Idiom::parse("test.something[1]");
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
let res = Value::parse("{ test: { something: [123, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_field() { 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 idi = Idiom::parse("test.something[1].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_fields() { async fn del_array_fields() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[*].age"); let idi = Idiom::parse("test.something[*].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_fields_flat() { 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 idi = Idiom::parse("test.something.age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_where_field() { 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 idi = Idiom::parse("test.something[WHERE age > 35].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_where_fields() { 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 idi = Idiom::parse("test.something[WHERE age > 35]");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,5 +1,5 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::err::Error; use crate::err::Error;
use crate::sql::number::Number; use crate::sql::number::Number;
use crate::sql::part::Part; use crate::sql::part::Part;
@ -11,21 +11,22 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
val: Value, val: Value,
) -> Result<(), Error> { ) -> 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(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(()), _ => Ok(()),
}, },
Value::Array(v) => match val { Value::Array(v) => match val {
Value::Array(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, path, Value::from(v - x)).await, x => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
}, },
Value::None => match val { Value::None => match val {
Value::Number(x) => { 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(()), _ => Ok(()),
}, },
@ -44,51 +45,51 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn decrement_none() { async fn decrement_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("other"); let idi = Idiom::parse("other");
let mut val = Value::parse("{ test: 100 }"); let mut val = Value::parse("{ test: 100 }");
let res = Value::parse("{ test: 100, other: -10 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn decrement_number() { async fn decrement_number() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: 100 }"); let mut val = Value::parse("{ test: 100 }");
let res = Value::parse("{ test: 90 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn decrement_array_number() { async fn decrement_array_number() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test[1]"); let idi = Idiom::parse("test[1]");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 190, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn decrement_array_value() { async fn decrement_array_value() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn decrement_array_array() { async fn decrement_array_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [200] }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::exe::try_join_all_buffered; use crate::exe::try_join_all_buffered;
use crate::sql::array::Abolish; use crate::sql::array::Abolish;
@ -17,6 +18,7 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
) -> Result<(), Error> { ) -> Result<(), Error> {
match path.first() { match path.first() {
@ -30,7 +32,7 @@ impl Value {
Ok(()) Ok(())
} }
_ => match v.get_mut(f.as_str()) { _ => 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(()), _ => Ok(()),
}, },
}, },
@ -40,7 +42,7 @@ impl Value {
Ok(()) Ok(())
} }
_ => match v.get_mut(&i.to_string()) { _ => 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(()), _ => Ok(()),
}, },
}, },
@ -55,7 +57,7 @@ impl Value {
} }
_ => { _ => {
let path = path.next(); 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?; try_join_all_buffered(futs).await?;
Ok(()) Ok(())
} }
@ -69,7 +71,7 @@ impl Value {
Ok(()) Ok(())
} }
_ => match v.first_mut() { _ => 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(()), None => Ok(()),
}, },
}, },
@ -82,7 +84,7 @@ impl Value {
Ok(()) Ok(())
} }
_ => match v.last_mut() { _ => 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(()), None => Ok(()),
}, },
}, },
@ -94,7 +96,7 @@ impl Value {
Ok(()) Ok(())
} }
_ => match v.get_mut(i.to_usize()) { _ => 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(()), None => Ok(()),
}, },
}, },
@ -104,9 +106,8 @@ impl Value {
// iterate in reverse, and call swap_remove // iterate in reverse, and call swap_remove
let mut m = HashSet::new(); let mut m = HashSet::new();
for (i, v) in v.iter().enumerate() { for (i, v) in v.iter().enumerate() {
let mut child_ctx = Context::new(ctx); let cur = CursorDoc::new(None, None, v);
child_ctx.add_cursor_doc(v); if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
if w.compute(&child_ctx, opt).await?.is_truthy() {
m.insert(i); m.insert(i);
}; };
} }
@ -116,17 +117,16 @@ impl Value {
_ => { _ => {
let path = path.next(); let path = path.next();
for v in v.iter_mut() { for v in v.iter_mut() {
let mut child_ctx = Context::new(ctx); let cur = CursorDoc::new(None, None, v);
child_ctx.add_cursor_doc(v); if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
if w.compute(&child_ctx, opt).await?.is_truthy() { v.del(ctx, opt, txn, path).await?;
v.del(ctx, opt, path).await?;
} }
} }
Ok(()) 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?; try_join_all_buffered(futs).await?;
Ok(()) Ok(())
} }
@ -150,121 +150,121 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn del_none() { async fn del_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::default(); let idi = Idiom::default();
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_reset() { async fn del_reset() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ }"); let res = Value::parse("{ }");
val.del(&ctx, &opt, &idi).await.unwrap(); val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_basic() { async fn del_basic() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something"); let idi = Idiom::parse("test.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_wrong() { async fn del_wrong() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.wrong"); let idi = Idiom::parse("test.something.wrong");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_other() { async fn del_other() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other.something"); let idi = Idiom::parse("test.other.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array() { async fn del_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]"); let idi = Idiom::parse("test.something[1]");
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
let res = Value::parse("{ test: { something: [123, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_field() { 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 idi = Idiom::parse("test.something[1].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_fields() { async fn del_array_fields() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[*].age"); let idi = Idiom::parse("test.something[*].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_fields_flat() { 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 idi = Idiom::parse("test.something.age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_where_field() { 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 idi = Idiom::parse("test.something[WHERE age > 35].age");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn del_array_where_fields() { 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 idi = Idiom::parse("test.something[WHERE age > 35]");
let mut val = Value::parse( let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }", "{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
); );
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,5 +1,5 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::err::Error; use crate::err::Error;
use crate::sql::array::Uniq; use crate::sql::array::Uniq;
use crate::sql::part::Part; use crate::sql::part::Part;
@ -10,17 +10,18 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
val: Value, val: Value,
) -> Result<(), Error> { ) -> 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(v) => match val {
Value::Array(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, 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::None => match val {
Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await, Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
x => self.set(ctx, opt, path, Value::from(vec![x])).await, x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
}, },
_ => Ok(()), _ => Ok(()),
} }
@ -37,21 +38,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn extend_array_value() { async fn extend_array_value() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn extend_array_array() { async fn extend_array_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 200, 300, 400, 500] }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::edges::Edges; use crate::sql::edges::Edges;
use crate::sql::field::{Field, Fields}; use crate::sql::field::{Field, Fields};
@ -17,6 +18,7 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
) -> Result<(), Error> { ) -> Result<(), Error> {
match path.first() { match path.first() {
@ -25,53 +27,52 @@ impl Value {
// Current path part is an object // Current path part is an object
Value::Object(v) => match p { Value::Object(v) => match p {
Part::Graph(_) => match v.rid() { 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(()), None => Ok(()),
}, },
Part::Field(f) => match v.get_mut(f as &str) { 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(()), None => Ok(()),
}, },
Part::Index(i) => match v.get_mut(&i.to_string()) { 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(()), None => Ok(()),
}, },
Part::All => self.fetch(ctx, opt, path.next()).await, Part::All => self.fetch(ctx, opt, txn, path.next()).await,
_ => Ok(()), _ => Ok(()),
}, },
// Current path part is an array // Current path part is an array
Value::Array(v) => match p { Value::Array(v) => match p {
Part::All => { Part::All => {
let path = path.next(); 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?; try_join_all(futs).await?;
Ok(()) Ok(())
} }
Part::First => match v.first_mut() { 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(()), None => Ok(()),
}, },
Part::Last => match v.last_mut() { 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(()), None => Ok(()),
}, },
Part::Index(i) => match v.get_mut(i.to_usize()) { 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(()), None => Ok(()),
}, },
Part::Where(w) => { Part::Where(w) => {
let path = path.next(); let path = path.next();
for v in v.iter_mut() { for v in v.iter_mut() {
let mut child_ctx = Context::new(ctx); let cur = CursorDoc::new(None, None, v);
child_ctx.add_cursor_doc(v); if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
if w.compute(&child_ctx, opt).await?.is_truthy() { v.fetch(ctx, opt, txn, path).await?;
v.fetch(ctx, opt, path).await?;
} }
} }
Ok(()) 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?; try_join_all(futs).await?;
Ok(()) Ok(())
} }
@ -95,10 +96,10 @@ impl Value {
..SelectStatement::default() ..SelectStatement::default()
}; };
*self = stm *self = stm
.compute(ctx, opt) .compute(ctx, opt, txn, None)
.await? .await?
.all() .all()
.get(ctx, opt, path.next()) .get(ctx, opt, txn, None, path.next())
.await? .await?
.flatten() .flatten()
.ok()?; .ok()?;
@ -111,7 +112,7 @@ impl Value {
what: Values(vec![Value::from(val)]), what: Values(vec![Value::from(val)]),
..SelectStatement::default() ..SelectStatement::default()
}; };
*self = stm.compute(ctx, opt).await?.first(); *self = stm.compute(ctx, opt, txn, None).await?.first();
Ok(()) Ok(())
} }
} }
@ -123,7 +124,7 @@ impl Value {
None => match self { None => match self {
// Current path part is an array // Current path part is an array
Value::Array(v) => { 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?; try_join_all(futs).await?;
Ok(()) Ok(())
} }
@ -137,7 +138,7 @@ impl Value {
what: Values(vec![Value::from(val)]), what: Values(vec![Value::from(val)]),
..SelectStatement::default() ..SelectStatement::default()
}; };
*self = stm.compute(ctx, opt).await?.first(); *self = stm.compute(ctx, opt, txn, None).await?.first();
Ok(()) Ok(())
} }
// Ignore everything else // Ignore everything else

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::exe::try_join_all_buffered; use crate::exe::try_join_all_buffered;
use crate::sql::edges::Edges; use crate::sql::edges::Edges;
@ -21,6 +22,8 @@ impl Value {
&self, &self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
doc: Option<&'async_recursion CursorDoc<'_>>,
path: &[Part], path: &[Part],
) -> Result<Self, Error> { ) -> Result<Self, Error> {
match path.first() { match path.first() {
@ -30,15 +33,15 @@ impl Value {
Value::Geometry(v) => match p { Value::Geometry(v) => match p {
// If this is the 'type' field then continue // If this is the 'type' field then continue
Part::Field(f) if f.is_type() => { 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 // If this is the 'coordinates' field then continue
Part::Field(f) if f.is_coordinates() && v.is_geometry() => { 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 // If this is the 'geometries' field then continue
Part::Field(f) if f.is_geometries() && v.is_collection() => { 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 // otherwise return none
_ => Ok(Value::None), _ => Ok(Value::None),
@ -54,9 +57,9 @@ impl Value {
// Ensure the future is processed // Ensure the future is processed
let fut = &opt.new_with_futures(true); let fut = &opt.new_with_futures(true);
// Get the future return value // 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 // 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 { Some(Value::Thing(Thing {
id: Id::Object(v), 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 { Some(Value::Thing(Thing {
id: Id::Array(v), id: Id::Array(v),
.. ..
})) => Value::Array(v.clone()).get(ctx, opt, path.next()).await, })) => Value::Array(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
Some(v) => v.get(ctx, opt, path.next()).await, Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
None => Ok(Value::None), None => Ok(Value::None),
}, },
Part::Graph(_) => match v.rid() { 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), None => Ok(Value::None),
}, },
Part::Field(f) => match v.get(f as &str) { 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), 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), _ => Ok(Value::None),
}, },
// Current path part is an array // Current path part is an array
Value::Array(v) => match p { Value::Array(v) => match p {
Part::All => { Part::All => {
let path = path.next(); 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) try_join_all_buffered(futs).await.map(Into::into)
} }
Part::First => match v.first() { 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), None => Ok(Value::None),
}, },
Part::Last => match v.last() { 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), None => Ok(Value::None),
}, },
Part::Index(i) => match v.get(i.to_usize()) { 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), None => Ok(Value::None),
}, },
Part::Where(w) => { Part::Where(w) => {
let path = path.next(); let path = path.next();
let mut a = Vec::new(); let mut a = Vec::new();
for v in v.iter() { for v in v.iter() {
let mut child_ctx = Context::new(ctx); let cur = Some(CursorDoc::new(None, None, v));
child_ctx.add_cursor_doc(v); if w.compute(ctx, opt, txn, cur.as_ref()).await?.is_truthy() {
if w.compute(&child_ctx, opt).await?.is_truthy() { a.push(v.get(ctx, opt, txn, cur.as_ref(), path).await?)
a.push(v.get(&child_ctx, opt, path).await?)
} }
} }
Ok(a.into()) 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) try_join_all_buffered(futs).await.map(Into::into)
} }
}, },
@ -137,7 +139,11 @@ impl Value {
what: Values(vec![Value::from(val)]), what: Values(vec![Value::from(val)]),
..SelectStatement::default() ..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() { match path.len() {
1 => stm 1 => stm
.compute(ctx, opt) .compute(ctx, opt, txn, None)
.await? .await?
.all() .all()
.get(ctx, opt, ID.as_ref()) .get(ctx, opt, txn, None, ID.as_ref())
.await? .await?
.flatten() .flatten()
.ok(), .ok(),
_ => stm _ => stm
.compute(ctx, opt) .compute(ctx, opt, txn, None)
.await? .await?
.all() .all()
.get(ctx, opt, path.next()) .get(ctx, opt, txn, None, path.next())
.await? .await?
.flatten() .flatten()
.ok(), .ok(),
@ -189,7 +195,11 @@ impl Value {
what: Values(vec![Value::from(val)]), what: Values(vec![Value::from(val)]),
..SelectStatement::default() ..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] #[tokio::test]
async fn get_none() { async fn get_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::default(); let idi = Idiom::default();
let val = Value::parse("{ test: { other: null, something: 123 } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn get_basic() { async fn get_basic() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something"); let idi = Idiom::parse("test.something");
let val = Value::parse("{ test: { other: null, something: 123 } }"); 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)); assert_eq!(res, Value::from(123));
} }
#[tokio::test] #[tokio::test]
async fn get_thing() { async fn get_thing() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other"); let idi = Idiom::parse("test.other");
let val = Value::parse("{ test: { other: test:tobie, something: 123 } }"); 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!( assert_eq!(
res, res,
Value::from(Thing { Value::from(Thing {
@ -248,19 +258,19 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn get_array() { async fn get_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]"); let idi = Idiom::parse("test.something[1]");
let val = Value::parse("{ test: { something: [123, 456, 789] } }"); 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)); assert_eq!(res, Value::from(456));
} }
#[tokio::test] #[tokio::test]
async fn get_array_thing() { async fn get_array_thing() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]"); let idi = Idiom::parse("test.something[1]");
let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }"); 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!( assert_eq!(
res, res,
Value::from(Thing { Value::from(Thing {
@ -272,46 +282,46 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn get_array_field() { 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 idi = Idiom::parse("test.something[1].age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); 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)); assert_eq!(res, Value::from(36));
} }
#[tokio::test] #[tokio::test]
async fn get_array_fields() { async fn get_array_fields() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[*].age"); let idi = Idiom::parse("test.something[*].age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); 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])); assert_eq!(res, Value::from(vec![34, 36]));
} }
#[tokio::test] #[tokio::test]
async fn get_array_fields_flat() { 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 idi = Idiom::parse("test.something.age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); 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])); assert_eq!(res, Value::from(vec![34, 36]));
} }
#[tokio::test] #[tokio::test]
async fn get_array_where_field() { 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 idi = Idiom::parse("test.something[WHERE age > 35].age");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); 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])); assert_eq!(res, Value::from(vec![36]));
} }
#[tokio::test] #[tokio::test]
async fn get_array_where_fields() { 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 idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); 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!( assert_eq!(
res, res,
Value::from(vec![Value::from(map! { Value::from(vec![Value::from(map! {
@ -322,10 +332,10 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn get_future_embedded_field() { 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 idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: <future> { { something: [{ age: 34 }, { age: 36 }] } } }"); let val = Value::parse("{ test: <future> { { 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!( assert_eq!(
res, res,
Value::from(vec![Value::from(map! { Value::from(vec![Value::from(map! {
@ -336,12 +346,12 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn get_future_embedded_field_with_reference() { 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 doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }");
let idi = Idiom::parse("test.something[WHERE age > 35]"); let idi = Idiom::parse("test.something[WHERE age > 35]");
let val = Value::parse("{ test: <future> { { something: something } } }"); let val = Value::parse("{ test: <future> { { something: something } } }");
ctx.add_cursor_doc(&doc); let cur = CursorDoc::new(None, None, &doc);
let res = val.get(&ctx, &opt, &idi).await.unwrap(); let res = val.get(&ctx, &opt, &txn, Some(&cur), &idi).await.unwrap();
assert_eq!( assert_eq!(
res, res,
Value::from(vec![Value::from(map! { Value::from(vec![Value::from(map! {

View file

@ -1,5 +1,5 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::err::Error; use crate::err::Error;
use crate::sql::number::Number; use crate::sql::number::Number;
use crate::sql::part::Part; use crate::sql::part::Part;
@ -11,24 +11,25 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
val: Value, val: Value,
) -> Result<(), Error> { ) -> 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(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(()), _ => Ok(()),
}, },
Value::Array(v) => match val { Value::Array(v) => match val {
Value::Array(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, path, Value::from(v + x)).await, x => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
}, },
Value::None => match val { Value::None => match val {
Value::Number(x) => { 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, Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
x => self.set(ctx, opt, path, Value::from(vec![x])).await, x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
}, },
_ => Ok(()), _ => Ok(()),
} }
@ -45,51 +46,51 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn increment_none() { async fn increment_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("other"); let idi = Idiom::parse("other");
let mut val = Value::parse("{ test: 100 }"); let mut val = Value::parse("{ test: 100 }");
let res = Value::parse("{ test: 100, other: +10 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn increment_number() { async fn increment_number() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: 100 }"); let mut val = Value::parse("{ test: 100 }");
let res = Value::parse("{ test: 110 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn increment_array_number() { async fn increment_array_number() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test[1]"); let idi = Idiom::parse("test[1]");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 210, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn increment_array_value() { async fn increment_array_value() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 200, 300, 200] }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn increment_array_array() { async fn increment_array_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: [100, 200, 300] }"); let mut val = Value::parse("{ test: [100, 200, 300] }");
let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,5 +1,6 @@
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::exe::try_join_all_buffered; use crate::exe::try_join_all_buffered;
use crate::sql::part::Next; use crate::sql::part::Next;
@ -15,6 +16,7 @@ impl Value {
&mut self, &mut self,
ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction,
path: &[Part], path: &[Part],
val: Value, val: Value,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -24,28 +26,28 @@ impl Value {
// Current path part is an object // Current path part is an object
Value::Object(v) => match p { Value::Object(v) => match p {
Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) { 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(); 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); v.insert(g.to_raw(), obj);
Ok(()) Ok(())
} }
}, },
Part::Field(f) => match v.get_mut(f as &str) { 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(); 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); v.insert(f.to_raw(), obj);
Ok(()) Ok(())
} }
}, },
Part::Index(i) => match v.get_mut(&i.to_string()) { 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(); 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); v.insert(i.to_string(), obj);
Ok(()) Ok(())
} }
@ -56,35 +58,34 @@ impl Value {
Value::Array(v) => match p { Value::Array(v) => match p {
Part::All => { Part::All => {
let path = path.next(); 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?; try_join_all_buffered(futs).await?;
Ok(()) Ok(())
} }
Part::First => match v.first_mut() { 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(()), None => Ok(()),
}, },
Part::Last => match v.last_mut() { 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(()), None => Ok(()),
}, },
Part::Index(i) => match v.get_mut(i.to_usize()) { 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(()), None => Ok(()),
}, },
Part::Where(w) => { Part::Where(w) => {
let path = path.next(); let path = path.next();
for v in v.iter_mut() { for v in v.iter_mut() {
let mut child_ctx = Context::new(ctx); let cur = CursorDoc::new(None, None, v);
child_ctx.add_cursor_doc(v); if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
if w.compute(&child_ctx, opt).await?.is_truthy() { v.set(ctx, opt, txn, path, val.clone()).await?;
v.set(ctx, opt, path, val.clone()).await?;
} }
} }
Ok(()) 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?; try_join_all_buffered(futs).await?;
Ok(()) Ok(())
} }
@ -92,12 +93,12 @@ impl Value {
// Current path part is empty // Current path part is empty
Value::Null => { Value::Null => {
*self = Value::base(); *self = Value::base();
self.set(ctx, opt, path, val).await self.set(ctx, opt, txn, path, val).await
} }
// Current path part is empty // Current path part is empty
Value::None => { Value::None => {
*self = Value::base(); *self = Value::base();
self.set(ctx, opt, path, val).await self.set(ctx, opt, txn, path, val).await
} }
// Ignore everything else // Ignore everything else
_ => Ok(()), _ => Ok(()),
@ -121,141 +122,141 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn set_none() { async fn set_none() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::default(); let idi = Idiom::default();
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("999"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_empty() { async fn set_empty() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::None; let mut val = Value::None;
let res = Value::parse("{ test: 999 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_blank() { async fn set_blank() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something"); let idi = Idiom::parse("test.something");
let mut val = Value::None; let mut val = Value::None;
let res = Value::parse("{ test: { something: 999 } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_reset() { async fn set_reset() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test"); let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: 999 }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_basic() { async fn set_basic() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something"); let idi = Idiom::parse("test.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null, something: 999 } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_allow() { async fn set_allow() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.allow"); let idi = Idiom::parse("test.something.allow");
let mut val = Value::parse("{ test: { other: null } }"); let mut val = Value::parse("{ test: { other: null } }");
let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_wrong() { async fn set_wrong() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.wrong"); let idi = Idiom::parse("test.something.wrong");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_other() { async fn set_other() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other.something"); let idi = Idiom::parse("test.other.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: { something: 999 }, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array() { async fn set_array() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]"); let idi = Idiom::parse("test.something[1]");
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }"); let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
let res = Value::parse("{ test: { something: [123, 999, 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array_field() { 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 idi = Idiom::parse("test.something[1].age");
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array_fields() { async fn set_array_fields() {
let (ctx, opt) = mock().await; let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[*].age"); let idi = Idiom::parse("test.something[*].age");
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array_fields_flat() { 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 idi = Idiom::parse("test.something.age");
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array_where_field() { 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 idi = Idiom::parse("test.something[WHERE age > 35].age");
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }"); 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); assert_eq!(res, val);
} }
#[tokio::test] #[tokio::test]
async fn set_array_where_fields() { 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 idi = Idiom::parse("test.something[WHERE age > 35]");
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
let res = Value::parse("{ test: { something: [{ age: 34 }, 21] } }"); 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); assert_eq!(res, val);
} }
} }

View file

@ -1,7 +1,8 @@
#![allow(clippy::derive_ord_xor_partial_ord)] #![allow(clippy::derive_ord_xor_partial_ord)]
use crate::ctx::Context; use crate::ctx::Context;
use crate::dbs::Options; use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error; use crate::err::Error;
use crate::sql::array::Uniq; use crate::sql::array::Uniq;
use crate::sql::array::{array, Array}; use crate::sql::array::{array, Array};
@ -2484,21 +2485,27 @@ impl Value {
/// Process this type returning a computed simple Value /// Process this type returning a computed simple Value
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))] #[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> { pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&'async_recursion CursorDoc<'_>>,
) -> Result<Value, Error> {
match self { match self {
Value::Cast(v) => v.compute(ctx, opt).await, Value::Cast(v) => v.compute(ctx, opt, txn, doc).await,
Value::Thing(v) => v.compute(ctx, opt).await, Value::Thing(v) => v.compute(ctx, opt, txn, doc).await,
Value::Block(v) => v.compute(ctx, opt).await, Value::Block(v) => v.compute(ctx, opt, txn, doc).await,
Value::Range(v) => v.compute(ctx, opt).await, Value::Range(v) => v.compute(ctx, opt, txn, doc).await,
Value::Param(v) => v.compute(ctx, opt).await, Value::Param(v) => v.compute(ctx, opt, txn, doc).await,
Value::Idiom(v) => v.compute(ctx, opt).await, Value::Idiom(v) => v.compute(ctx, opt, txn, doc).await,
Value::Array(v) => v.compute(ctx, opt).await, Value::Array(v) => v.compute(ctx, opt, txn, doc).await,
Value::Object(v) => v.compute(ctx, opt).await, Value::Object(v) => v.compute(ctx, opt, txn, doc).await,
Value::Future(v) => v.compute(ctx, opt).await, Value::Future(v) => v.compute(ctx, opt, txn, doc).await,
Value::Constant(v) => v.compute(ctx, opt).await, Value::Constant(v) => v.compute(ctx, opt, txn, doc).await,
Value::Function(v) => v.compute(ctx, opt).await, Value::Function(v) => v.compute(ctx, opt, txn, doc).await,
Value::Subquery(v) => v.compute(ctx, opt).await, Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await,
Value::Expression(v) => v.compute(ctx, opt).await, Value::Expression(v) => v.compute(ctx, opt, txn, doc).await,
_ => Ok(self.to_owned()), _ => Ok(self.to_owned()),
} }
} }

View file

@ -92,14 +92,20 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error
Ok(()) Ok(())
} }
#[tokio::test] async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(), Error> {
async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> { let sql = format!(
let sql = r" r"
CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr']; CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr'];
DEFINE ANALYZER simple TOKENIZERS blank,class; DEFINE ANALYZER simple TOKENIZERS blank,class;
DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS; DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS;
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' EXPLAIN; SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {} EXPLAIN;
"; ",
if parallel {
"PARALLEL"
} else {
""
}
);
let dbs = Datastore::new("memory").await?; let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test"); let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None).await?; 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(()) 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] #[tokio::test]
async fn select_where_matches_using_index_offsets() -> Result<(), Error> { async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
let sql = r" let sql = r"