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-executor",
"async-recursion",
"async-trait",
"base64 0.21.2",
"bcrypt",
"bincode",

View file

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

View file

@ -1,12 +1,8 @@
use crate::ctx::canceller::Canceller;
use crate::ctx::reason::Reason;
use crate::dbs::Notification;
use crate::dbs::Transaction;
use crate::err::Error;
use crate::idx::ft::docids::DocId;
use crate::idx::planner::executor::QueryExecutor;
use crate::sql::value::Value;
use crate::sql::Thing;
use channel::Sender;
use std::borrow::Cow;
use std::collections::HashMap;
@ -36,18 +32,10 @@ pub struct Context<'a> {
cancelled: Arc<AtomicBool>,
// A collection of read only values stored in this context.
values: HashMap<Cow<'static, str>, Cow<'a, Value>>,
// Stores the current transaction if available
transaction: Option<Transaction>,
// Stores the notification channel if available
notifications: Option<Sender<Notification>>,
// An optional query executor
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> {
@ -63,8 +51,6 @@ impl<'a> Debug for Context<'a> {
.field("deadline", &self.deadline)
.field("cancelled", &self.cancelled)
.field("values", &self.values)
.field("thing", &self.thing)
.field("doc", &self.cursor_doc)
.finish()
}
}
@ -77,12 +63,8 @@ impl<'a> Context<'a> {
parent: None,
deadline: None,
cancelled: Arc::new(AtomicBool::new(false)),
transaction: None,
notifications: None,
query_executors: None,
thing: None,
doc_id: None,
cursor_doc: None,
}
}
@ -93,12 +75,8 @@ impl<'a> Context<'a> {
parent: Some(parent),
deadline: parent.deadline,
cancelled: Arc::new(AtomicBool::new(false)),
transaction: parent.transaction.clone(),
notifications: parent.notifications.clone(),
query_executors: parent.query_executors.clone(),
thing: parent.thing,
doc_id: parent.doc_id,
cursor_doc: parent.cursor_doc,
}
}
@ -134,34 +112,12 @@ impl<'a> Context<'a> {
self.add_deadline(Instant::now() + timeout)
}
/// Add the current transaction to the context, so that it can be fetched
/// where necessary, including inside the query planner.
pub fn add_transaction(&mut self, txn: Option<&Transaction>) {
self.transaction = txn.cloned()
}
/// Add the LIVE query notification channel to the context, so that we
/// can send notifications to any subscribers.
pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) {
self.notifications = chn.cloned()
}
/// Add a cursor document to this context.
/// Usage: A new child context is created by an iterator for each document.
/// The iterator sets the value of the current document (known as cursor document).
/// The cursor document is copied do the child contexts.
pub fn add_cursor_doc(&mut self, doc: &'a Value) {
self.cursor_doc = Some(doc);
}
pub fn add_thing(&mut self, thing: &'a Thing) {
self.thing = Some(thing);
}
pub fn add_doc_id(&mut self, doc_id: DocId) {
self.doc_id = Some(doc_id);
}
/// Set the query executors
pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) {
self.query_executors = Some(Arc::new(executors));
@ -173,28 +129,10 @@ impl<'a> Context<'a> {
self.deadline.map(|v| v.saturating_duration_since(Instant::now()))
}
/// Returns a transaction if any.
/// Otherwise it fails by returning a Error::NoTx error.
pub fn try_clone_transaction(&self) -> Result<Transaction, Error> {
self.transaction.clone().ok_or(Error::Unreachable)
}
pub fn notifications(&self) -> Option<Sender<Notification>> {
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> {
if let Some(qe) = &self.query_executors {
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
/// - true if a new transaction has begun
/// - false if
@ -275,10 +279,7 @@ impl<'a> Executor<'a> {
// Check if the variable is a protected variable
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
// The variable isn't protected and can be stored
false => {
ctx.add_transaction(self.txn.as_ref());
stm.compute(&ctx, &opt).await
}
false => stm.compute(&ctx, &opt, &self.txn(), None).await,
// The user tried to set a protected variable
true => Err(Error::InvalidParam {
// Move the parameter name, as we no longer need it
@ -338,16 +339,15 @@ impl<'a> Executor<'a> {
true => Err(Error::TxFailure),
// The transaction began successfully
false => {
let mut ctx = Context::new(&ctx);
// Process the statement
let res = match stm.timeout() {
// There is a timeout clause
Some(timeout) => {
// Set statement timeout
let mut ctx = Context::new(&ctx);
ctx.add_timeout(timeout);
ctx.add_transaction(self.txn.as_ref());
// Process the statement
let res = stm.compute(&ctx, &opt).await;
let res = stm.compute(&ctx, &opt, &self.txn(), None).await;
// Catch statement timeout
match ctx.is_timedout() {
true => Err(Error::QueryTimedout),
@ -355,10 +355,7 @@ impl<'a> Executor<'a> {
}
}
// There is no timeout clause
None => {
ctx.add_transaction(self.txn.as_ref());
stm.compute(&ctx, &opt).await
}
None => stm.compute(&ctx, &opt, &self.txn(), None).await,
};
// Catch global timeout
let res = match ctx.is_timedout() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,7 @@
//! Executes functions from SQL. If there is an SQL function it will be defined in this module.
use crate::ctx::Context;
use crate::dbs::Transaction;
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::value::Value;
@ -29,7 +31,13 @@ pub mod r#type;
pub mod util;
/// Attempts to run any function
pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<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")
|| name.starts_with("search")
|| 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::scrypt")
{
asynchronous(ctx, name, args).await
asynchronous(ctx, Some(txn), doc, name, args).await
} else {
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.
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
// perform a function call.
#[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::delete" => http::delete(ctx).await,
//
"search::score" => search::score(ctx).await,
"search::highlight" => search::highlight(ctx).await,
"search::offsets" => search::offsets(ctx).await,
"search::score" => search::score((ctx, txn, doc)).await,
"search::highlight" => search::highlight((ctx,txn, doc)).await,
"search::offsets" => search::offsets((ctx, txn, doc)).await,
//
"sleep" => sleep::sleep(ctx).await,
)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
use crate::err::Error;
use crate::idx::bkeys::TrieKeys;
use crate::idx::btree::{BTree, KeyProvider, NodeId, Payload, Statistics};
use crate::idx::btree::{BTree, KeyProvider, Payload, Statistics};
use crate::idx::ft::docids::DocId;
use crate::idx::{btree, IndexKeyBase, SerdeState};
use crate::kvs::{Key, Transaction};
@ -9,7 +9,7 @@ pub(super) type DocLength = u64;
pub(super) struct DocLengths {
state_key: Key,
btree: BTree<DocLengthsKeyProvider>,
btree: BTree,
}
impl DocLengths {
@ -18,9 +18,7 @@ impl DocLengths {
index_key_base: IndexKeyBase,
default_btree_order: u32,
) -> Result<Self, Error> {
let keys = DocLengthsKeyProvider {
index_key_base,
};
let keys = KeyProvider::DocLengths(index_key_base);
let state_key: Key = keys.get_state_key();
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
btree::State::try_from_val(val)?
@ -70,21 +68,6 @@ impl DocLengths {
}
}
#[derive(Clone)]
struct DocLengthsKeyProvider {
index_key_base: IndexKeyBase,
}
impl KeyProvider for DocLengthsKeyProvider {
fn get_node_key(&self, node_id: NodeId) -> Key {
self.index_key_base.new_bl_key(Some(node_id))
}
fn get_state_key(&self) -> Key {
self.index_key_base.new_bl_key(None)
}
}
#[cfg(test)]
mod tests {
use crate::idx::ft::doclength::DocLengths;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -79,7 +79,7 @@ impl<'a> TreeBuilder<'a> {
Value::Bool(_) => Node::Scalar(v.to_owned()),
Value::Subquery(s) => self.eval_subquery(s).await?,
Value::Param(p) => {
let v = p.compute(self.ctx, self.opt).await?;
let v = p.compute(self.ctx, self.opt, self.txn, None).await?;
self.eval_value(&v).await?
}
_ => Node::Unsupported,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::block::{block, Block};
use crate::sql::comment::mightbespace;
@ -24,12 +25,18 @@ impl From<Value> for Future {
impl Future {
/// 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
let opt = &opt.dive(1)?;
// Process the future if enabled
match opt.futures {
true => self.0.compute(ctx, opt).await?.ok(),
true => self.0.compute(ctx, opt, txn, doc).await?.ok(),
false => Ok(self.clone().into()),
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::{Options, Transaction};
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::error::IResult;
use crate::sql::escape::escape_rid;
@ -102,10 +103,16 @@ impl fmt::Display for Thing {
impl Thing {
/// Process this type returning a computed simple Value
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
pub(crate) async fn compute(
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&CursorDoc<'_>>,
) -> Result<Value, Error> {
Ok(Value::Thing(Thing {
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]
async fn del_none() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::default();
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null, something: 123 } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_reset() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test");
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_basic() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_wrong() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.wrong");
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null, something: 123 } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_other() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.other.something");
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
let res = Value::parse("{ test: { other: null, something: 123 } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1]");
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
let res = Value::parse("{ test: { something: [123, 789] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array_field() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[1].age");
let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
);
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array_fields() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[*].age");
let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
);
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array_fields_flat() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something.age");
let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
);
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array_where_field() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[WHERE age > 35].age");
let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
);
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
#[tokio::test]
async fn del_array_where_fields() {
let (ctx, opt) = mock().await;
let (ctx, opt, txn) = mock().await;
let idi = Idiom::parse("test.something[WHERE age > 35]");
let mut val = Value::parse(
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
);
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
val.del(&ctx, &opt, &idi).await.unwrap();
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
assert_eq!(res, val);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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