QueryPlanner / indexing / Context / Cursor doc (#2229)
This commit is contained in:
parent
4b690c763b
commit
e9eeb9aca7
97 changed files with 1624 additions and 1817 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4523,7 +4523,6 @@ dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-trait",
|
|
||||||
"base64 0.21.2",
|
"base64 0.21.2",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
|
|
@ -54,7 +54,6 @@ targets = []
|
||||||
addr = { version = "0.15.6", default-features = false, features = ["std"] }
|
addr = { version = "0.15.6", default-features = false, features = ["std"] }
|
||||||
argon2 = "0.5.0"
|
argon2 = "0.5.0"
|
||||||
ascii = { version = "0.3.2", package = "any_ascii" }
|
ascii = { version = "0.3.2", package = "any_ascii" }
|
||||||
async-trait = "0.1.69"
|
|
||||||
async-recursion = "1.0.4"
|
async-recursion = "1.0.4"
|
||||||
base64_lib = { version = "0.21.2", package = "base64" }
|
base64_lib = { version = "0.21.2", package = "base64" }
|
||||||
bcrypt = "0.14.0"
|
bcrypt = "0.14.0"
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
use crate::ctx::canceller::Canceller;
|
use crate::ctx::canceller::Canceller;
|
||||||
use crate::ctx::reason::Reason;
|
use crate::ctx::reason::Reason;
|
||||||
use crate::dbs::Notification;
|
use crate::dbs::Notification;
|
||||||
use crate::dbs::Transaction;
|
|
||||||
use crate::err::Error;
|
|
||||||
use crate::idx::ft::docids::DocId;
|
|
||||||
use crate::idx::planner::executor::QueryExecutor;
|
use crate::idx::planner::executor::QueryExecutor;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use crate::sql::Thing;
|
|
||||||
use channel::Sender;
|
use channel::Sender;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -36,18 +32,10 @@ pub struct Context<'a> {
|
||||||
cancelled: Arc<AtomicBool>,
|
cancelled: Arc<AtomicBool>,
|
||||||
// A collection of read only values stored in this context.
|
// A collection of read only values stored in this context.
|
||||||
values: HashMap<Cow<'static, str>, Cow<'a, Value>>,
|
values: HashMap<Cow<'static, str>, Cow<'a, Value>>,
|
||||||
// Stores the current transaction if available
|
|
||||||
transaction: Option<Transaction>,
|
|
||||||
// Stores the notification channel if available
|
// Stores the notification channel if available
|
||||||
notifications: Option<Sender<Notification>>,
|
notifications: Option<Sender<Notification>>,
|
||||||
// An optional query executor
|
// An optional query executor
|
||||||
query_executors: Option<Arc<HashMap<String, QueryExecutor>>>,
|
query_executors: Option<Arc<HashMap<String, QueryExecutor>>>,
|
||||||
// An optional record id
|
|
||||||
thing: Option<&'a Thing>,
|
|
||||||
// An optional doc id
|
|
||||||
doc_id: Option<DocId>,
|
|
||||||
// An optional cursor document
|
|
||||||
cursor_doc: Option<&'a Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Context<'a> {
|
impl<'a> Default for Context<'a> {
|
||||||
|
@ -63,8 +51,6 @@ impl<'a> Debug for Context<'a> {
|
||||||
.field("deadline", &self.deadline)
|
.field("deadline", &self.deadline)
|
||||||
.field("cancelled", &self.cancelled)
|
.field("cancelled", &self.cancelled)
|
||||||
.field("values", &self.values)
|
.field("values", &self.values)
|
||||||
.field("thing", &self.thing)
|
|
||||||
.field("doc", &self.cursor_doc)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,12 +63,8 @@ impl<'a> Context<'a> {
|
||||||
parent: None,
|
parent: None,
|
||||||
deadline: None,
|
deadline: None,
|
||||||
cancelled: Arc::new(AtomicBool::new(false)),
|
cancelled: Arc::new(AtomicBool::new(false)),
|
||||||
transaction: None,
|
|
||||||
notifications: None,
|
notifications: None,
|
||||||
query_executors: None,
|
query_executors: None,
|
||||||
thing: None,
|
|
||||||
doc_id: None,
|
|
||||||
cursor_doc: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,12 +75,8 @@ impl<'a> Context<'a> {
|
||||||
parent: Some(parent),
|
parent: Some(parent),
|
||||||
deadline: parent.deadline,
|
deadline: parent.deadline,
|
||||||
cancelled: Arc::new(AtomicBool::new(false)),
|
cancelled: Arc::new(AtomicBool::new(false)),
|
||||||
transaction: parent.transaction.clone(),
|
|
||||||
notifications: parent.notifications.clone(),
|
notifications: parent.notifications.clone(),
|
||||||
query_executors: parent.query_executors.clone(),
|
query_executors: parent.query_executors.clone(),
|
||||||
thing: parent.thing,
|
|
||||||
doc_id: parent.doc_id,
|
|
||||||
cursor_doc: parent.cursor_doc,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,34 +112,12 @@ impl<'a> Context<'a> {
|
||||||
self.add_deadline(Instant::now() + timeout)
|
self.add_deadline(Instant::now() + timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the current transaction to the context, so that it can be fetched
|
|
||||||
/// where necessary, including inside the query planner.
|
|
||||||
pub fn add_transaction(&mut self, txn: Option<&Transaction>) {
|
|
||||||
self.transaction = txn.cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add the LIVE query notification channel to the context, so that we
|
/// Add the LIVE query notification channel to the context, so that we
|
||||||
/// can send notifications to any subscribers.
|
/// can send notifications to any subscribers.
|
||||||
pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) {
|
pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) {
|
||||||
self.notifications = chn.cloned()
|
self.notifications = chn.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a cursor document to this context.
|
|
||||||
/// Usage: A new child context is created by an iterator for each document.
|
|
||||||
/// The iterator sets the value of the current document (known as cursor document).
|
|
||||||
/// The cursor document is copied do the child contexts.
|
|
||||||
pub fn add_cursor_doc(&mut self, doc: &'a Value) {
|
|
||||||
self.cursor_doc = Some(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_thing(&mut self, thing: &'a Thing) {
|
|
||||||
self.thing = Some(thing);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_doc_id(&mut self, doc_id: DocId) {
|
|
||||||
self.doc_id = Some(doc_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the query executors
|
/// Set the query executors
|
||||||
pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) {
|
pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) {
|
||||||
self.query_executors = Some(Arc::new(executors));
|
self.query_executors = Some(Arc::new(executors));
|
||||||
|
@ -173,28 +129,10 @@ impl<'a> Context<'a> {
|
||||||
self.deadline.map(|v| v.saturating_duration_since(Instant::now()))
|
self.deadline.map(|v| v.saturating_duration_since(Instant::now()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a transaction if any.
|
|
||||||
/// Otherwise it fails by returning a Error::NoTx error.
|
|
||||||
pub fn try_clone_transaction(&self) -> Result<Transaction, Error> {
|
|
||||||
self.transaction.clone().ok_or(Error::Unreachable)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn notifications(&self) -> Option<Sender<Notification>> {
|
pub fn notifications(&self) -> Option<Sender<Notification>> {
|
||||||
self.notifications.clone()
|
self.notifications.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thing(&self) -> Option<&Thing> {
|
|
||||||
self.thing
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn doc_id(&self) -> Option<DocId> {
|
|
||||||
self.doc_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn doc(&self) -> Option<&Value> {
|
|
||||||
self.cursor_doc
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> {
|
pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> {
|
||||||
if let Some(qe) = &self.query_executors {
|
if let Some(qe) = &self.query_executors {
|
||||||
qe.get(tb)
|
qe.get(tb)
|
||||||
|
|
|
@ -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(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -34,6 +34,10 @@ impl<'a> Executor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn txn(&self) -> Transaction {
|
||||||
|
self.txn.clone().expect("unreachable: txn was None after successful begin")
|
||||||
|
}
|
||||||
|
|
||||||
/// # Return
|
/// # Return
|
||||||
/// - true if a new transaction has begun
|
/// - true if a new transaction has begun
|
||||||
/// - false if
|
/// - false if
|
||||||
|
@ -275,10 +279,7 @@ impl<'a> Executor<'a> {
|
||||||
// Check if the variable is a protected variable
|
// Check if the variable is a protected variable
|
||||||
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
|
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
|
||||||
// The variable isn't protected and can be stored
|
// The variable isn't protected and can be stored
|
||||||
false => {
|
false => stm.compute(&ctx, &opt, &self.txn(), None).await,
|
||||||
ctx.add_transaction(self.txn.as_ref());
|
|
||||||
stm.compute(&ctx, &opt).await
|
|
||||||
}
|
|
||||||
// The user tried to set a protected variable
|
// The user tried to set a protected variable
|
||||||
true => Err(Error::InvalidParam {
|
true => Err(Error::InvalidParam {
|
||||||
// Move the parameter name, as we no longer need it
|
// Move the parameter name, as we no longer need it
|
||||||
|
@ -338,16 +339,15 @@ impl<'a> Executor<'a> {
|
||||||
true => Err(Error::TxFailure),
|
true => Err(Error::TxFailure),
|
||||||
// The transaction began successfully
|
// The transaction began successfully
|
||||||
false => {
|
false => {
|
||||||
|
let mut ctx = Context::new(&ctx);
|
||||||
// Process the statement
|
// Process the statement
|
||||||
let res = match stm.timeout() {
|
let res = match stm.timeout() {
|
||||||
// There is a timeout clause
|
// There is a timeout clause
|
||||||
Some(timeout) => {
|
Some(timeout) => {
|
||||||
// Set statement timeout
|
// Set statement timeout
|
||||||
let mut ctx = Context::new(&ctx);
|
|
||||||
ctx.add_timeout(timeout);
|
ctx.add_timeout(timeout);
|
||||||
ctx.add_transaction(self.txn.as_ref());
|
|
||||||
// Process the statement
|
// Process the statement
|
||||||
let res = stm.compute(&ctx, &opt).await;
|
let res = stm.compute(&ctx, &opt, &self.txn(), None).await;
|
||||||
// Catch statement timeout
|
// Catch statement timeout
|
||||||
match ctx.is_timedout() {
|
match ctx.is_timedout() {
|
||||||
true => Err(Error::QueryTimedout),
|
true => Err(Error::QueryTimedout),
|
||||||
|
@ -355,10 +355,7 @@ impl<'a> Executor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// There is no timeout clause
|
// There is no timeout clause
|
||||||
None => {
|
None => stm.compute(&ctx, &opt, &self.txn(), None).await,
|
||||||
ctx.add_transaction(self.txn.as_ref());
|
|
||||||
stm.compute(&ctx, &opt).await
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// Catch global timeout
|
// Catch global timeout
|
||||||
let res = match ctx.is_timedout() {
|
let res = match ctx.is_timedout() {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::ctx::Canceller;
|
use crate::ctx::Canceller;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::idx::planner::plan::Plan;
|
use crate::idx::planner::plan::Plan;
|
||||||
use crate::sql::array::Array;
|
use crate::sql::array::Array;
|
||||||
use crate::sql::edges::Edges;
|
use crate::sql::edges::Edges;
|
||||||
|
@ -74,6 +76,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Log the statement
|
// Log the statement
|
||||||
|
@ -82,29 +85,29 @@ impl Iterator {
|
||||||
let mut cancel_ctx = Context::new(ctx);
|
let mut cancel_ctx = Context::new(ctx);
|
||||||
self.run = cancel_ctx.add_cancel();
|
self.run = cancel_ctx.add_cancel();
|
||||||
// Process the query LIMIT clause
|
// Process the query LIMIT clause
|
||||||
self.setup_limit(&cancel_ctx, opt, stm).await?;
|
self.setup_limit(&cancel_ctx, opt, txn, stm).await?;
|
||||||
// Process the query START clause
|
// Process the query START clause
|
||||||
self.setup_start(&cancel_ctx, opt, stm).await?;
|
self.setup_start(&cancel_ctx, opt, txn, stm).await?;
|
||||||
// Process any EXPLAIN clause
|
// Process any EXPLAIN clause
|
||||||
let explanation = self.output_explain(&cancel_ctx, opt, stm)?;
|
let explanation = self.output_explain(&cancel_ctx, opt, txn, stm)?;
|
||||||
// Process prepared values
|
// Process prepared values
|
||||||
self.iterate(&cancel_ctx, opt, stm).await?;
|
self.iterate(&cancel_ctx, opt, txn, stm).await?;
|
||||||
// Return any document errors
|
// Return any document errors
|
||||||
if let Some(e) = self.error.take() {
|
if let Some(e) = self.error.take() {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
// Process any SPLIT clause
|
// Process any SPLIT clause
|
||||||
self.output_split(ctx, opt, stm).await?;
|
self.output_split(ctx, opt, txn, stm).await?;
|
||||||
// Process any GROUP clause
|
// Process any GROUP clause
|
||||||
self.output_group(ctx, opt, stm).await?;
|
self.output_group(ctx, opt, txn, stm).await?;
|
||||||
// Process any ORDER clause
|
// Process any ORDER clause
|
||||||
self.output_order(ctx, opt, stm).await?;
|
self.output_order(ctx, opt, txn, stm).await?;
|
||||||
// Process any START clause
|
// Process any START clause
|
||||||
self.output_start(ctx, opt, stm).await?;
|
self.output_start(ctx, opt, txn, stm).await?;
|
||||||
// Process any LIMIT clause
|
// Process any LIMIT clause
|
||||||
self.output_limit(ctx, opt, stm).await?;
|
self.output_limit(ctx, opt, txn, stm).await?;
|
||||||
// Process any FETCH clause
|
// Process any FETCH clause
|
||||||
self.output_fetch(ctx, opt, stm).await?;
|
self.output_fetch(ctx, opt, txn, stm).await?;
|
||||||
// Add the EXPLAIN clause to the result
|
// Add the EXPLAIN clause to the result
|
||||||
if let Some(e) = explanation {
|
if let Some(e) = explanation {
|
||||||
self.results.push(e);
|
self.results.push(e);
|
||||||
|
@ -118,10 +121,11 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(v) = stm.limit() {
|
if let Some(v) = stm.limit() {
|
||||||
self.limit = Some(v.process(ctx, opt).await?);
|
self.limit = Some(v.process(ctx, opt, txn, None).await?);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -131,10 +135,11 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(v) = stm.start() {
|
if let Some(v) = stm.start() {
|
||||||
self.start = Some(v.process(ctx, opt).await?);
|
self.start = Some(v.process(ctx, opt, txn, None).await?);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -144,6 +149,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(splits) = stm.split() {
|
if let Some(splits) = stm.split() {
|
||||||
|
@ -162,7 +168,7 @@ impl Iterator {
|
||||||
// Make a copy of object
|
// Make a copy of object
|
||||||
let mut obj = obj.clone();
|
let mut obj = obj.clone();
|
||||||
// Set the value at the path
|
// Set the value at the path
|
||||||
obj.set(ctx, opt, split, val).await?;
|
obj.set(ctx, opt, txn, split, val).await?;
|
||||||
// Add the object to the results
|
// Add the object to the results
|
||||||
self.results.push(obj);
|
self.results.push(obj);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +177,7 @@ impl Iterator {
|
||||||
// Make a copy of object
|
// Make a copy of object
|
||||||
let mut obj = obj.clone();
|
let mut obj = obj.clone();
|
||||||
// Set the value at the path
|
// Set the value at the path
|
||||||
obj.set(ctx, opt, split, val).await?;
|
obj.set(ctx, opt, txn, split, val).await?;
|
||||||
// Add the object to the results
|
// Add the object to the results
|
||||||
self.results.push(obj);
|
self.results.push(obj);
|
||||||
}
|
}
|
||||||
|
@ -187,6 +193,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(fields) = stm.expr() {
|
if let Some(fields) = stm.expr() {
|
||||||
|
@ -234,20 +241,21 @@ impl Iterator {
|
||||||
.unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
|
.unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
|
||||||
match expr {
|
match expr {
|
||||||
Value::Function(f) if f.is_aggregate() => {
|
Value::Function(f) if f.is_aggregate() => {
|
||||||
let x = vals.all().get(ctx, opt, idiom.as_ref()).await?;
|
let x =
|
||||||
let x = f.aggregate(x).compute(ctx, opt).await?;
|
vals.all().get(ctx, opt, txn, None, idiom.as_ref()).await?;
|
||||||
obj.set(ctx, opt, idiom.as_ref(), x).await?;
|
let x = f.aggregate(x).compute(ctx, opt, txn, None).await?;
|
||||||
|
obj.set(ctx, opt, txn, idiom.as_ref(), x).await?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let x = vals.first();
|
let x = vals.first();
|
||||||
let mut child_ctx = Context::new(ctx);
|
|
||||||
child_ctx.add_cursor_doc(&x);
|
|
||||||
let x = if let Some(alias) = alias {
|
let x = if let Some(alias) = alias {
|
||||||
alias.compute(&child_ctx, opt).await?
|
let cur = CursorDoc::new(None, None, &x);
|
||||||
|
alias.compute(ctx, opt, txn, Some(&cur)).await?
|
||||||
} else {
|
} else {
|
||||||
expr.compute(&child_ctx, opt).await?
|
let cur = CursorDoc::new(None, None, &x);
|
||||||
|
expr.compute(ctx, opt, txn, Some(&cur)).await?
|
||||||
};
|
};
|
||||||
obj.set(ctx, opt, idiom.as_ref(), x).await?;
|
obj.set(ctx, opt, txn, idiom.as_ref(), x).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +273,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(orders) = stm.order() {
|
if let Some(orders) = stm.order() {
|
||||||
|
@ -303,6 +312,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(v) = self.start {
|
if let Some(v) = self.start {
|
||||||
|
@ -316,6 +326,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(v) = self.limit {
|
if let Some(v) = self.limit {
|
||||||
|
@ -329,6 +340,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if let Some(fetchs) = stm.fetch() {
|
if let Some(fetchs) = stm.fetch() {
|
||||||
|
@ -336,7 +348,7 @@ impl Iterator {
|
||||||
// Loop over each result value
|
// Loop over each result value
|
||||||
for obj in &mut self.results {
|
for obj in &mut self.results {
|
||||||
// Fetch the value at the path
|
// Fetch the value at the path
|
||||||
obj.fetch(ctx, opt, fetch).await?;
|
obj.fetch(ctx, opt, txn, fetch).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,6 +360,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Option<Value>, Error> {
|
) -> Result<Option<Value>, Error> {
|
||||||
Ok(if stm.explain() {
|
Ok(if stm.explain() {
|
||||||
|
@ -405,13 +418,14 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Prevent deep recursion
|
// Prevent deep recursion
|
||||||
let opt = &opt.dive(4)?;
|
let opt = &opt.dive(4)?;
|
||||||
// Process all prepared values
|
// Process all prepared values
|
||||||
for v in mem::take(&mut self.entries) {
|
for v in mem::take(&mut self.entries) {
|
||||||
v.iterate(ctx, opt, stm, self).await?;
|
v.iterate(ctx, opt, txn, stm, self).await?;
|
||||||
}
|
}
|
||||||
// Everything processed ok
|
// Everything processed ok
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -423,6 +437,7 @@ impl Iterator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Prevent deep recursion
|
// Prevent deep recursion
|
||||||
|
@ -433,7 +448,7 @@ impl Iterator {
|
||||||
false => {
|
false => {
|
||||||
// Process all prepared values
|
// Process all prepared values
|
||||||
for v in mem::take(&mut self.entries) {
|
for v in mem::take(&mut self.entries) {
|
||||||
v.iterate(ctx, opt, stm, self).await?;
|
v.iterate(ctx, opt, txn, stm, self).await?;
|
||||||
}
|
}
|
||||||
// Everything processed ok
|
// Everything processed ok
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -452,7 +467,7 @@ impl Iterator {
|
||||||
let adocs = async {
|
let adocs = async {
|
||||||
// Process all prepared values
|
// Process all prepared values
|
||||||
for v in vals {
|
for v in vals {
|
||||||
e.spawn(v.channel(ctx, opt, stm, chn.clone()))
|
e.spawn(v.channel(ctx, opt, txn, stm, chn.clone()))
|
||||||
// Ensure we detach the spawned task
|
// Ensure we detach the spawned task
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
@ -464,8 +479,8 @@ impl Iterator {
|
||||||
// Create an async closure for received values
|
// Create an async closure for received values
|
||||||
let avals = async {
|
let avals = async {
|
||||||
// Process all received values
|
// Process all received values
|
||||||
while let Ok((k, v)) = docs.recv().await {
|
while let Ok((k, d, v)) = docs.recv().await {
|
||||||
e.spawn(Document::compute(ctx, opt, stm, chn.clone(), k, v))
|
e.spawn(Document::compute(ctx, opt, txn, stm, chn.clone(), k, d, v))
|
||||||
// Ensure we detach the spawned task
|
// Ensure we detach the spawned task
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
@ -494,11 +509,15 @@ impl Iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a new record Thing and Value
|
/// Process a new record Thing and Value
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn process(
|
pub async fn process(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
|
thg: Option<Thing>,
|
||||||
|
doc_id: Option<DocId>,
|
||||||
val: Operable,
|
val: Operable,
|
||||||
) {
|
) {
|
||||||
// Check current context
|
// Check current context
|
||||||
|
@ -512,15 +531,15 @@ impl Iterator {
|
||||||
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
||||||
};
|
};
|
||||||
// Setup a new document
|
// Setup a new document
|
||||||
let mut doc = Document::new(ctx.thing(), &val, ext);
|
let mut doc = Document::new(thg.as_ref(), doc_id, &val, ext);
|
||||||
// Process the document
|
// Process the document
|
||||||
let res = match stm {
|
let res = match stm {
|
||||||
Statement::Select(_) => doc.select(ctx, opt, stm).await,
|
Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
|
||||||
Statement::Create(_) => doc.create(ctx, opt, stm).await,
|
Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
|
||||||
Statement::Update(_) => doc.update(ctx, opt, stm).await,
|
Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
|
||||||
Statement::Relate(_) => doc.relate(ctx, opt, stm).await,
|
Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
|
||||||
Statement::Delete(_) => doc.delete(ctx, opt, stm).await,
|
Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
|
||||||
Statement::Insert(_) => doc.insert(ctx, opt, stm).await,
|
Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// Process the result
|
// Process the result
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
//! and executors to process the operations. This module also gives a `context` to the transaction.
|
//! and executors to process the operations. This module also gives a `context` to the transaction.
|
||||||
mod auth;
|
mod auth;
|
||||||
mod executor;
|
mod executor;
|
||||||
mod iterate;
|
|
||||||
mod iterator;
|
mod iterator;
|
||||||
mod notification;
|
mod notification;
|
||||||
mod options;
|
mod options;
|
||||||
|
@ -26,13 +25,8 @@ pub(crate) use self::statement::*;
|
||||||
pub(crate) use self::transaction::*;
|
pub(crate) use self::transaction::*;
|
||||||
pub(crate) use self::variables::*;
|
pub(crate) use self::variables::*;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
mod channel;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
pub use self::channel::*;
|
|
||||||
|
|
||||||
pub mod cl;
|
pub mod cl;
|
||||||
|
|
||||||
|
mod processor;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test;
|
pub(crate) mod test;
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
use crate::dbs::{Iterable, Iterator, Operable, Options, Statement, Transaction};
|
||||||
use crate::dbs::Iterator;
|
|
||||||
use crate::dbs::Operable;
|
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::idx::planner::plan::Plan;
|
use crate::idx::planner::plan::Plan;
|
||||||
use crate::key::graph;
|
use crate::key::{graph, thing};
|
||||||
use crate::key::thing;
|
|
||||||
use crate::sql::dir::Dir;
|
use crate::sql::dir::Dir;
|
||||||
use crate::sql::thing::Thing;
|
use crate::sql::{Edges, Range, Table, Thing, Value};
|
||||||
use crate::sql::value::Value;
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use crate::sql::{Edges, Range, Table};
|
use channel::Sender;
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
impl Iterable {
|
impl Iterable {
|
||||||
|
@ -19,50 +15,105 @@ impl Iterable {
|
||||||
self,
|
self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
ite: &mut Iterator,
|
ite: &mut Iterator,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
Processor::Iterator(ite).process_iterable(ctx, opt, txn, stm, self).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub(crate) async fn channel(
|
||||||
|
self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
stm: &Statement<'_>,
|
||||||
|
chn: Sender<(Option<Thing>, Option<DocId>, Operable)>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
Processor::Channel(chn).process_iterable(ctx, opt, txn, stm, self).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Processor<'a> {
|
||||||
|
Iterator(&'a mut Iterator),
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
Channel(Sender<(Option<Thing>, Option<DocId>, Operable)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Processor<'a> {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn process(
|
||||||
|
&mut self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
stm: &Statement<'_>,
|
||||||
|
rid: Option<Thing>,
|
||||||
|
doc_id: Option<DocId>,
|
||||||
|
val: Operable,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
match self {
|
||||||
|
Processor::Iterator(ite) => {
|
||||||
|
ite.process(ctx, opt, txn, stm, rid, doc_id, val).await;
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
Processor::Channel(chn) => {
|
||||||
|
chn.send((rid, doc_id, val)).await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_iterable(
|
||||||
|
&mut self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
stm: &Statement<'_>,
|
||||||
|
iterable: Iterable,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if ctx.is_ok() {
|
if ctx.is_ok() {
|
||||||
match self {
|
match iterable {
|
||||||
Iterable::Value(v) => Self::iterate_value(ctx, opt, stm, v, ite).await,
|
Iterable::Value(v) => self.process_value(ctx, opt, txn, stm, v).await?,
|
||||||
Iterable::Thing(v) => Self::iterate_thing(ctx, opt, stm, v, ite).await?,
|
Iterable::Thing(v) => self.process_thing(ctx, opt, txn, stm, v).await?,
|
||||||
Iterable::Table(v) => Self::iterate_table(ctx, opt, stm, v, ite).await?,
|
Iterable::Table(v) => self.process_table(ctx, opt, txn, stm, v).await?,
|
||||||
Iterable::Range(v) => Self::iterate_range(ctx, opt, stm, v, ite).await?,
|
Iterable::Range(v) => self.process_range(ctx, opt, txn, stm, v).await?,
|
||||||
Iterable::Edges(e) => Self::iterate_edge(ctx, opt, stm, e, ite).await?,
|
Iterable::Edges(e) => self.process_edge(ctx, opt, txn, stm, e).await?,
|
||||||
Iterable::Index(t, p) => Self::iterate_index(ctx, opt, stm, t, p, ite).await?,
|
Iterable::Index(t, p) => self.process_index(ctx, opt, txn, stm, t, p).await?,
|
||||||
Iterable::Mergeable(v, o) => {
|
Iterable::Mergeable(v, o) => {
|
||||||
Self::iterate_mergeable(ctx, opt, stm, v, o, ite).await?
|
self.process_mergeable(ctx, opt, txn, stm, v, o).await?
|
||||||
}
|
}
|
||||||
Iterable::Relatable(f, v, w) => {
|
Iterable::Relatable(f, v, w) => {
|
||||||
Self::iterate_relatable(ctx, opt, stm, f, v, w, ite).await?
|
self.process_relatable(ctx, opt, txn, stm, f, v, w).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_value(
|
async fn process_value(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
v: Value,
|
v: Value,
|
||||||
ite: &mut Iterator,
|
) -> Result<(), Error> {
|
||||||
) {
|
|
||||||
// Pass the value through
|
// Pass the value through
|
||||||
let val = Operable::Value(v);
|
let val = Operable::Value(v);
|
||||||
// Process the document record
|
// Process the document record
|
||||||
ite.process(ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, None, None, val).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_thing(
|
async fn process_thing(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
v: Thing,
|
v: Thing,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||||
// Fetch the data from the store
|
// Fetch the data from the store
|
||||||
|
@ -73,25 +124,21 @@ impl Iterable {
|
||||||
Some(v) => Value::from(v),
|
Some(v) => Value::from(v),
|
||||||
None => Value::None,
|
None => Value::None,
|
||||||
});
|
});
|
||||||
// Get the optional query executor
|
|
||||||
let mut child_ctx = Context::new(ctx);
|
|
||||||
child_ctx.add_thing(&v);
|
|
||||||
// Process the document record
|
// Process the document record
|
||||||
ite.process(&child_ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||||
// Everything ok
|
// Everything ok
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_mergeable(
|
async fn process_mergeable(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
v: Thing,
|
v: Thing,
|
||||||
o: Value,
|
o: Value,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||||
// Fetch the data from the store
|
// Fetch the data from the store
|
||||||
|
@ -104,26 +151,23 @@ impl Iterable {
|
||||||
};
|
};
|
||||||
// Create a new operable value
|
// Create a new operable value
|
||||||
let val = Operable::Mergeable(x, o);
|
let val = Operable::Mergeable(x, o);
|
||||||
// Create a new context to process the operable
|
|
||||||
let mut child_ctx = Context::new(ctx);
|
|
||||||
child_ctx.add_thing(&v);
|
|
||||||
// Process the document record
|
// Process the document record
|
||||||
ite.process(&child_ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||||
// Everything ok
|
// Everything ok
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_relatable(
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn process_relatable(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
f: Thing,
|
f: Thing,
|
||||||
v: Thing,
|
v: Thing,
|
||||||
w: Thing,
|
w: Thing,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||||
// Fetch the data from the store
|
// Fetch the data from the store
|
||||||
|
@ -136,24 +180,20 @@ impl Iterable {
|
||||||
};
|
};
|
||||||
// Create a new operable value
|
// Create a new operable value
|
||||||
let val = Operable::Relatable(f, x, w);
|
let val = Operable::Relatable(f, x, w);
|
||||||
// Create the child context
|
|
||||||
let mut child_ctx = Context::new(ctx);
|
|
||||||
child_ctx.add_thing(&v);
|
|
||||||
// Process the document record
|
// Process the document record
|
||||||
ite.process(&child_ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||||
// Everything ok
|
// Everything ok
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_table(
|
async fn process_table(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
v: Table,
|
v: Table,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
|
||||||
// Prepare the start and end keys
|
// Prepare the start and end keys
|
||||||
|
@ -201,10 +241,8 @@ impl Iterable {
|
||||||
let rid = Thing::from((key.tb, key.id));
|
let rid = Thing::from((key.tb, key.id));
|
||||||
// Create a new operable value
|
// Create a new operable value
|
||||||
let val = Operable::Value(val);
|
let val = Operable::Value(val);
|
||||||
let mut child_ctx = Context::new(ctx);
|
|
||||||
child_ctx.add_thing(&rid);
|
|
||||||
// Process the record
|
// Process the record
|
||||||
ite.process(&child_ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -214,15 +252,14 @@ impl Iterable {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_range(
|
async fn process_range(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
v: Range,
|
v: Range,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||||
// Prepare the range start key
|
// Prepare the range start key
|
||||||
|
@ -285,12 +322,10 @@ impl Iterable {
|
||||||
let key: crate::key::thing::Thing = (&k).into();
|
let key: crate::key::thing::Thing = (&k).into();
|
||||||
let val: crate::sql::value::Value = (&v).into();
|
let val: crate::sql::value::Value = (&v).into();
|
||||||
let rid = Thing::from((key.tb, key.id));
|
let rid = Thing::from((key.tb, key.id));
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_thing(&rid);
|
|
||||||
// Create a new operable value
|
// Create a new operable value
|
||||||
let val = Operable::Value(val);
|
let val = Operable::Value(val);
|
||||||
// Process the record
|
// Process the record
|
||||||
ite.process(&ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -300,12 +335,13 @@ impl Iterable {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_edge(
|
async fn process_edge(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
e: Edges,
|
e: Edges,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Pull out options
|
// Pull out options
|
||||||
let ns = opt.ns();
|
let ns = opt.ns();
|
||||||
|
@ -390,13 +426,13 @@ impl Iterable {
|
||||||
None => {
|
None => {
|
||||||
let min = beg.clone();
|
let min = beg.clone();
|
||||||
let max = end.clone();
|
let max = end.clone();
|
||||||
ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await?
|
txn.lock().await.scan(min..max, 1000).await?
|
||||||
}
|
}
|
||||||
Some(ref mut beg) => {
|
Some(ref mut beg) => {
|
||||||
beg.push(0x00);
|
beg.push(0x00);
|
||||||
let min = beg.clone();
|
let min = beg.clone();
|
||||||
let max = end.clone();
|
let max = end.clone();
|
||||||
ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await?
|
txn.lock().await.scan(min..max, 1000).await?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// If there are key-value entries then fetch them
|
// If there are key-value entries then fetch them
|
||||||
|
@ -421,17 +457,15 @@ impl Iterable {
|
||||||
let gra: crate::key::graph::Graph = (&k).into();
|
let gra: crate::key::graph::Graph = (&k).into();
|
||||||
// Fetch the data from the store
|
// Fetch the data from the store
|
||||||
let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk);
|
let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk);
|
||||||
let val = ctx.try_clone_transaction()?.lock().await.get(key).await?;
|
let val = txn.lock().await.get(key).await?;
|
||||||
let rid = Thing::from((gra.ft, gra.fk));
|
let rid = Thing::from((gra.ft, gra.fk));
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_thing(&rid);
|
|
||||||
// Parse the data from the store
|
// Parse the data from the store
|
||||||
let val = Operable::Value(match val {
|
let val = Operable::Value(match val {
|
||||||
Some(v) => Value::from(v),
|
Some(v) => Value::from(v),
|
||||||
None => Value::None,
|
None => Value::None,
|
||||||
});
|
});
|
||||||
// Process the record
|
// Process the record
|
||||||
ite.process(&ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -442,22 +476,21 @@ impl Iterable {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn iterate_index(
|
async fn process_index(
|
||||||
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
table: Table,
|
table: Table,
|
||||||
plan: Plan,
|
plan: Plan,
|
||||||
ite: &mut Iterator,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check that the table exists
|
// Check that the table exists
|
||||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?;
|
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?;
|
||||||
let exe = ctx.get_query_executor(&table.0);
|
let exe = ctx.get_query_executor(&table.0);
|
||||||
if let Some(exe) = exe {
|
if let Some(exe) = exe {
|
||||||
let mut iterator = plan.new_iterator(opt, &txn, exe).await?;
|
let mut iterator = plan.new_iterator(opt, txn, exe).await?;
|
||||||
let mut things = iterator.next_batch(&txn, 1000).await?;
|
let mut things = iterator.next_batch(txn, 1000).await?;
|
||||||
while !things.is_empty() {
|
while !things.is_empty() {
|
||||||
// Check if the context is finished
|
// Check if the context is finished
|
||||||
if ctx.is_done() {
|
if ctx.is_done() {
|
||||||
|
@ -479,20 +512,17 @@ impl Iterable {
|
||||||
let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id);
|
let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id);
|
||||||
let val = txn.lock().await.get(key.clone()).await?;
|
let val = txn.lock().await.get(key.clone()).await?;
|
||||||
let rid = Thing::from((key.tb, key.id));
|
let rid = Thing::from((key.tb, key.id));
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_thing(&rid);
|
|
||||||
ctx.add_doc_id(doc_id);
|
|
||||||
// Parse the data from the store
|
// Parse the data from the store
|
||||||
let val = Operable::Value(match val {
|
let val = Operable::Value(match val {
|
||||||
Some(v) => Value::from(v),
|
Some(v) => Value::from(v),
|
||||||
None => Value::None,
|
None => Value::None,
|
||||||
});
|
});
|
||||||
// Process the document record
|
// Process the document record
|
||||||
ite.process(&ctx, opt, stm, val).await;
|
self.process(ctx, opt, txn, stm, Some(rid), Some(doc_id), val).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect the next batch of ids
|
// Collect the next batch of ids
|
||||||
things = iterator.next_batch(&txn, 1000).await?;
|
things = iterator.next_batch(txn, 1000).await?;
|
||||||
}
|
}
|
||||||
// Everything ok
|
// Everything ok
|
||||||
Ok(())
|
Ok(())
|
|
@ -1,15 +1,14 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::{Auth, Options};
|
use crate::dbs::{Auth, Options, Transaction};
|
||||||
use crate::kvs::Datastore;
|
use crate::kvs::Datastore;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub async fn mock<'a>() -> (Context<'a>, Options) {
|
pub async fn mock<'a>() -> (Context<'a>, Options, Transaction) {
|
||||||
let mut ctx = Context::default();
|
let ctx = Context::default();
|
||||||
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
||||||
let kvs = Datastore::new("memory").await.unwrap();
|
let kvs = Datastore::new("memory").await.unwrap();
|
||||||
let txn = kvs.transaction(true, false).await.unwrap();
|
let txn = kvs.transaction(true, false).await.unwrap();
|
||||||
let txn = Arc::new(Mutex::new(txn));
|
let txn = Arc::new(Mutex::new(txn));
|
||||||
ctx.add_transaction(Some(&txn));
|
(ctx, opt, txn)
|
||||||
(ctx, opt)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::permission::Permission;
|
use crate::sql::permission::Permission;
|
||||||
|
@ -10,16 +10,15 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if this record exists
|
// Check if this record exists
|
||||||
if self.id.is_some() {
|
if self.id.is_some() {
|
||||||
// Should we run permissions checks?
|
// Should we run permissions checks?
|
||||||
if opt.perms && opt.auth.perms() {
|
if opt.perms && opt.auth.perms() {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Get the table
|
// Get the table
|
||||||
let tb = self.tb(opt, &txn).await?;
|
let tb = self.tb(opt, txn).await?;
|
||||||
// Get the permission clause
|
// Get the permission clause
|
||||||
let perms = if stm.is_delete() {
|
let perms = if stm.is_delete() {
|
||||||
&tb.permissions.delete
|
&tb.permissions.delete
|
||||||
|
@ -37,10 +36,8 @@ impl<'a> Document<'a> {
|
||||||
Permission::Specific(e) => {
|
Permission::Specific(e) => {
|
||||||
// Disable permissions
|
// Disable permissions
|
||||||
let opt = &opt.new_with_perms(false);
|
let opt = &opt.new_with_perms(false);
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process the PERMISSION clause
|
// Process the PERMISSION clause
|
||||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
if !e.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||||
return Err(Error::Ignore);
|
return Err(Error::Ignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
use crate::dbs::Workable;
|
use crate::dbs::Workable;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::data::Data;
|
use crate::sql::data::Data;
|
||||||
|
@ -13,57 +13,50 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Set default field values
|
// Set default field values
|
||||||
self.current.to_mut().def(rid);
|
self.current.doc.to_mut().def(rid);
|
||||||
// The statement has a data clause
|
// The statement has a data clause
|
||||||
if let Some(v) = stm.data() {
|
if let Some(v) = stm.data() {
|
||||||
match v {
|
match v {
|
||||||
Data::PatchExpression(data) => {
|
Data::PatchExpression(data) => {
|
||||||
let mut current_ctx = Context::new(ctx);
|
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
self.current.doc.to_mut().patch(data)?
|
||||||
let data = data.compute(¤t_ctx, opt).await?;
|
|
||||||
self.current.to_mut().patch(data)?
|
|
||||||
}
|
}
|
||||||
Data::MergeExpression(data) => {
|
Data::MergeExpression(data) => {
|
||||||
let mut current_ctx = Context::new(ctx);
|
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
self.current.doc.to_mut().merge(data)?
|
||||||
let data = data.compute(¤t_ctx, opt).await?;
|
|
||||||
self.current.to_mut().merge(data)?
|
|
||||||
}
|
}
|
||||||
Data::ReplaceExpression(data) => {
|
Data::ReplaceExpression(data) => {
|
||||||
let mut current_ctx = Context::new(ctx);
|
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
self.current.doc.to_mut().replace(data)?
|
||||||
let data = data.compute(¤t_ctx, opt).await?;
|
|
||||||
self.current.to_mut().replace(data)?
|
|
||||||
}
|
}
|
||||||
Data::ContentExpression(data) => {
|
Data::ContentExpression(data) => {
|
||||||
let mut current_ctx = Context::new(ctx);
|
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
self.current.doc.to_mut().replace(data)?
|
||||||
let data = data.compute(¤t_ctx, opt).await?;
|
|
||||||
self.current.to_mut().replace(data)?
|
|
||||||
}
|
}
|
||||||
Data::SetExpression(x) => {
|
Data::SetExpression(x) => {
|
||||||
for x in x.iter() {
|
for x in x.iter() {
|
||||||
let mut current_ctx = Context::new(ctx);
|
let v = x.2.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
|
||||||
let v = x.2.compute(¤t_ctx, opt).await?;
|
|
||||||
match x.1 {
|
match x.1 {
|
||||||
Operator::Equal => match v {
|
Operator::Equal => match v {
|
||||||
Value::None => self.current.to_mut().del(ctx, opt, &x.0).await?,
|
Value::None => {
|
||||||
_ => self.current.to_mut().set(ctx, opt, &x.0, v).await?,
|
self.current.doc.to_mut().del(ctx, opt, txn, &x.0).await?
|
||||||
|
}
|
||||||
|
_ => self.current.doc.to_mut().set(ctx, opt, txn, &x.0, v).await?,
|
||||||
},
|
},
|
||||||
Operator::Inc => {
|
Operator::Inc => {
|
||||||
self.current.to_mut().increment(ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().increment(ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
Operator::Dec => {
|
Operator::Dec => {
|
||||||
self.current.to_mut().decrement(ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().decrement(ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
Operator::Ext => {
|
Operator::Ext => {
|
||||||
self.current.to_mut().extend(ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().extend(ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -71,7 +64,7 @@ impl<'a> Document<'a> {
|
||||||
}
|
}
|
||||||
Data::UnsetExpression(i) => {
|
Data::UnsetExpression(i) => {
|
||||||
for i in i.iter() {
|
for i in i.iter() {
|
||||||
self.current.to_mut().del(ctx, opt, i).await?
|
self.current.doc.to_mut().del(ctx, opt, txn, i).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::UpdateExpression(x) => {
|
Data::UpdateExpression(x) => {
|
||||||
|
@ -83,22 +76,22 @@ impl<'a> Document<'a> {
|
||||||
}
|
}
|
||||||
// Process ON DUPLICATE KEY clause
|
// Process ON DUPLICATE KEY clause
|
||||||
for x in x.iter() {
|
for x in x.iter() {
|
||||||
let mut current_ctx = Context::new(&ctx);
|
let v = x.2.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
|
||||||
let v = x.2.compute(¤t_ctx, opt).await?;
|
|
||||||
match x.1 {
|
match x.1 {
|
||||||
Operator::Equal => match v {
|
Operator::Equal => match v {
|
||||||
Value::None => self.current.to_mut().del(&ctx, opt, &x.0).await?,
|
Value::None => {
|
||||||
_ => self.current.to_mut().set(&ctx, opt, &x.0, v).await?,
|
self.current.doc.to_mut().del(&ctx, opt, txn, &x.0).await?
|
||||||
|
}
|
||||||
|
_ => self.current.doc.to_mut().set(&ctx, opt, txn, &x.0, v).await?,
|
||||||
},
|
},
|
||||||
Operator::Inc => {
|
Operator::Inc => {
|
||||||
self.current.to_mut().increment(&ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().increment(&ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
Operator::Dec => {
|
Operator::Dec => {
|
||||||
self.current.to_mut().decrement(&ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().decrement(&ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
Operator::Ext => {
|
Operator::Ext => {
|
||||||
self.current.to_mut().extend(&ctx, opt, &x.0, v).await?
|
self.current.doc.to_mut().extend(&ctx, opt, txn, &x.0, v).await?
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -108,7 +101,7 @@ impl<'a> Document<'a> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
// Set default field values
|
// Set default field values
|
||||||
self.current.to_mut().def(rid);
|
self.current.doc.to_mut().def(rid);
|
||||||
// Carry on
|
// Carry on
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
|
||||||
|
@ -9,14 +9,13 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check where condition
|
// Check where condition
|
||||||
if let Some(cond) = stm.conds() {
|
if let Some(cond) = stm.conds() {
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Check if the expression is truthy
|
// Check if the expression is truthy
|
||||||
if !cond.compute(&ctx, opt).await?.is_truthy() {
|
if !cond.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||||
// Ignore this document
|
// Ignore this document
|
||||||
return Err(Error::Ignore);
|
return Err(Error::Ignore);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::idiom::Idiom;
|
use crate::sql::idiom::Idiom;
|
||||||
|
@ -10,43 +10,42 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Get the table
|
// Get the table
|
||||||
let tb = self.tb(opt, &txn).await?;
|
let tb = self.tb(opt, txn).await?;
|
||||||
// This table is schemafull
|
// This table is schemafull
|
||||||
if tb.full {
|
if tb.full {
|
||||||
// Create a vector to store the keys
|
// Create a vector to store the keys
|
||||||
let mut keys: Vec<Idiom> = vec![];
|
let mut keys: Vec<Idiom> = vec![];
|
||||||
// Loop through all field statements
|
// Loop through all field statements
|
||||||
for fd in self.fd(opt, &txn).await?.iter() {
|
for fd in self.fd(opt, txn).await?.iter() {
|
||||||
// Is this a schemaless field?
|
// Is this a schemaless field?
|
||||||
match fd.flex {
|
match fd.flex {
|
||||||
false => {
|
false => {
|
||||||
// Loop over this field in the document
|
// Loop over this field in the document
|
||||||
for k in self.current.each(&fd.name).into_iter() {
|
for k in self.current.doc.each(&fd.name).into_iter() {
|
||||||
keys.push(k);
|
keys.push(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true => {
|
true => {
|
||||||
// Loop over every field under this field in the document
|
// Loop over every field under this field in the document
|
||||||
for k in self.current.every(Some(&fd.name), true, true).into_iter() {
|
for k in self.current.doc.every(Some(&fd.name), true, true).into_iter() {
|
||||||
keys.push(k);
|
keys.push(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Loop over every field in the document
|
// Loop over every field in the document
|
||||||
for fd in self.current.every(None, true, true).iter() {
|
for fd in self.current.doc.every(None, true, true).iter() {
|
||||||
if !keys.contains(fd) {
|
if !keys.contains(fd) {
|
||||||
match fd {
|
match fd {
|
||||||
fd if fd.is_id() => continue,
|
fd if fd.is_id() => continue,
|
||||||
fd if fd.is_in() => continue,
|
fd if fd.is_in() => continue,
|
||||||
fd if fd.is_out() => continue,
|
fd if fd.is_out() => continue,
|
||||||
fd if fd.is_meta() => continue,
|
fd if fd.is_meta() => continue,
|
||||||
fd => self.current.to_mut().del(ctx, opt, fd).await?,
|
fd => self.current.doc.to_mut().del(ctx, opt, txn, fd).await?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Operable;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
use crate::dbs::Workable;
|
use crate::dbs::Workable;
|
||||||
|
use crate::dbs::{Operable, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::sql::thing::Thing;
|
use crate::sql::thing::Thing;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use channel::Sender;
|
use channel::Sender;
|
||||||
|
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) async fn compute(
|
pub(crate) async fn compute(
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
chn: Sender<Result<Value, Error>>,
|
chn: Sender<Result<Value, Error>>,
|
||||||
thg: Option<Thing>,
|
thg: Option<Thing>,
|
||||||
|
doc_id: Option<DocId>,
|
||||||
val: Operable,
|
val: Operable,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
if let Some(t) = &thg {
|
|
||||||
ctx.add_thing(t);
|
|
||||||
}
|
|
||||||
// Setup a new workable
|
// Setup a new workable
|
||||||
let ins = match val {
|
let ins = match val {
|
||||||
Operable::Value(v) => (v, Workable::Normal),
|
Operable::Value(v) => (v, Workable::Normal),
|
||||||
|
@ -30,15 +30,15 @@ impl<'a> Document<'a> {
|
||||||
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
||||||
};
|
};
|
||||||
// Setup a new document
|
// Setup a new document
|
||||||
let mut doc = Document::new(ctx.thing(), &ins.0, ins.1);
|
let mut doc = Document::new(thg.as_ref(), doc_id, &ins.0, ins.1);
|
||||||
// Process the statement
|
// Process the statement
|
||||||
let res = match stm {
|
let res = match stm {
|
||||||
Statement::Select(_) => doc.select(&ctx, opt, stm).await,
|
Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
|
||||||
Statement::Create(_) => doc.create(&ctx, opt, stm).await,
|
Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
|
||||||
Statement::Update(_) => doc.update(&ctx, opt, stm).await,
|
Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
|
||||||
Statement::Relate(_) => doc.relate(&ctx, opt, stm).await,
|
Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
|
||||||
Statement::Delete(_) => doc.delete(&ctx, opt, stm).await,
|
Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
|
||||||
Statement::Insert(_) => doc.insert(&ctx, opt, stm).await,
|
Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// Send back the result
|
// Send back the result
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,31 +10,32 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check if exists
|
// Check if exists
|
||||||
self.exist(ctx, opt, stm).await?;
|
self.exist(ctx, opt, txn, stm).await?;
|
||||||
// Alter record data
|
// Alter record data
|
||||||
self.alter(ctx, opt, stm).await?;
|
self.alter(ctx, opt, txn, stm).await?;
|
||||||
// Merge fields data
|
// Merge fields data
|
||||||
self.field(ctx, opt, stm).await?;
|
self.field(ctx, opt, txn, stm).await?;
|
||||||
// Reset fields data
|
// Reset fields data
|
||||||
self.reset(ctx, opt, stm).await?;
|
self.reset(ctx, opt, txn, stm).await?;
|
||||||
// Clean fields data
|
// Clean fields data
|
||||||
self.clean(ctx, opt, stm).await?;
|
self.clean(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Store index data
|
// Store index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Store record data
|
// Store record data
|
||||||
self.store(ctx, opt, stm).await?;
|
self.store(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,25 +10,26 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check where clause
|
// Check where clause
|
||||||
self.check(ctx, opt, stm).await?;
|
self.check(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Erase document
|
// Erase document
|
||||||
self.erase(ctx, opt, stm).await?;
|
self.erase(ctx, opt, stm).await?;
|
||||||
// Purge index data
|
// Purge index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Purge record data
|
// Purge record data
|
||||||
self.purge(ctx, opt, stm).await?;
|
self.purge(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::dbs::Options;
|
||||||
use crate::dbs::Transaction;
|
use crate::dbs::Transaction;
|
||||||
use crate::dbs::Workable;
|
use crate::dbs::Workable;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::sql::statements::define::DefineEventStatement;
|
use crate::sql::statements::define::DefineEventStatement;
|
||||||
use crate::sql::statements::define::DefineFieldStatement;
|
use crate::sql::statements::define::DefineFieldStatement;
|
||||||
use crate::sql::statements::define::DefineIndexStatement;
|
use crate::sql::statements::define::DefineIndexStatement;
|
||||||
|
@ -17,8 +18,24 @@ use std::sync::Arc;
|
||||||
pub(crate) struct Document<'a> {
|
pub(crate) struct Document<'a> {
|
||||||
pub(super) id: Option<&'a Thing>,
|
pub(super) id: Option<&'a Thing>,
|
||||||
pub(super) extras: Workable,
|
pub(super) extras: Workable,
|
||||||
pub(super) current: Cow<'a, Value>,
|
pub(super) initial: CursorDoc<'a>,
|
||||||
pub(super) initial: Cow<'a, Value>,
|
pub(super) current: CursorDoc<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CursorDoc<'a> {
|
||||||
|
pub(crate) rid: Option<&'a Thing>,
|
||||||
|
pub(crate) doc: Cow<'a, Value>,
|
||||||
|
pub(crate) doc_id: Option<DocId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CursorDoc<'a> {
|
||||||
|
pub(crate) fn new(rid: Option<&'a Thing>, doc_id: Option<DocId>, doc: &'a Value) -> Self {
|
||||||
|
Self {
|
||||||
|
rid,
|
||||||
|
doc: Cow::Borrowed(doc),
|
||||||
|
doc_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Debug for Document<'a> {
|
impl<'a> Debug for Document<'a> {
|
||||||
|
@ -29,17 +46,22 @@ impl<'a> Debug for Document<'a> {
|
||||||
|
|
||||||
impl<'a> From<&Document<'a>> for Vec<u8> {
|
impl<'a> From<&Document<'a>> for Vec<u8> {
|
||||||
fn from(val: &Document<'a>) -> Vec<u8> {
|
fn from(val: &Document<'a>) -> Vec<u8> {
|
||||||
val.current.as_ref().into()
|
val.current.doc.as_ref().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
pub fn new(id: Option<&'a Thing>, val: &'a Value, ext: Workable) -> Self {
|
pub fn new(
|
||||||
|
id: Option<&'a Thing>,
|
||||||
|
doc_id: Option<DocId>,
|
||||||
|
val: &'a Value,
|
||||||
|
extras: Workable,
|
||||||
|
) -> Self {
|
||||||
Document {
|
Document {
|
||||||
id,
|
id,
|
||||||
extras: ext,
|
extras,
|
||||||
current: Cow::Borrowed(val),
|
current: CursorDoc::new(id, doc_id, val),
|
||||||
initial: Cow::Borrowed(val),
|
initial: CursorDoc::new(id, doc_id, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,11 +69,11 @@ impl<'a> Document<'a> {
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
/// Check if document has changed
|
/// Check if document has changed
|
||||||
pub fn changed(&self) -> bool {
|
pub fn changed(&self) -> bool {
|
||||||
self.initial != self.current
|
self.initial.doc != self.current.doc
|
||||||
}
|
}
|
||||||
/// Check if document has changed
|
/// Check if document has changed
|
||||||
pub fn is_new(&self) -> bool {
|
pub fn is_new(&self) -> bool {
|
||||||
self.initial.is_none()
|
self.initial.doc.is_none()
|
||||||
}
|
}
|
||||||
/// Get the table for this document
|
/// Get the table for this document
|
||||||
pub async fn tb(
|
pub async fn tb(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
use crate::dbs::Workable;
|
use crate::dbs::Workable;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::paths::EDGE;
|
use crate::sql::paths::EDGE;
|
||||||
|
@ -13,14 +13,13 @@ use crate::sql::Dir;
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
pub async fn edges(
|
pub async fn edges(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check if the table is a view
|
// Check if the table is a view
|
||||||
if self.tb(opt, &txn).await?.drop {
|
if self.tb(opt, txn).await?.drop {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
|
@ -44,9 +43,9 @@ impl<'a> Document<'a> {
|
||||||
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
|
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
|
||||||
run.set(key, vec![]).await?;
|
run.set(key, vec![]).await?;
|
||||||
// Store the edges on the record
|
// Store the edges on the record
|
||||||
self.current.to_mut().put(&*EDGE, Value::Bool(true));
|
self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
|
||||||
self.current.to_mut().put(&*IN, l.clone().into());
|
self.current.doc.to_mut().put(&*IN, l.clone().into());
|
||||||
self.current.to_mut().put(&*OUT, r.clone().into());
|
self.current.doc.to_mut().put(&*OUT, r.clone().into());
|
||||||
}
|
}
|
||||||
// Carry on
|
// Carry on
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
|
||||||
|
@ -9,12 +10,13 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if this record exists
|
// Check if this record exists
|
||||||
if self.id.is_some() {
|
if self.id.is_some() {
|
||||||
// There is no current record
|
// There is no current record
|
||||||
if self.current.is_none() {
|
if self.current.doc.is_none() {
|
||||||
// Ignore this requested record
|
// Ignore this requested record
|
||||||
return Err(Error::Ignore);
|
return Err(Error::Ignore);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@ impl<'a> Document<'a> {
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.current.to_mut().clear()
|
self.current.doc.to_mut().clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check events
|
// Check events
|
||||||
|
@ -23,10 +24,8 @@ impl<'a> Document<'a> {
|
||||||
}
|
}
|
||||||
// Don't run permissions
|
// Don't run permissions
|
||||||
let opt = &opt.new_with_perms(false);
|
let opt = &opt.new_with_perms(false);
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Loop through all event statements
|
// Loop through all event statements
|
||||||
for ev in self.ev(opt, &txn).await?.iter() {
|
for ev in self.ev(opt, txn).await?.iter() {
|
||||||
// Get the event action
|
// Get the event action
|
||||||
let met = if stm.is_delete() {
|
let met = if stm.is_delete() {
|
||||||
Value::from("DELETE")
|
Value::from("DELETE")
|
||||||
|
@ -38,16 +37,15 @@ impl<'a> Document<'a> {
|
||||||
// Configure the context
|
// Configure the context
|
||||||
let mut ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
ctx.add_value("event", met);
|
ctx.add_value("event", met);
|
||||||
ctx.add_value("value", self.current.deref());
|
ctx.add_value("value", self.current.doc.deref());
|
||||||
ctx.add_value("after", self.current.deref());
|
ctx.add_value("after", self.current.doc.deref());
|
||||||
ctx.add_value("before", self.initial.deref());
|
ctx.add_value("before", self.initial.doc.deref());
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process conditional clause
|
// Process conditional clause
|
||||||
let val = ev.when.compute(&ctx, opt).await?;
|
let val = ev.when.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||||
// Execute event if value is truthy
|
// Execute event if value is truthy
|
||||||
if val.is_truthy() {
|
if val.is_truthy() {
|
||||||
for v in ev.then.iter() {
|
for v in ev.then.iter() {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
|
||||||
|
@ -9,12 +9,13 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if this record exists
|
// Check if this record exists
|
||||||
if let Some(id) = &self.id {
|
if let Some(id) = &self.id {
|
||||||
// If there is a current value
|
// If there is a current value
|
||||||
if self.current.is_some() {
|
if self.current.doc.is_some() {
|
||||||
// The record already exists
|
// The record already exists
|
||||||
return Err(Error::RecordExists {
|
return Err(Error::RecordExists {
|
||||||
thing: id.to_string(),
|
thing: id.to_string(),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::permission::Permission;
|
use crate::sql::permission::Permission;
|
||||||
|
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check fields
|
// Check fields
|
||||||
|
@ -20,15 +21,13 @@ impl<'a> Document<'a> {
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Get the user applied input
|
// Get the user applied input
|
||||||
let inp = self.initial.changed(self.current.as_ref());
|
let inp = self.initial.doc.changed(self.current.doc.as_ref());
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Loop through all field statements
|
// Loop through all field statements
|
||||||
for fd in self.fd(opt, &txn).await?.iter() {
|
for fd in self.fd(opt, txn).await?.iter() {
|
||||||
// Loop over each field in document
|
// Loop over each field in document
|
||||||
for (k, mut val) in self.current.walk(&fd.name).into_iter() {
|
for (k, mut val) in self.current.doc.walk(&fd.name).into_iter() {
|
||||||
// Get the initial value
|
// Get the initial value
|
||||||
let old = self.initial.pick(&k);
|
let old = self.initial.doc.pick(&k);
|
||||||
// Get the input value
|
// Get the input value
|
||||||
let inp = inp.pick(&k);
|
let inp = inp.pick(&k);
|
||||||
// Check for a TYPE clause
|
// Check for a TYPE clause
|
||||||
|
@ -58,9 +57,8 @@ impl<'a> Document<'a> {
|
||||||
ctx.add_value("value", &val);
|
ctx.add_value("value", &val);
|
||||||
ctx.add_value("after", &val);
|
ctx.add_value("after", &val);
|
||||||
ctx.add_value("before", &old);
|
ctx.add_value("before", &old);
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process the VALUE clause
|
// Process the VALUE clause
|
||||||
val = expr.compute(&ctx, opt).await?;
|
val = expr.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||||
}
|
}
|
||||||
// Check for a TYPE clause
|
// Check for a TYPE clause
|
||||||
if let Some(kind) = &fd.kind {
|
if let Some(kind) = &fd.kind {
|
||||||
|
@ -87,9 +85,8 @@ impl<'a> Document<'a> {
|
||||||
ctx.add_value("value", &val);
|
ctx.add_value("value", &val);
|
||||||
ctx.add_value("after", &val);
|
ctx.add_value("after", &val);
|
||||||
ctx.add_value("before", &old);
|
ctx.add_value("before", &old);
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process the ASSERT clause
|
// Process the ASSERT clause
|
||||||
if !expr.compute(&ctx, opt).await?.is_truthy() {
|
if !expr.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||||
return Err(Error::FieldValue {
|
return Err(Error::FieldValue {
|
||||||
thing: rid.to_string(),
|
thing: rid.to_string(),
|
||||||
field: fd.name.clone(),
|
field: fd.name.clone(),
|
||||||
|
@ -119,9 +116,8 @@ impl<'a> Document<'a> {
|
||||||
ctx.add_value("value", &val);
|
ctx.add_value("value", &val);
|
||||||
ctx.add_value("after", &val);
|
ctx.add_value("after", &val);
|
||||||
ctx.add_value("before", &old);
|
ctx.add_value("before", &old);
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process the PERMISSION clause
|
// Process the PERMISSION clause
|
||||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
if !e.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||||
val = old
|
val = old
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,8 +125,8 @@ impl<'a> Document<'a> {
|
||||||
}
|
}
|
||||||
// Set the value of the field
|
// Set the value of the field
|
||||||
match val {
|
match val {
|
||||||
Value::None => self.current.to_mut().del(ctx, opt, &k).await?,
|
Value::None => self.current.doc.to_mut().del(ctx, opt, txn, &k).await?,
|
||||||
_ => self.current.to_mut().set(ctx, opt, &k, val).await?,
|
_ => self.current.doc.to_mut().set(ctx, opt, txn, &k, val).await?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
use crate::doc::Document;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::{CursorDoc, Document};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::ft::FtIndex;
|
use crate::idx::ft::FtIndex;
|
||||||
use crate::idx::IndexKeyBase;
|
use crate::idx::IndexKeyBase;
|
||||||
|
@ -9,7 +9,7 @@ use crate::sql::array::Array;
|
||||||
use crate::sql::index::Index;
|
use crate::sql::index::Index;
|
||||||
use crate::sql::scoring::Scoring;
|
use crate::sql::scoring::Scoring;
|
||||||
use crate::sql::statements::DefineIndexStatement;
|
use crate::sql::statements::DefineIndexStatement;
|
||||||
use crate::sql::{Ident, Thing, Value};
|
use crate::sql::{Ident, Thing};
|
||||||
use crate::{key, kvs};
|
use crate::{key, kvs};
|
||||||
|
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
|
@ -17,6 +17,7 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check indexes
|
// Check indexes
|
||||||
|
@ -27,21 +28,19 @@ impl<'a> Document<'a> {
|
||||||
if !opt.force && !self.changed() {
|
if !opt.force && !self.changed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check if the table is a view
|
// Check if the table is a view
|
||||||
if self.tb(opt, &txn).await?.drop {
|
if self.tb(opt, txn).await?.drop {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Loop through all index statements
|
// Loop through all index statements
|
||||||
for ix in self.ix(opt, &txn).await?.iter() {
|
for ix in self.ix(opt, txn).await?.iter() {
|
||||||
// Calculate old values
|
// Calculate old values
|
||||||
let o = Self::build_opt_array(ctx, opt, ix, &self.initial).await?;
|
let o = Self::build_opt_array(ctx, opt, txn, ix, &self.initial).await?;
|
||||||
|
|
||||||
// Calculate new values
|
// Calculate new values
|
||||||
let n = Self::build_opt_array(ctx, opt, ix, &self.current).await?;
|
let n = Self::build_opt_array(ctx, opt, txn, ix, &self.current).await?;
|
||||||
|
|
||||||
// Update the index entries
|
// Update the index entries
|
||||||
if opt.force || o != n {
|
if opt.force || o != n {
|
||||||
|
@ -75,17 +74,16 @@ impl<'a> Document<'a> {
|
||||||
async fn build_opt_array(
|
async fn build_opt_array(
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
ix: &DefineIndexStatement,
|
ix: &DefineIndexStatement,
|
||||||
value: &Value,
|
doc: &CursorDoc<'_>,
|
||||||
) -> Result<Option<Array>, Error> {
|
) -> Result<Option<Array>, Error> {
|
||||||
if !value.is_some() {
|
if !doc.doc.is_some() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(value);
|
|
||||||
let mut o = Array::with_capacity(ix.cols.len());
|
let mut o = Array::with_capacity(ix.cols.len());
|
||||||
for i in ix.cols.iter() {
|
for i in ix.cols.iter() {
|
||||||
let v = i.compute(&ctx, opt).await?;
|
let v = i.compute(ctx, opt, txn, Some(doc)).await?;
|
||||||
o.push(v);
|
o.push(v);
|
||||||
}
|
}
|
||||||
Ok(Some(o))
|
Ok(Some(o))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,63 +10,64 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check current record
|
// Check current record
|
||||||
match self.current.is_some() {
|
match self.current.doc.is_some() {
|
||||||
// Run INSERT clause
|
// Run INSERT clause
|
||||||
false => {
|
false => {
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Merge record data
|
// Merge record data
|
||||||
self.merge(ctx, opt, stm).await?;
|
self.merge(ctx, opt, txn, stm).await?;
|
||||||
// Merge fields data
|
// Merge fields data
|
||||||
self.field(ctx, opt, stm).await?;
|
self.field(ctx, opt, txn, stm).await?;
|
||||||
// Reset fields data
|
// Reset fields data
|
||||||
self.reset(ctx, opt, stm).await?;
|
self.reset(ctx, opt, txn, stm).await?;
|
||||||
// Clean fields data
|
// Clean fields data
|
||||||
self.clean(ctx, opt, stm).await?;
|
self.clean(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Store index data
|
// Store index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Store record data
|
// Store record data
|
||||||
self.store(ctx, opt, stm).await?;
|
self.store(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
// Run UPDATE clause
|
// Run UPDATE clause
|
||||||
true => {
|
true => {
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Alter record data
|
// Alter record data
|
||||||
self.alter(ctx, opt, stm).await?;
|
self.alter(ctx, opt, txn, stm).await?;
|
||||||
// Merge fields data
|
// Merge fields data
|
||||||
self.field(ctx, opt, stm).await?;
|
self.field(ctx, opt, txn, stm).await?;
|
||||||
// Reset fields data
|
// Reset fields data
|
||||||
self.reset(ctx, opt, stm).await?;
|
self.reset(ctx, opt, txn, stm).await?;
|
||||||
// Clean fields data
|
// Clean fields data
|
||||||
self.clean(ctx, opt, stm).await?;
|
self.clean(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Store index data
|
// Store index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Store record data
|
// Store record data
|
||||||
self.store(ctx, opt, stm).await?;
|
self.store(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Action;
|
|
||||||
use crate::dbs::Notification;
|
use crate::dbs::Notification;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Action, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
|
@ -12,14 +12,13 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if forced
|
// Check if forced
|
||||||
if !opt.force && !self.changed() {
|
if !opt.force && !self.changed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Check if we can send notifications
|
// Check if we can send notifications
|
||||||
|
@ -27,11 +26,11 @@ impl<'a> Document<'a> {
|
||||||
// Clone the sending channel
|
// Clone the sending channel
|
||||||
let chn = chn.clone();
|
let chn = chn.clone();
|
||||||
// Loop through all index statements
|
// Loop through all index statements
|
||||||
for lv in self.lv(opt, &txn).await?.iter() {
|
for lv in self.lv(opt, txn).await?.iter() {
|
||||||
// Create a new statement
|
// Create a new statement
|
||||||
let lq = Statement::from(lv);
|
let lq = Statement::from(lv);
|
||||||
// Check LIVE SELECT where condition
|
// Check LIVE SELECT where condition
|
||||||
if self.check(ctx, opt, &lq).await.is_err() {
|
if self.check(ctx, opt, txn, &lq).await.is_err() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Check what type of data change this is
|
// Check what type of data change this is
|
||||||
|
@ -54,7 +53,7 @@ impl<'a> Document<'a> {
|
||||||
chn.send(Notification {
|
chn.send(Notification {
|
||||||
id: lv.id.0,
|
id: lv.id.0,
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
result: self.pluck(ctx, opt, &lq).await?,
|
result: self.pluck(ctx, opt, txn, &lq).await?,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,7 +65,7 @@ impl<'a> Document<'a> {
|
||||||
chn.send(Notification {
|
chn.send(Notification {
|
||||||
id: lv.id.0,
|
id: lv.id.0,
|
||||||
action: Action::Update,
|
action: Action::Update,
|
||||||
result: self.pluck(ctx, opt, &lq).await?,
|
result: self.pluck(ctx, opt, txn, &lq).await?,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
use crate::dbs::Workable;
|
use crate::dbs::Workable;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
|
||||||
|
@ -10,21 +10,20 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Set default field values
|
// Set default field values
|
||||||
self.current.to_mut().def(rid);
|
self.current.doc.to_mut().def(rid);
|
||||||
// This is an INSERT statement
|
// This is an INSERT statement
|
||||||
if let Workable::Insert(v) = &self.extras {
|
if let Workable::Insert(v) = &self.extras {
|
||||||
let mut ctx = Context::new(ctx);
|
let v = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||||
ctx.add_cursor_doc(&self.current);
|
self.current.doc.to_mut().merge(v)?;
|
||||||
let v = v.compute(&ctx, opt).await?;
|
|
||||||
self.current.to_mut().merge(v)?;
|
|
||||||
}
|
}
|
||||||
// Set default field values
|
// Set default field values
|
||||||
self.current.to_mut().def(rid);
|
self.current.doc.to_mut().def(rid);
|
||||||
// Carry on
|
// Carry on
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::idiom::Idiom;
|
use crate::sql::idiom::Idiom;
|
||||||
|
@ -14,6 +14,7 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Ensure futures are run
|
// Ensure futures are run
|
||||||
|
@ -23,56 +24,34 @@ impl<'a> Document<'a> {
|
||||||
Some(v) => match v {
|
Some(v) => match v {
|
||||||
Output::None => Err(Error::Ignore),
|
Output::None => Err(Error::Ignore),
|
||||||
Output::Null => Ok(Value::Null),
|
Output::Null => Ok(Value::Null),
|
||||||
Output::Diff => Ok(self.initial.diff(&self.current, Idiom::default()).into()),
|
Output::Diff => {
|
||||||
Output::After => {
|
Ok(self.initial.doc.diff(self.current.doc.as_ref(), Idiom::default()).into())
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
self.current.compute(&ctx, opt).await
|
|
||||||
}
|
}
|
||||||
|
Output::After => self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await,
|
||||||
Output::Before => {
|
Output::Before => {
|
||||||
let mut ctx = Context::new(ctx);
|
self.initial.doc.compute(ctx, opt, txn, Some(&self.initial)).await
|
||||||
ctx.add_cursor_doc(&self.initial);
|
|
||||||
self.initial.compute(&ctx, opt).await
|
|
||||||
}
|
|
||||||
Output::Fields(v) => {
|
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
v.compute(&ctx, opt, false).await
|
|
||||||
}
|
}
|
||||||
|
Output::Fields(v) => v.compute(ctx, opt, txn, Some(&self.current), false).await,
|
||||||
},
|
},
|
||||||
None => match stm {
|
None => match stm {
|
||||||
Statement::Live(s) => match s.expr.len() {
|
Statement::Live(s) => match s.expr.len() {
|
||||||
0 => Ok(self.initial.diff(&self.current, Idiom::default()).into()),
|
0 => Ok(self.initial.doc.diff(&self.current.doc, Idiom::default()).into()),
|
||||||
_ => {
|
_ => s.expr.compute(ctx, opt, txn, Some(&self.current), false).await,
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
s.expr.compute(&ctx, opt, false).await
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Statement::Select(s) => {
|
Statement::Select(s) => {
|
||||||
let mut ctx = Context::new(ctx);
|
s.expr.compute(ctx, opt, txn, Some(&self.current), s.group.is_some()).await
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
s.expr.compute(&ctx, opt, s.group.is_some()).await
|
|
||||||
}
|
}
|
||||||
Statement::Create(_) => {
|
Statement::Create(_) => {
|
||||||
let mut ctx = Context::new(ctx);
|
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
self.current.compute(&ctx, opt).await
|
|
||||||
}
|
}
|
||||||
Statement::Update(_) => {
|
Statement::Update(_) => {
|
||||||
let mut ctx = Context::new(ctx);
|
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
self.current.compute(&ctx, opt).await
|
|
||||||
}
|
}
|
||||||
Statement::Relate(_) => {
|
Statement::Relate(_) => {
|
||||||
let mut ctx = Context::new(ctx);
|
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
self.current.compute(&ctx, opt).await
|
|
||||||
}
|
}
|
||||||
Statement::Insert(_) => {
|
Statement::Insert(_) => {
|
||||||
let mut ctx = Context::new(ctx);
|
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
self.current.compute(&ctx, opt).await
|
|
||||||
}
|
}
|
||||||
_ => Err(Error::Ignore),
|
_ => Err(Error::Ignore),
|
||||||
},
|
},
|
||||||
|
@ -81,28 +60,29 @@ impl<'a> Document<'a> {
|
||||||
if self.id.is_some() {
|
if self.id.is_some() {
|
||||||
// Should we run permissions checks?
|
// Should we run permissions checks?
|
||||||
if opt.perms && opt.auth.perms() {
|
if opt.perms && opt.auth.perms() {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Loop through all field statements
|
// Loop through all field statements
|
||||||
for fd in self.fd(opt, &txn).await?.iter() {
|
for fd in self.fd(opt, txn).await?.iter() {
|
||||||
// Loop over each field in document
|
// Loop over each field in document
|
||||||
for k in out.each(&fd.name).iter() {
|
for k in out.each(&fd.name).iter() {
|
||||||
// Process the field permissions
|
// Process the field permissions
|
||||||
match &fd.permissions.select {
|
match &fd.permissions.select {
|
||||||
Permission::Full => (),
|
Permission::Full => (),
|
||||||
Permission::None => out.del(ctx, opt, k).await?,
|
Permission::None => out.del(ctx, opt, txn, k).await?,
|
||||||
Permission::Specific(e) => {
|
Permission::Specific(e) => {
|
||||||
// Disable permissions
|
// Disable permissions
|
||||||
let opt = &opt.new_with_perms(false);
|
let opt = &opt.new_with_perms(false);
|
||||||
// Get the current value
|
// Get the current value
|
||||||
let val = self.current.pick(k);
|
let val = self.current.doc.pick(k);
|
||||||
// Configure the context
|
// Configure the context
|
||||||
let mut ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
ctx.add_value("value", &val);
|
ctx.add_value("value", &val);
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Process the PERMISSION clause
|
// Process the PERMISSION clause
|
||||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
if !e
|
||||||
out.del(&ctx, opt, k).await?
|
.compute(&ctx, opt, txn, Some(&self.current))
|
||||||
|
.await?
|
||||||
|
.is_truthy()
|
||||||
|
{
|
||||||
|
out.del(&ctx, opt, txn, k).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +91,7 @@ impl<'a> Document<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove metadata fields on output
|
// Remove metadata fields on output
|
||||||
out.del(ctx, opt, &*META).await?;
|
out.del(ctx, opt, txn, &*META).await?;
|
||||||
// Output result
|
// Output result
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::dir::Dir;
|
use crate::sql::dir::Dir;
|
||||||
|
@ -17,16 +17,15 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if forced
|
// Check if forced
|
||||||
if !opt.force && !self.changed() {
|
if !opt.force && !self.changed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check if the table is a view
|
// Check if the table is a view
|
||||||
if self.tb(opt, &txn).await?.drop {
|
if self.tb(opt, txn).await?.drop {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Clone transaction
|
// Clone transaction
|
||||||
|
@ -39,7 +38,11 @@ impl<'a> Document<'a> {
|
||||||
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
|
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
|
||||||
run.del(key).await?;
|
run.del(key).await?;
|
||||||
// Purge the record edges
|
// Purge the record edges
|
||||||
match (self.initial.pick(&*EDGE), self.initial.pick(&*IN), self.initial.pick(&*OUT)) {
|
match (
|
||||||
|
self.initial.doc.pick(&*EDGE),
|
||||||
|
self.initial.doc.pick(&*IN),
|
||||||
|
self.initial.doc.pick(&*OUT),
|
||||||
|
) {
|
||||||
(Value::Bool(true), Value::Thing(ref l), Value::Thing(ref r)) => {
|
(Value::Bool(true), Value::Thing(ref l), Value::Thing(ref r)) => {
|
||||||
// Get temporary edge references
|
// Get temporary edge references
|
||||||
let (ref o, ref i) = (Dir::Out, Dir::In);
|
let (ref o, ref i) = (Dir::Out, Dir::In);
|
||||||
|
@ -69,7 +72,7 @@ impl<'a> Document<'a> {
|
||||||
..DeleteStatement::default()
|
..DeleteStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the delete statement
|
// Execute the delete statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Alter record data
|
// Alter record data
|
||||||
self.alter(ctx, opt, stm).await?;
|
self.alter(ctx, opt, txn, stm).await?;
|
||||||
// Merge fields data
|
// Merge fields data
|
||||||
self.field(ctx, opt, stm).await?;
|
self.field(ctx, opt, txn, stm).await?;
|
||||||
// Reset fields data
|
// Reset fields data
|
||||||
self.reset(ctx, opt, stm).await?;
|
self.reset(ctx, opt, txn, stm).await?;
|
||||||
// Clean fields data
|
// Clean fields data
|
||||||
self.clean(ctx, opt, stm).await?;
|
self.clean(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Store record edges
|
// Store record edges
|
||||||
self.edges(ctx, opt, stm).await?;
|
self.edges(ctx, opt, txn, stm).await?;
|
||||||
// Store index data
|
// Store index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Store record data
|
// Store record data
|
||||||
self.store(ctx, opt, stm).await?;
|
self.store(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::paths::EDGE;
|
use crate::sql::paths::EDGE;
|
||||||
|
@ -13,17 +14,18 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
_ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the record id
|
// Get the record id
|
||||||
let rid = self.id.as_ref().unwrap();
|
let rid = self.id.as_ref().unwrap();
|
||||||
// Set default field values
|
// Set default field values
|
||||||
self.current.to_mut().def(rid);
|
self.current.doc.to_mut().def(rid);
|
||||||
// Ensure edge fields are reset
|
// Ensure edge fields are reset
|
||||||
if self.initial.pick(&*EDGE).is_true() {
|
if self.initial.doc.pick(&*EDGE).is_true() {
|
||||||
self.current.to_mut().put(&*EDGE, Value::Bool(true));
|
self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
|
||||||
self.current.to_mut().put(&*IN, self.initial.pick(&*IN));
|
self.current.doc.to_mut().put(&*IN, self.initial.doc.pick(&*IN));
|
||||||
self.current.to_mut().put(&*OUT, self.initial.pick(&*OUT));
|
self.current.doc.to_mut().put(&*OUT, self.initial.doc.pick(&*OUT));
|
||||||
}
|
}
|
||||||
// Carry on
|
// Carry on
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,15 +10,16 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check if record exists
|
// Check if record exists
|
||||||
self.empty(ctx, opt, stm).await?;
|
self.empty(ctx, opt, txn, stm).await?;
|
||||||
// Check where clause
|
// Check where clause
|
||||||
self.check(ctx, opt, stm).await?;
|
self.check(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
|
||||||
impl<'a> Document<'a> {
|
impl<'a> Document<'a> {
|
||||||
pub async fn store(
|
pub async fn store(
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
_ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
_stm: &Statement<'_>,
|
_stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check if forced
|
// Check if forced
|
||||||
if !opt.force && !self.changed() {
|
if !opt.force && !self.changed() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Check if the table is a view
|
// Check if the table is a view
|
||||||
if self.tb(opt, &txn).await?.drop {
|
if self.tb(opt, txn).await?.drop {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::data::Data;
|
use crate::sql::data::Data;
|
||||||
|
@ -33,6 +33,7 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Check tables
|
// Check tables
|
||||||
|
@ -55,43 +56,41 @@ impl<'a> Document<'a> {
|
||||||
} else {
|
} else {
|
||||||
Action::Update
|
Action::Update
|
||||||
};
|
};
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Loop through all foreign table statements
|
// Loop through all foreign table statements
|
||||||
for ft in self.ft(opt, &txn).await?.iter() {
|
for ft in self.ft(opt, txn).await?.iter() {
|
||||||
// Get the table definition
|
// Get the table definition
|
||||||
let tb = ft.view.as_ref().unwrap();
|
let tb = ft.view.as_ref().unwrap();
|
||||||
// Check if there is a GROUP BY clause
|
// Check if there is a GROUP BY clause
|
||||||
match &tb.group {
|
match &tb.group {
|
||||||
// There is a GROUP BY clause specified
|
// There is a GROUP BY clause specified
|
||||||
Some(group) => {
|
Some(group) => {
|
||||||
let mut initial_ctx = Context::new(ctx);
|
|
||||||
initial_ctx.add_cursor_doc(&self.initial);
|
|
||||||
// Set the previous record id
|
// Set the previous record id
|
||||||
let old = Thing {
|
let old = Thing {
|
||||||
tb: ft.name.to_raw(),
|
tb: ft.name.to_raw(),
|
||||||
id: try_join_all(group.iter().map(|v| v.compute(&initial_ctx, opt)))
|
id: try_join_all(
|
||||||
.await?
|
group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.initial))),
|
||||||
.into_iter()
|
)
|
||||||
.collect::<Vec<_>>()
|
.await?
|
||||||
.into(),
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
let mut current_ctx = Context::new(ctx);
|
|
||||||
current_ctx.add_cursor_doc(&self.current);
|
|
||||||
// Set the current record id
|
// Set the current record id
|
||||||
let rid = Thing {
|
let rid = Thing {
|
||||||
tb: ft.name.to_raw(),
|
tb: ft.name.to_raw(),
|
||||||
id: try_join_all(group.iter().map(|v| v.compute(¤t_ctx, opt)))
|
id: try_join_all(
|
||||||
.await?
|
group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.current))),
|
||||||
.into_iter()
|
)
|
||||||
.collect::<Vec<_>>()
|
.await?
|
||||||
.into(),
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
// Check if a WHERE clause is specified
|
// Check if a WHERE clause is specified
|
||||||
match &tb.cond {
|
match &tb.cond {
|
||||||
// There is a WHERE clause specified
|
// There is a WHERE clause specified
|
||||||
Some(cond) => {
|
Some(cond) => {
|
||||||
match cond.compute(¤t_ctx, opt).await? {
|
match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
|
||||||
v if v.is_truthy() => {
|
v if v.is_truthy() => {
|
||||||
if !opt.force && act != Action::Create {
|
if !opt.force && act != Action::Create {
|
||||||
// Delete the old value
|
// Delete the old value
|
||||||
|
@ -99,11 +98,13 @@ impl<'a> Document<'a> {
|
||||||
// Modify the value in the table
|
// Modify the value in the table
|
||||||
let stm = UpdateStatement {
|
let stm = UpdateStatement {
|
||||||
what: Values(vec![Value::from(old)]),
|
what: Values(vec![Value::from(old)]),
|
||||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
data: Some(
|
||||||
|
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||||
|
),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
if act != Action::Delete {
|
if act != Action::Delete {
|
||||||
// Update the new value
|
// Update the new value
|
||||||
|
@ -111,11 +112,13 @@ impl<'a> Document<'a> {
|
||||||
// Modify the value in the table
|
// Modify the value in the table
|
||||||
let stm = UpdateStatement {
|
let stm = UpdateStatement {
|
||||||
what: Values(vec![Value::from(rid)]),
|
what: Values(vec![Value::from(rid)]),
|
||||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
data: Some(
|
||||||
|
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||||
|
),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -125,11 +128,13 @@ impl<'a> Document<'a> {
|
||||||
// Modify the value in the table
|
// Modify the value in the table
|
||||||
let stm = UpdateStatement {
|
let stm = UpdateStatement {
|
||||||
what: Values(vec![Value::from(old)]),
|
what: Values(vec![Value::from(old)]),
|
||||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
data: Some(
|
||||||
|
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||||
|
),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +147,11 @@ impl<'a> Document<'a> {
|
||||||
// Modify the value in the table
|
// Modify the value in the table
|
||||||
let stm = UpdateStatement {
|
let stm = UpdateStatement {
|
||||||
what: Values(vec![Value::from(old)]),
|
what: Values(vec![Value::from(old)]),
|
||||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
if act != Action::Delete {
|
if act != Action::Delete {
|
||||||
// Update the new value
|
// Update the new value
|
||||||
|
@ -154,11 +159,11 @@ impl<'a> Document<'a> {
|
||||||
// Modify the value in the table
|
// Modify the value in the table
|
||||||
let stm = UpdateStatement {
|
let stm = UpdateStatement {
|
||||||
what: Values(vec![Value::from(rid)]),
|
what: Values(vec![Value::from(rid)]),
|
||||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,13 +176,11 @@ impl<'a> Document<'a> {
|
||||||
id: rid.id.clone(),
|
id: rid.id.clone(),
|
||||||
};
|
};
|
||||||
// Use the current record data
|
// Use the current record data
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(&self.current);
|
|
||||||
// Check if a WHERE clause is specified
|
// Check if a WHERE clause is specified
|
||||||
match &tb.cond {
|
match &tb.cond {
|
||||||
// There is a WHERE clause specified
|
// There is a WHERE clause specified
|
||||||
Some(cond) => {
|
Some(cond) => {
|
||||||
match cond.compute(&ctx, opt).await? {
|
match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
|
||||||
v if v.is_truthy() => {
|
v if v.is_truthy() => {
|
||||||
// Define the statement
|
// Define the statement
|
||||||
let stm = match act {
|
let stm = match act {
|
||||||
|
@ -190,13 +193,21 @@ impl<'a> Document<'a> {
|
||||||
_ => Query::Update(UpdateStatement {
|
_ => Query::Update(UpdateStatement {
|
||||||
what: Values(vec![Value::from(rid)]),
|
what: Values(vec![Value::from(rid)]),
|
||||||
data: Some(Data::ReplaceExpression(
|
data: Some(Data::ReplaceExpression(
|
||||||
tb.expr.compute(&ctx, opt, false).await?,
|
tb.expr
|
||||||
|
.compute(
|
||||||
|
ctx,
|
||||||
|
opt,
|
||||||
|
txn,
|
||||||
|
Some(&self.current),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
)),
|
)),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(&ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Delete the value in the table
|
// Delete the value in the table
|
||||||
|
@ -205,7 +216,7 @@ impl<'a> Document<'a> {
|
||||||
..DeleteStatement::default()
|
..DeleteStatement::default()
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(&ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,13 +233,15 @@ impl<'a> Document<'a> {
|
||||||
_ => Query::Update(UpdateStatement {
|
_ => Query::Update(UpdateStatement {
|
||||||
what: Values(vec![Value::from(rid)]),
|
what: Values(vec![Value::from(rid)]),
|
||||||
data: Some(Data::ReplaceExpression(
|
data: Some(Data::ReplaceExpression(
|
||||||
tb.expr.compute(&ctx, opt, false).await?,
|
tb.expr
|
||||||
|
.compute(ctx, opt, txn, Some(&self.current), false)
|
||||||
|
.await?,
|
||||||
)),
|
)),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
// Execute the statement
|
// Execute the statement
|
||||||
stm.compute(&ctx, opt).await?;
|
stm.compute(ctx, opt, txn, None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,16 +255,16 @@ impl<'a> Document<'a> {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
act: Action,
|
act: Action,
|
||||||
exp: &Fields,
|
exp: &Fields,
|
||||||
) -> Result<Data, Error> {
|
) -> Result<Data, Error> {
|
||||||
//
|
//
|
||||||
let mut ops: Ops = vec![];
|
let mut ops: Ops = vec![];
|
||||||
// Create a new context with the initial or the current doc
|
// Create a new context with the initial or the current doc
|
||||||
let mut ctx = Context::new(ctx);
|
let doc = match act {
|
||||||
match act {
|
Action::Delete => Some(&self.initial),
|
||||||
Action::Delete => ctx.add_cursor_doc(self.initial.as_ref()),
|
Action::Update => Some(&self.current),
|
||||||
Action::Update => ctx.add_cursor_doc(self.current.as_ref()),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
|
@ -266,29 +279,29 @@ impl<'a> Document<'a> {
|
||||||
match expr {
|
match expr {
|
||||||
Value::Function(f) if f.is_rolling() => match f.name() {
|
Value::Function(f) if f.is_rolling() => match f.name() {
|
||||||
"count" => {
|
"count" => {
|
||||||
let val = f.compute(&ctx, opt).await?;
|
let val = f.compute(ctx, opt, txn, doc).await?;
|
||||||
self.chg(&mut ops, &act, idiom, val);
|
self.chg(&mut ops, &act, idiom, val);
|
||||||
}
|
}
|
||||||
"math::sum" => {
|
"math::sum" => {
|
||||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||||
self.chg(&mut ops, &act, idiom, val);
|
self.chg(&mut ops, &act, idiom, val);
|
||||||
}
|
}
|
||||||
"math::min" => {
|
"math::min" => {
|
||||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||||
self.min(&mut ops, &act, idiom, val);
|
self.min(&mut ops, &act, idiom, val);
|
||||||
}
|
}
|
||||||
"math::max" => {
|
"math::max" => {
|
||||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||||
self.max(&mut ops, &act, idiom, val);
|
self.max(&mut ops, &act, idiom, val);
|
||||||
}
|
}
|
||||||
"math::mean" => {
|
"math::mean" => {
|
||||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||||
self.mean(&mut ops, &act, idiom, val);
|
self.mean(&mut ops, &act, idiom, val);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let val = expr.compute(&ctx, opt).await?;
|
let val = expr.compute(ctx, opt, txn, doc).await?;
|
||||||
self.set(&mut ops, idiom, val);
|
self.set(&mut ops, idiom, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
stm: &Statement<'_>,
|
stm: &Statement<'_>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Check where clause
|
// Check where clause
|
||||||
self.check(ctx, opt, stm).await?;
|
self.check(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Alter record data
|
// Alter record data
|
||||||
self.alter(ctx, opt, stm).await?;
|
self.alter(ctx, opt, txn, stm).await?;
|
||||||
// Merge fields data
|
// Merge fields data
|
||||||
self.field(ctx, opt, stm).await?;
|
self.field(ctx, opt, txn, stm).await?;
|
||||||
// Reset fields data
|
// Reset fields data
|
||||||
self.reset(ctx, opt, stm).await?;
|
self.reset(ctx, opt, txn, stm).await?;
|
||||||
// Clean fields data
|
// Clean fields data
|
||||||
self.clean(ctx, opt, stm).await?;
|
self.clean(ctx, opt, txn, stm).await?;
|
||||||
// Check if allowed
|
// Check if allowed
|
||||||
self.allow(ctx, opt, stm).await?;
|
self.allow(ctx, opt, txn, stm).await?;
|
||||||
// Store index data
|
// Store index data
|
||||||
self.index(ctx, opt, stm).await?;
|
self.index(ctx, opt, txn, stm).await?;
|
||||||
// Store record data
|
// Store record data
|
||||||
self.store(ctx, opt, stm).await?;
|
self.store(ctx, opt, txn, stm).await?;
|
||||||
// Run table queries
|
// Run table queries
|
||||||
self.table(ctx, opt, stm).await?;
|
self.table(ctx, opt, txn, stm).await?;
|
||||||
// Run lives queries
|
// Run lives queries
|
||||||
self.lives(ctx, opt, stm).await?;
|
self.lives(ctx, opt, txn, stm).await?;
|
||||||
// Run event queries
|
// Run event queries
|
||||||
self.event(ctx, opt, stm).await?;
|
self.event(ctx, opt, txn, stm).await?;
|
||||||
// Yield document
|
// Yield document
|
||||||
self.pluck(ctx, opt, stm).await
|
self.pluck(ctx, opt, txn, stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
//! Executes functions from SQL. If there is an SQL function it will be defined in this module.
|
//! Executes functions from SQL. If there is an SQL function it will be defined in this module.
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
|
||||||
|
@ -29,7 +31,13 @@ pub mod r#type;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
/// Attempts to run any function
|
/// Attempts to run any function
|
||||||
pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
pub async fn run(
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
name: &str,
|
||||||
|
args: Vec<Value>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
if name.eq("sleep")
|
if name.eq("sleep")
|
||||||
|| name.starts_with("search")
|
|| name.starts_with("search")
|
||||||
|| name.starts_with("http")
|
|| name.starts_with("http")
|
||||||
|
@ -38,7 +46,7 @@ pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Valu
|
||||||
|| name.starts_with("crypto::pbkdf2")
|
|| name.starts_with("crypto::pbkdf2")
|
||||||
|| name.starts_with("crypto::scrypt")
|
|| name.starts_with("crypto::scrypt")
|
||||||
{
|
{
|
||||||
asynchronous(ctx, name, args).await
|
asynchronous(ctx, Some(txn), doc, name, args).await
|
||||||
} else {
|
} else {
|
||||||
synchronous(ctx, name, args)
|
synchronous(ctx, name, args)
|
||||||
}
|
}
|
||||||
|
@ -266,7 +274,13 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to run any asynchronous function.
|
/// Attempts to run any asynchronous function.
|
||||||
pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
pub async fn asynchronous(
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
txn: Option<&Transaction>,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
name: &str,
|
||||||
|
args: Vec<Value>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Wrappers return a function as opposed to a value so that the dispatch! method can always
|
// Wrappers return a function as opposed to a value so that the dispatch! method can always
|
||||||
// perform a function call.
|
// perform a function call.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -302,9 +316,9 @@ pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Re
|
||||||
"http::patch" => http::patch(ctx).await,
|
"http::patch" => http::patch(ctx).await,
|
||||||
"http::delete" => http::delete(ctx).await,
|
"http::delete" => http::delete(ctx).await,
|
||||||
//
|
//
|
||||||
"search::score" => search::score(ctx).await,
|
"search::score" => search::score((ctx, txn, doc)).await,
|
||||||
"search::highlight" => search::highlight(ctx).await,
|
"search::highlight" => search::highlight((ctx,txn, doc)).await,
|
||||||
"search::offsets" => search::offsets(ctx).await,
|
"search::offsets" => search::offsets((ctx, txn, doc)).await,
|
||||||
//
|
//
|
||||||
"sleep" => sleep::sleep(ctx).await,
|
"sleep" => sleep::sleep(ctx).await,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::TryAdd;
|
use crate::sql::value::TryAdd;
|
||||||
use crate::sql::value::TryDiv;
|
use crate::sql::value::TryDiv;
|
||||||
|
@ -165,13 +167,18 @@ pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> {
|
||||||
Ok(a.intersects(b).into())
|
Ok(a.intersects(b).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn matches(ctx: &Context<'_>, e: &Expression) -> Result<Value, Error> {
|
pub(crate) async fn matches(
|
||||||
if let Some(thg) = ctx.thing() {
|
ctx: &Context<'_>,
|
||||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
txn: &Transaction,
|
||||||
// Clone transaction
|
doc: Option<&CursorDoc<'_>>,
|
||||||
let txn = ctx.try_clone_transaction()?;
|
e: &Expression,
|
||||||
// Check the matches
|
) -> Result<Value, Error> {
|
||||||
return exe.matches(&txn, thg, e).await;
|
if let Some(doc) = doc {
|
||||||
|
if let Some(thg) = doc.rid {
|
||||||
|
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||||
|
// Check the matches
|
||||||
|
return exe.matches(txn, thg, e).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Value::Bool(false))
|
Ok(Value::Bool(false))
|
||||||
|
|
|
@ -5,7 +5,8 @@ use super::modules;
|
||||||
use super::modules::loader;
|
use super::modules::loader;
|
||||||
use super::modules::resolver;
|
use super::modules::resolver;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use js::async_with;
|
use js::async_with;
|
||||||
|
@ -19,6 +20,8 @@ use js::Module;
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
_opt: &Options,
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
src: &str,
|
src: &str,
|
||||||
arg: Vec<Value>,
|
arg: Vec<Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
|
@ -26,8 +29,6 @@ pub async fn run(
|
||||||
if ctx.is_done() {
|
if ctx.is_done() {
|
||||||
return Ok(Value::None);
|
return Ok(Value::None);
|
||||||
}
|
}
|
||||||
// Get the optional doc
|
|
||||||
let doc = ctx.doc();
|
|
||||||
// Create an JavaScript context
|
// Create an JavaScript context
|
||||||
let run = js::AsyncRuntime::new().unwrap();
|
let run = js::AsyncRuntime::new().unwrap();
|
||||||
// Explicitly set max stack size to 256 KiB
|
// Explicitly set max stack size to 256 KiB
|
||||||
|
@ -68,6 +69,8 @@ pub async fn run(
|
||||||
let res = ctx.compile("script", src)?;
|
let res = ctx.compile("script", src)?;
|
||||||
// Attempt to fetch the main export
|
// Attempt to fetch the main export
|
||||||
let fnc = res.get::<_, Function>("default")?;
|
let fnc = res.get::<_, Function>("default")?;
|
||||||
|
// Extract the doc if any
|
||||||
|
let doc = doc.map(|v|v.doc.as_ref());
|
||||||
// Execute the main function
|
// Execute the main function
|
||||||
let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?;
|
let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?;
|
||||||
promise.await
|
promise.await
|
||||||
|
|
|
@ -68,7 +68,7 @@ async fn fut(js_ctx: js::Ctx<'_>, name: &str, args: Vec<Value>) -> Result<Value>
|
||||||
// Create a default context
|
// Create a default context
|
||||||
let ctx = Context::background();
|
let ctx = Context::background();
|
||||||
// Process the called function
|
// Process the called function
|
||||||
let res = fnc::asynchronous(&ctx, name, args).await;
|
let res = fnc::asynchronous(&ctx, None, None, name, args).await;
|
||||||
// Convert any response error
|
// Convert any response error
|
||||||
res.map_err(|err| {
|
res.map_err(|err| {
|
||||||
js::Exception::from_message(js_ctx, &err.to_string())
|
js::Exception::from_message(js_ctx, &err.to_string())
|
||||||
|
|
|
@ -1,37 +1,54 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::Value;
|
use crate::sql::Value;
|
||||||
|
|
||||||
pub async fn score(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> {
|
pub async fn score(
|
||||||
if let Some(thg) = ctx.thing() {
|
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
(match_ref,): (Value,),
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
return exe.score(txn, &match_ref, thg, ctx.doc_id()).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Value::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn highlight(
|
|
||||||
ctx: &Context<'_>,
|
|
||||||
(prefix, suffix, match_ref): (Value, Value, Value),
|
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(txn) = txn {
|
||||||
if let Some(thg) = ctx.thing() {
|
if let Some(doc) = doc {
|
||||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
if let Some(thg) = doc.rid {
|
||||||
let txn = ctx.try_clone_transaction()?;
|
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||||
return exe.highlight(txn, thg, prefix, suffix, &match_ref, doc).await;
|
return exe.score(txn, &match_ref, thg, doc.doc_id).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn offsets(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> {
|
pub async fn highlight(
|
||||||
if let Some(thg) = ctx.thing() {
|
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
(prefix, suffix, match_ref): (Value, Value, Value),
|
||||||
let txn = ctx.try_clone_transaction()?;
|
) -> Result<Value, Error> {
|
||||||
return exe.offsets(txn, thg, &match_ref).await;
|
if let Some(txn) = txn {
|
||||||
|
if let Some(doc) = doc {
|
||||||
|
if let Some(thg) = doc.rid {
|
||||||
|
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||||
|
return exe
|
||||||
|
.highlight(txn, thg, prefix, suffix, &match_ref, doc.doc.as_ref())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Value::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn offsets(
|
||||||
|
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||||
|
(match_ref,): (Value,),
|
||||||
|
) -> Result<Value, Error> {
|
||||||
|
if let Some(txn) = txn {
|
||||||
|
if let Some(doc) = doc {
|
||||||
|
if let Some(thg) = doc.rid {
|
||||||
|
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||||
|
return exe.offsets(txn, thg, &match_ref).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::btree::Payload;
|
use crate::idx::btree::Payload;
|
||||||
use crate::kvs::Key;
|
use crate::kvs::Key;
|
||||||
use async_trait::async_trait;
|
|
||||||
use fst::{IntoStreamer, Map, MapBuilder, Streamer};
|
use fst::{IntoStreamer, Map, MapBuilder, Streamer};
|
||||||
use radix_trie::{SubTrie, Trie, TrieCommon};
|
use radix_trie::{SubTrie, Trie, TrieCommon};
|
||||||
use serde::{de, ser, Deserialize, Serialize};
|
use serde::{de, ser, Deserialize, Serialize};
|
||||||
|
@ -361,7 +360,6 @@ impl Display for TrieKeys {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl BKeys for TrieKeys {
|
impl BKeys for TrieKeys {
|
||||||
fn with_key_val(key: Key, payload: Payload) -> Result<Self, Error> {
|
fn with_key_val(key: Key, payload: Payload) -> Result<Self, Error> {
|
||||||
let mut trie_keys = Self {
|
let mut trie_keys = Self {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::bkeys::BKeys;
|
use crate::idx::bkeys::BKeys;
|
||||||
use crate::idx::SerdeState;
|
use crate::idx::{IndexKeyBase, SerdeState};
|
||||||
use crate::kvs::{Key, Transaction};
|
use crate::kvs::{Key, Transaction};
|
||||||
use crate::sql::{Object, Value};
|
use crate::sql::{Object, Value};
|
||||||
use async_trait::async_trait;
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -12,13 +11,39 @@ use std::fmt::Debug;
|
||||||
pub(crate) type NodeId = u64;
|
pub(crate) type NodeId = u64;
|
||||||
pub(super) type Payload = u64;
|
pub(super) type Payload = u64;
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
#[derive(Clone)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
pub(super) enum KeyProvider {
|
||||||
pub(super) trait KeyProvider {
|
DocIds(IndexKeyBase),
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key;
|
DocLengths(IndexKeyBase),
|
||||||
fn get_state_key(&self) -> Key {
|
Postings(IndexKeyBase),
|
||||||
panic!("Not supported")
|
Terms(IndexKeyBase),
|
||||||
|
#[cfg(test)]
|
||||||
|
Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyProvider {
|
||||||
|
pub(super) fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||||
|
match self {
|
||||||
|
KeyProvider::DocIds(ikb) => ikb.new_bd_key(Some(node_id)),
|
||||||
|
KeyProvider::DocLengths(ikb) => ikb.new_bl_key(Some(node_id)),
|
||||||
|
KeyProvider::Postings(ikb) => ikb.new_bp_key(Some(node_id)),
|
||||||
|
KeyProvider::Terms(ikb) => ikb.new_bt_key(Some(node_id)),
|
||||||
|
#[cfg(test)]
|
||||||
|
KeyProvider::Debug => node_id.to_be_bytes().to_vec(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn get_state_key(&self) -> Key {
|
||||||
|
match self {
|
||||||
|
KeyProvider::DocIds(ikb) => ikb.new_bd_key(None),
|
||||||
|
KeyProvider::DocLengths(ikb) => ikb.new_bl_key(None),
|
||||||
|
KeyProvider::Postings(ikb) => ikb.new_bp_key(None),
|
||||||
|
KeyProvider::Terms(ikb) => ikb.new_bt_key(None),
|
||||||
|
#[cfg(test)]
|
||||||
|
KeyProvider::Debug => "".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn load_node<BK>(&self, tx: &mut Transaction, id: NodeId) -> Result<StoredNode<BK>, Error>
|
async fn load_node<BK>(&self, tx: &mut Transaction, id: NodeId) -> Result<StoredNode<BK>, Error>
|
||||||
where
|
where
|
||||||
BK: BKeys + Serialize + DeserializeOwned,
|
BK: BKeys + Serialize + DeserializeOwned,
|
||||||
|
@ -34,11 +59,8 @@ pub(super) trait KeyProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct BTree<K>
|
pub(super) struct BTree {
|
||||||
where
|
keys: KeyProvider,
|
||||||
K: KeyProvider + Clone,
|
|
||||||
{
|
|
||||||
keys: K,
|
|
||||||
state: State,
|
state: State,
|
||||||
full_size: u32,
|
full_size: u32,
|
||||||
updated: bool,
|
updated: bool,
|
||||||
|
@ -164,11 +186,8 @@ where
|
||||||
median_key: Key,
|
median_key: Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> BTree<K>
|
impl BTree {
|
||||||
where
|
pub(super) fn new(keys: KeyProvider, state: State) -> Self {
|
||||||
K: KeyProvider + Clone + Sync,
|
|
||||||
{
|
|
||||||
pub(super) fn new(keys: K, state: State) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
keys,
|
keys,
|
||||||
full_size: state.minimum_degree * 2 - 1,
|
full_size: state.minimum_degree * 2 - 1,
|
||||||
|
@ -730,18 +749,6 @@ mod tests {
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use test_log::test;
|
use test_log::test;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TestKeyProvider {}
|
|
||||||
|
|
||||||
impl KeyProvider for TestKeyProvider {
|
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
|
||||||
node_id.to_be_bytes().to_vec()
|
|
||||||
}
|
|
||||||
fn get_state_key(&self) -> Key {
|
|
||||||
"".into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_btree_state_serde() {
|
fn test_btree_state_serde() {
|
||||||
let s = State::new(3);
|
let s = State::new(3);
|
||||||
|
@ -766,15 +773,14 @@ mod tests {
|
||||||
let _: Node<TrieKeys> = Node::try_from_val(val).unwrap();
|
let _: Node<TrieKeys> = Node::try_from_val(val).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn insertions_test<F, BK, K>(
|
async fn insertions_test<F, BK>(
|
||||||
tx: &mut Transaction,
|
tx: &mut Transaction,
|
||||||
t: &mut BTree<K>,
|
t: &mut BTree,
|
||||||
samples_size: usize,
|
samples_size: usize,
|
||||||
sample_provider: F,
|
sample_provider: F,
|
||||||
) where
|
) where
|
||||||
F: Fn(usize) -> (Key, Payload),
|
F: Fn(usize) -> (Key, Payload),
|
||||||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||||
K: KeyProvider + Clone + Sync,
|
|
||||||
{
|
{
|
||||||
for i in 0..samples_size {
|
for i in 0..samples_size {
|
||||||
let (key, payload) = sample_provider(i);
|
let (key, payload) = sample_provider(i);
|
||||||
|
@ -791,10 +797,10 @@ mod tests {
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_btree_fst_small_order_sequential_insertions() {
|
async fn test_btree_fst_small_order_sequential_insertions() {
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(5));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(5));
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, get_key_value).await;
|
insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, get_key_value).await;
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -810,10 +816,10 @@ mod tests {
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_btree_trie_small_order_sequential_insertions() {
|
async fn test_btree_trie_small_order_sequential_insertions() {
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(6));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(6));
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, get_key_value).await;
|
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, get_key_value).await;
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -831,11 +837,11 @@ mod tests {
|
||||||
async fn test_btree_fst_small_order_random_insertions() {
|
async fn test_btree_fst_small_order_random_insertions() {
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(8));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(8));
|
||||||
let mut samples: Vec<usize> = (0..100).collect();
|
let mut samples: Vec<usize> = (0..100).collect();
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
samples.shuffle(&mut rng);
|
samples.shuffle(&mut rng);
|
||||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
let s = t.statistics::<FstKeys>(&mut tx).await.unwrap();
|
let s = t.statistics::<FstKeys>(&mut tx).await.unwrap();
|
||||||
|
@ -846,12 +852,11 @@ mod tests {
|
||||||
async fn test_btree_trie_small_order_random_insertions() {
|
async fn test_btree_trie_small_order_random_insertions() {
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(75));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(75));
|
||||||
let mut samples: Vec<usize> = (0..100).collect();
|
let mut samples: Vec<usize> = (0..100).collect();
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
samples.shuffle(&mut rng);
|
samples.shuffle(&mut rng);
|
||||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i]))
|
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
||||||
.await;
|
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
let s = t.statistics::<TrieKeys>(&mut tx).await.unwrap();
|
let s = t.statistics::<TrieKeys>(&mut tx).await.unwrap();
|
||||||
|
@ -862,8 +867,8 @@ mod tests {
|
||||||
async fn test_btree_fst_keys_large_order_sequential_insertions() {
|
async fn test_btree_fst_keys_large_order_sequential_insertions() {
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(60));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(60));
|
||||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 10000, get_key_value).await;
|
insertions_test::<_, FstKeys>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -881,8 +886,8 @@ mod tests {
|
||||||
async fn test_btree_trie_keys_large_order_sequential_insertions() {
|
async fn test_btree_trie_keys_large_order_sequential_insertions() {
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(60));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(60));
|
||||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 10000, get_key_value).await;
|
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -908,8 +913,8 @@ mod tests {
|
||||||
{
|
{
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(default_minimum_degree));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(default_minimum_degree));
|
||||||
insertions_test::<_, BK, _>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| {
|
insertions_test::<_, BK>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| {
|
||||||
(REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload)
|
(REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload)
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
@ -1006,7 +1011,7 @@ mod tests {
|
||||||
// This check node splitting. CLRS: Figure 18.7, page 498.
|
// This check node splitting. CLRS: Figure 18.7, page 498.
|
||||||
async fn clrs_insertion_test() {
|
async fn clrs_insertion_test() {
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
for (key, payload) in CLRS_EXAMPLE {
|
for (key, payload) in CLRS_EXAMPLE {
|
||||||
t.insert::<TrieKeys>(&mut tx, key.into(), payload).await.unwrap();
|
t.insert::<TrieKeys>(&mut tx, key.into(), payload).await.unwrap();
|
||||||
|
@ -1090,7 +1095,7 @@ mod tests {
|
||||||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||||
{
|
{
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
for (key, payload) in CLRS_EXAMPLE {
|
for (key, payload) in CLRS_EXAMPLE {
|
||||||
t.insert::<BK>(&mut tx, key.into(), payload).await.unwrap();
|
t.insert::<BK>(&mut tx, key.into(), payload).await.unwrap();
|
||||||
|
@ -1180,7 +1185,7 @@ mod tests {
|
||||||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||||
{
|
{
|
||||||
let ds = Datastore::new("memory").await.unwrap();
|
let ds = Datastore::new("memory").await.unwrap();
|
||||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||||
|
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
let mut expected_keys = HashMap::new();
|
let mut expected_keys = HashMap::new();
|
||||||
|
@ -1191,13 +1196,13 @@ mod tests {
|
||||||
tx.commit().await.unwrap();
|
tx.commit().await.unwrap();
|
||||||
|
|
||||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||||
print_tree::<BK, _>(&mut tx, &t).await;
|
print_tree::<BK>(&mut tx, &t).await;
|
||||||
|
|
||||||
for (key, _) in CLRS_EXAMPLE {
|
for (key, _) in CLRS_EXAMPLE {
|
||||||
debug!("------------------------");
|
debug!("------------------------");
|
||||||
debug!("Delete {}", key);
|
debug!("Delete {}", key);
|
||||||
t.delete::<BK>(&mut tx, key.into()).await.unwrap();
|
t.delete::<BK>(&mut tx, key.into()).await.unwrap();
|
||||||
print_tree::<BK, _>(&mut tx, &t).await;
|
print_tree::<BK>(&mut tx, &t).await;
|
||||||
|
|
||||||
// Check that every expected keys are still found in the tree
|
// Check that every expected keys are still found in the tree
|
||||||
expected_keys.remove(key);
|
expected_keys.remove(key);
|
||||||
|
@ -1259,9 +1264,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn print_tree<BK, K>(tx: &mut Transaction, t: &BTree<K>)
|
async fn print_tree<BK>(tx: &mut Transaction, t: &BTree)
|
||||||
where
|
where
|
||||||
K: KeyProvider + Clone + Sync,
|
|
||||||
BK: BKeys + Serialize + DeserializeOwned,
|
BK: BKeys + Serialize + DeserializeOwned,
|
||||||
{
|
{
|
||||||
debug!("----------------------------------");
|
debug!("----------------------------------");
|
||||||
|
@ -1289,10 +1293,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K> BTree<K>
|
impl BTree {
|
||||||
where
|
|
||||||
K: KeyProvider + Clone + Sync,
|
|
||||||
{
|
|
||||||
/// This is for debugging
|
/// This is for debugging
|
||||||
async fn inspect_nodes<BK, F>(
|
async fn inspect_nodes<BK, F>(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::bkeys::TrieKeys;
|
use crate::idx::bkeys::TrieKeys;
|
||||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||||
use crate::kvs::{Key, Transaction};
|
use crate::kvs::{Key, Transaction};
|
||||||
use roaring::RoaringTreemap;
|
use roaring::RoaringTreemap;
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) const NO_DOC_ID: u64 = u64::MAX;
|
||||||
pub(crate) struct DocIds {
|
pub(crate) struct DocIds {
|
||||||
state_key: Key,
|
state_key: Key,
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
btree: BTree<DocIdsKeyProvider>,
|
btree: BTree,
|
||||||
available_ids: Option<RoaringTreemap>,
|
available_ids: Option<RoaringTreemap>,
|
||||||
next_doc_id: DocId,
|
next_doc_id: DocId,
|
||||||
updated: bool,
|
updated: bool,
|
||||||
|
@ -25,9 +25,7 @@ impl DocIds {
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
default_btree_order: u32,
|
default_btree_order: u32,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let keys = DocIdsKeyProvider {
|
let keys = KeyProvider::DocIds(index_key_base.clone());
|
||||||
index_key_base: index_key_base.clone(),
|
|
||||||
};
|
|
||||||
let state_key: Key = keys.get_state_key();
|
let state_key: Key = keys.get_state_key();
|
||||||
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||||
State::try_from_val(val)?
|
State::try_from_val(val)?
|
||||||
|
@ -179,20 +177,6 @@ impl Resolved {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct DocIdsKeyProvider {
|
|
||||||
index_key_base: IndexKeyBase,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyProvider for DocIdsKeyProvider {
|
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
|
||||||
self.index_key_base.new_bd_key(Some(node_id))
|
|
||||||
}
|
|
||||||
fn get_state_key(&self) -> Key {
|
|
||||||
self.index_key_base.new_bd_key(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::idx::ft::docids::{DocIds, Resolved};
|
use crate::idx::ft::docids::{DocIds, Resolved};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::bkeys::TrieKeys;
|
use crate::idx::bkeys::TrieKeys;
|
||||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Payload, Statistics};
|
use crate::idx::btree::{BTree, KeyProvider, Payload, Statistics};
|
||||||
use crate::idx::ft::docids::DocId;
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||||
use crate::kvs::{Key, Transaction};
|
use crate::kvs::{Key, Transaction};
|
||||||
|
@ -9,7 +9,7 @@ pub(super) type DocLength = u64;
|
||||||
|
|
||||||
pub(super) struct DocLengths {
|
pub(super) struct DocLengths {
|
||||||
state_key: Key,
|
state_key: Key,
|
||||||
btree: BTree<DocLengthsKeyProvider>,
|
btree: BTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocLengths {
|
impl DocLengths {
|
||||||
|
@ -18,9 +18,7 @@ impl DocLengths {
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
default_btree_order: u32,
|
default_btree_order: u32,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let keys = DocLengthsKeyProvider {
|
let keys = KeyProvider::DocLengths(index_key_base);
|
||||||
index_key_base,
|
|
||||||
};
|
|
||||||
let state_key: Key = keys.get_state_key();
|
let state_key: Key = keys.get_state_key();
|
||||||
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||||
btree::State::try_from_val(val)?
|
btree::State::try_from_val(val)?
|
||||||
|
@ -70,21 +68,6 @@ impl DocLengths {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct DocLengthsKeyProvider {
|
|
||||||
index_key_base: IndexKeyBase,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyProvider for DocLengthsKeyProvider {
|
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
|
||||||
self.index_key_base.new_bl_key(Some(node_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_state_key(&self) -> Key {
|
|
||||||
self.index_key_base.new_bl_key(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::idx::ft::doclength::DocLengths;
|
use crate::idx::ft::doclength::DocLengths;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::bkeys::TrieKeys;
|
use crate::idx::bkeys::TrieKeys;
|
||||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||||
use crate::idx::ft::docids::DocId;
|
use crate::idx::ft::docids::DocId;
|
||||||
use crate::idx::ft::terms::TermId;
|
use crate::idx::ft::terms::TermId;
|
||||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||||
|
@ -11,7 +11,7 @@ pub(super) type TermFrequency = u64;
|
||||||
pub(super) struct Postings {
|
pub(super) struct Postings {
|
||||||
state_key: Key,
|
state_key: Key,
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
btree: BTree<PostingsKeyProvider>,
|
btree: BTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Postings {
|
impl Postings {
|
||||||
|
@ -20,9 +20,7 @@ impl Postings {
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
order: u32,
|
order: u32,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let keys = PostingsKeyProvider {
|
let keys = KeyProvider::Postings(index_key_base.clone());
|
||||||
index_key_base: index_key_base.clone(),
|
|
||||||
};
|
|
||||||
let state_key: Key = keys.get_state_key();
|
let state_key: Key = keys.get_state_key();
|
||||||
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||||
btree::State::try_from_val(val)?
|
btree::State::try_from_val(val)?
|
||||||
|
@ -79,20 +77,6 @@ impl Postings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(super) struct PostingsKeyProvider {
|
|
||||||
index_key_base: IndexKeyBase,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyProvider for PostingsKeyProvider {
|
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
|
||||||
self.index_key_base.new_bp_key(Some(node_id))
|
|
||||||
}
|
|
||||||
fn get_state_key(&self) -> Key {
|
|
||||||
self.index_key_base.new_bp_key(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::idx::ft::postings::Postings;
|
use crate::idx::ft::postings::Postings;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::bkeys::FstKeys;
|
use crate::idx::bkeys::FstKeys;
|
||||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||||
use crate::kvs::{Key, Transaction};
|
use crate::kvs::{Key, Transaction};
|
||||||
use roaring::RoaringTreemap;
|
use roaring::RoaringTreemap;
|
||||||
|
@ -11,7 +11,7 @@ pub(crate) type TermId = u64;
|
||||||
pub(super) struct Terms {
|
pub(super) struct Terms {
|
||||||
state_key: Key,
|
state_key: Key,
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
btree: BTree<TermsKeyProvider>,
|
btree: BTree,
|
||||||
available_ids: Option<RoaringTreemap>,
|
available_ids: Option<RoaringTreemap>,
|
||||||
next_term_id: TermId,
|
next_term_id: TermId,
|
||||||
updated: bool,
|
updated: bool,
|
||||||
|
@ -23,9 +23,7 @@ impl Terms {
|
||||||
index_key_base: IndexKeyBase,
|
index_key_base: IndexKeyBase,
|
||||||
default_btree_order: u32,
|
default_btree_order: u32,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let keys = TermsKeyProvider {
|
let keys = KeyProvider::Terms(index_key_base.clone());
|
||||||
index_key_base: index_key_base.clone(),
|
|
||||||
};
|
|
||||||
let state_key: Key = keys.get_state_key();
|
let state_key: Key = keys.get_state_key();
|
||||||
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||||
State::try_from_val(val)?
|
State::try_from_val(val)?
|
||||||
|
@ -143,20 +141,6 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TermsKeyProvider {
|
|
||||||
index_key_base: IndexKeyBase,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyProvider for TermsKeyProvider {
|
|
||||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
|
||||||
self.index_key_base.new_bt_key(Some(node_id))
|
|
||||||
}
|
|
||||||
fn get_state_key(&self) -> Key {
|
|
||||||
self.index_key_base.new_bt_key(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::idx::ft::postings::TermFrequency;
|
use crate::idx::ft::postings::TermFrequency;
|
||||||
|
|
|
@ -177,7 +177,7 @@ impl QueryExecutor {
|
||||||
|
|
||||||
pub(crate) async fn highlight(
|
pub(crate) async fn highlight(
|
||||||
&self,
|
&self,
|
||||||
txn: Transaction,
|
txn: &Transaction,
|
||||||
thg: &Thing,
|
thg: &Thing,
|
||||||
prefix: Value,
|
prefix: Value,
|
||||||
suffix: Value,
|
suffix: Value,
|
||||||
|
@ -195,7 +195,7 @@ impl QueryExecutor {
|
||||||
|
|
||||||
pub(crate) async fn offsets(
|
pub(crate) async fn offsets(
|
||||||
&self,
|
&self,
|
||||||
txn: Transaction,
|
txn: &Transaction,
|
||||||
thg: &Thing,
|
thg: &Thing,
|
||||||
match_ref: &Value,
|
match_ref: &Value,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
|
@ -208,7 +208,7 @@ impl QueryExecutor {
|
||||||
|
|
||||||
pub(crate) async fn score(
|
pub(crate) async fn score(
|
||||||
&self,
|
&self,
|
||||||
txn: Transaction,
|
txn: &Transaction,
|
||||||
match_ref: &Value,
|
match_ref: &Value,
|
||||||
rid: &Thing,
|
rid: &Thing,
|
||||||
mut doc_id: Option<DocId>,
|
mut doc_id: Option<DocId>,
|
||||||
|
|
|
@ -3,7 +3,7 @@ pub(crate) mod plan;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::{Iterable, Options};
|
use crate::dbs::{Iterable, Options, Transaction};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::planner::executor::QueryExecutor;
|
use crate::idx::planner::executor::QueryExecutor;
|
||||||
use crate::idx::planner::plan::{Plan, PlanBuilder};
|
use crate::idx::planner::plan::{Plan, PlanBuilder};
|
||||||
|
@ -30,17 +30,17 @@ impl<'a> QueryPlanner<'a> {
|
||||||
pub(crate) async fn get_iterable(
|
pub(crate) async fn get_iterable(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
|
txn: &Transaction,
|
||||||
t: Table,
|
t: Table,
|
||||||
) -> Result<Iterable, Error> {
|
) -> Result<Iterable, Error> {
|
||||||
let txn = ctx.try_clone_transaction()?;
|
let res = Tree::build(ctx, self.opt, txn, &t, self.cond).await?;
|
||||||
let res = Tree::build(ctx, self.opt, &txn, &t, self.cond).await?;
|
|
||||||
if let Some((node, im)) = res {
|
if let Some((node, im)) = res {
|
||||||
if let Some(plan) = AllAndStrategy::build(&node)? {
|
if let Some(plan) = AllAndStrategy::build(&node)? {
|
||||||
let e = QueryExecutor::new(self.opt, &txn, &t, im, Some(plan.e.clone())).await?;
|
let e = QueryExecutor::new(self.opt, txn, &t, im, Some(plan.e.clone())).await?;
|
||||||
self.executors.insert(t.0.clone(), e);
|
self.executors.insert(t.0.clone(), e);
|
||||||
return Ok(Iterable::Index(t, plan));
|
return Ok(Iterable::Index(t, plan));
|
||||||
}
|
}
|
||||||
let e = QueryExecutor::new(self.opt, &txn, &t, im, None).await?;
|
let e = QueryExecutor::new(self.opt, txn, &t, im, None).await?;
|
||||||
self.executors.insert(t.0.clone(), e);
|
self.executors.insert(t.0.clone(), e);
|
||||||
}
|
}
|
||||||
Ok(Iterable::Table(t))
|
Ok(Iterable::Table(t))
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::sql::index::Index;
|
||||||
use crate::sql::scoring::Scoring;
|
use crate::sql::scoring::Scoring;
|
||||||
use crate::sql::statements::DefineIndexStatement;
|
use crate::sql::statements::DefineIndexStatement;
|
||||||
use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value};
|
use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value};
|
||||||
use async_trait::async_trait;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -54,7 +53,7 @@ impl Plan {
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
exe: &QueryExecutor,
|
exe: &QueryExecutor,
|
||||||
) -> Result<Box<dyn ThingIterator>, Error> {
|
) -> Result<ThingIterator, Error> {
|
||||||
self.i.new_iterator(opt, txn, exe).await
|
self.i.new_iterator(opt, txn, exe).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,11 +127,11 @@ impl IndexOption {
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
exe: &QueryExecutor,
|
exe: &QueryExecutor,
|
||||||
) -> Result<Box<dyn ThingIterator>, Error> {
|
) -> Result<ThingIterator, Error> {
|
||||||
match &self.ix().index {
|
match &self.ix().index {
|
||||||
Index::Idx => {
|
Index::Idx => {
|
||||||
if self.op() == &Operator::Equal {
|
if self.op() == &Operator::Equal {
|
||||||
return Ok(Box::new(NonUniqueEqualThingIterator::new(
|
return Ok(ThingIterator::NonUniqueEqual(NonUniqueEqualThingIterator::new(
|
||||||
opt,
|
opt,
|
||||||
self.ix(),
|
self.ix(),
|
||||||
self.value(),
|
self.value(),
|
||||||
|
@ -141,7 +140,7 @@ impl IndexOption {
|
||||||
}
|
}
|
||||||
Index::Uniq => {
|
Index::Uniq => {
|
||||||
if self.op() == &Operator::Equal {
|
if self.op() == &Operator::Equal {
|
||||||
return Ok(Box::new(UniqueEqualThingIterator::new(
|
return Ok(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(
|
||||||
opt,
|
opt,
|
||||||
self.ix(),
|
self.ix(),
|
||||||
self.value(),
|
self.value(),
|
||||||
|
@ -156,7 +155,7 @@ impl IndexOption {
|
||||||
} => {
|
} => {
|
||||||
if let Operator::Matches(_) = self.op() {
|
if let Operator::Matches(_) = self.op() {
|
||||||
let td = exe.pre_match_terms_docs();
|
let td = exe.pre_match_terms_docs();
|
||||||
return Ok(Box::new(
|
return Ok(ThingIterator::Matches(
|
||||||
MatchesThingIterator::new(opt, txn, self.ix(), az, *hl, sc, *order, td)
|
MatchesThingIterator::new(opt, txn, self.ix(), az, *hl, sc, *order, td)
|
||||||
.await?,
|
.await?,
|
||||||
));
|
));
|
||||||
|
@ -167,23 +166,37 @@ impl IndexOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
pub(crate) enum ThingIterator {
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
NonUniqueEqual(NonUniqueEqualThingIterator),
|
||||||
pub(crate) trait ThingIterator: Send {
|
UniqueEqual(UniqueEqualThingIterator),
|
||||||
async fn next_batch(
|
Matches(MatchesThingIterator),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThingIterator {
|
||||||
|
pub(crate) async fn next_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
size: u32,
|
size: u32,
|
||||||
) -> Result<Vec<(Thing, DocId)>, Error>;
|
) -> Result<Vec<(Thing, DocId)>, Error> {
|
||||||
|
match self {
|
||||||
|
ThingIterator::NonUniqueEqual(i) => i.next_batch(tx, size).await,
|
||||||
|
ThingIterator::UniqueEqual(i) => i.next_batch(tx, size).await,
|
||||||
|
ThingIterator::Matches(i) => i.next_batch(tx, size).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NonUniqueEqualThingIterator {
|
pub(crate) struct NonUniqueEqualThingIterator {
|
||||||
beg: Vec<u8>,
|
beg: Vec<u8>,
|
||||||
end: Vec<u8>,
|
end: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonUniqueEqualThingIterator {
|
impl NonUniqueEqualThingIterator {
|
||||||
fn new(opt: &Options, ix: &DefineIndexStatement, v: &Value) -> Result<Self, Error> {
|
fn new(
|
||||||
|
opt: &Options,
|
||||||
|
ix: &DefineIndexStatement,
|
||||||
|
v: &Value,
|
||||||
|
) -> Result<NonUniqueEqualThingIterator, Error> {
|
||||||
let v = Array::from(v.clone());
|
let v = Array::from(v.clone());
|
||||||
let beg = key::index::prefix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
let beg = key::index::prefix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
||||||
let end = key::index::suffix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
let end = key::index::suffix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
||||||
|
@ -192,11 +205,7 @@ impl NonUniqueEqualThingIterator {
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
|
||||||
impl ThingIterator for NonUniqueEqualThingIterator {
|
|
||||||
async fn next_batch(
|
async fn next_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
|
@ -214,7 +223,7 @@ impl ThingIterator for NonUniqueEqualThingIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UniqueEqualThingIterator {
|
pub(crate) struct UniqueEqualThingIterator {
|
||||||
key: Option<Key>,
|
key: Option<Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,11 +235,7 @@ impl UniqueEqualThingIterator {
|
||||||
key: Some(key),
|
key: Some(key),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
|
||||||
impl ThingIterator for UniqueEqualThingIterator {
|
|
||||||
async fn next_batch(
|
async fn next_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
|
@ -245,7 +250,7 @@ impl ThingIterator for UniqueEqualThingIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MatchesThingIterator {
|
pub(crate) struct MatchesThingIterator {
|
||||||
hits: Option<HitsIterator>,
|
hits: Option<HitsIterator>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,11 +290,7 @@ impl MatchesThingIterator {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
|
||||||
impl ThingIterator for MatchesThingIterator {
|
|
||||||
async fn next_batch(
|
async fn next_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl<'a> TreeBuilder<'a> {
|
||||||
Value::Bool(_) => Node::Scalar(v.to_owned()),
|
Value::Bool(_) => Node::Scalar(v.to_owned()),
|
||||||
Value::Subquery(s) => self.eval_subquery(s).await?,
|
Value::Subquery(s) => self.eval_subquery(s).await?,
|
||||||
Value::Param(p) => {
|
Value::Param(p) => {
|
||||||
let v = p.compute(self.ctx, self.opt).await?;
|
let v = p.compute(self.ctx, self.opt, self.txn, None).await?;
|
||||||
self.eval_value(&v).await?
|
self.eval_value(&v).await?
|
||||||
}
|
}
|
||||||
_ => Node::Unsupported,
|
_ => Node::Unsupported,
|
||||||
|
|
|
@ -447,8 +447,6 @@ impl Datastore {
|
||||||
let txn = Arc::new(Mutex::new(txn));
|
let txn = Arc::new(Mutex::new(txn));
|
||||||
// Create a default context
|
// Create a default context
|
||||||
let mut ctx = Context::default();
|
let mut ctx = Context::default();
|
||||||
// Add the transaction
|
|
||||||
ctx.add_transaction(Some(&txn));
|
|
||||||
// Set the global query timeout
|
// Set the global query timeout
|
||||||
if let Some(timeout) = self.query_timeout {
|
if let Some(timeout) = self.query_timeout {
|
||||||
ctx.add_timeout(timeout);
|
ctx.add_timeout(timeout);
|
||||||
|
@ -462,7 +460,7 @@ impl Datastore {
|
||||||
// Store the query variables
|
// Store the query variables
|
||||||
let ctx = vars.attach(ctx)?;
|
let ctx = vars.attach(ctx)?;
|
||||||
// Compute the value
|
// Compute the value
|
||||||
let res = val.compute(&ctx, &opt).await?;
|
let res = val.compute(&ctx, &opt, &txn, None).await?;
|
||||||
// Store any data
|
// Store any data
|
||||||
match val.writeable() {
|
match val.writeable() {
|
||||||
true => txn.lock().await.commit().await?,
|
true => txn.lock().await.commit().await?,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::common::{closebracket, commas, openbracket};
|
use crate::sql::common::{closebracket, commas, openbracket};
|
||||||
|
@ -117,10 +118,16 @@ impl Array {
|
||||||
|
|
||||||
impl Array {
|
impl Array {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
let mut x = Self::with_capacity(self.len());
|
let mut x = Self::with_capacity(self.len());
|
||||||
for v in self.iter() {
|
for v in self.iter() {
|
||||||
match v.compute(ctx, opt).await {
|
match v.compute(ctx, opt, txn, doc).await {
|
||||||
Ok(v) => x.push(v),
|
Ok(v) => x.push(v),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::cnf::PROTECTED_PARAM_NAMES;
|
use crate::cnf::PROTECTED_PARAM_NAMES;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::{comment, mightbespace};
|
use crate::sql::comment::{comment, mightbespace};
|
||||||
use crate::sql::common::{closebraces, colons, openbraces};
|
use crate::sql::common::{closebraces, colons, openbraces};
|
||||||
|
@ -51,7 +52,13 @@ impl Block {
|
||||||
self.iter().any(Entry::writeable)
|
self.iter().any(Entry::writeable)
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Loop over the statements
|
// Loop over the statements
|
||||||
|
@ -61,7 +68,7 @@ impl Block {
|
||||||
// Check if the variable is a protected variable
|
// Check if the variable is a protected variable
|
||||||
let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) {
|
let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) {
|
||||||
// The variable isn't protected and can be stored
|
// The variable isn't protected and can be stored
|
||||||
false => v.compute(&ctx, opt).await,
|
false => v.compute(&ctx, opt, txn, doc).await,
|
||||||
// The user tried to set a protected variable
|
// The user tried to set a protected variable
|
||||||
true => {
|
true => {
|
||||||
return Err(Error::InvalidParam {
|
return Err(Error::InvalidParam {
|
||||||
|
@ -73,31 +80,31 @@ impl Block {
|
||||||
ctx.add_value(v.name.to_owned(), val);
|
ctx.add_value(v.name.to_owned(), val);
|
||||||
}
|
}
|
||||||
Entry::Ifelse(v) => {
|
Entry::Ifelse(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Select(v) => {
|
Entry::Select(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Create(v) => {
|
Entry::Create(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Update(v) => {
|
Entry::Update(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Delete(v) => {
|
Entry::Delete(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Relate(v) => {
|
Entry::Relate(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Insert(v) => {
|
Entry::Insert(v) => {
|
||||||
v.compute(&ctx, opt).await?;
|
v.compute(&ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
Entry::Output(v) => {
|
Entry::Output(v) => {
|
||||||
return v.compute(&ctx, opt).await;
|
return v.compute(&ctx, opt, txn, doc).await;
|
||||||
}
|
}
|
||||||
Entry::Value(v) => {
|
Entry::Value(v) => {
|
||||||
return v.compute(&ctx, opt).await;
|
return v.compute(&ctx, opt, txn, doc).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -36,11 +37,17 @@ impl Cast {
|
||||||
impl Cast {
|
impl Cast {
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Prevent long cast chains
|
// Prevent long cast chains
|
||||||
let opt = &opt.dive(1)?;
|
let opt = &opt.dive(1)?;
|
||||||
// Compute the value to be cast and convert it
|
// Compute the value to be cast and convert it
|
||||||
self.1.compute(ctx, opt).await?.convert_to(&self.0)
|
self.1.compute(ctx, opt, txn, doc).await?.convert_to(&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
|
@ -78,7 +79,13 @@ impl Constant {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
_opt: &Options,
|
||||||
|
_txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
Ok(match self.value() {
|
Ok(match self.value() {
|
||||||
ConstantValue::Datetime(d) => d.into(),
|
ConstantValue::Datetime(d) => d.into(),
|
||||||
ConstantValue::Float(f) => f.into(),
|
ConstantValue::Float(f) => f.into(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
|
@ -43,25 +43,26 @@ impl Data {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
tb: &Table,
|
tb: &Table,
|
||||||
) -> Result<Thing, Error> {
|
) -> Result<Thing, Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::MergeExpression(v) => {
|
Self::MergeExpression(v) => {
|
||||||
// This MERGE expression has an 'id' field
|
// This MERGE expression has an 'id' field
|
||||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||||
}
|
}
|
||||||
Self::ReplaceExpression(v) => {
|
Self::ReplaceExpression(v) => {
|
||||||
// This REPLACE expression has an 'id' field
|
// This REPLACE expression has an 'id' field
|
||||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||||
}
|
}
|
||||||
Self::ContentExpression(v) => {
|
Self::ContentExpression(v) => {
|
||||||
// This CONTENT expression has an 'id' field
|
// This CONTENT expression has an 'id' field
|
||||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||||
}
|
}
|
||||||
Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) {
|
Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) {
|
||||||
Some((_, _, v)) => {
|
Some((_, _, v)) => {
|
||||||
// This SET expression has an 'id' field
|
// This SET expression has an 'id' field
|
||||||
v.compute(ctx, opt).await?.generate(tb, false)
|
v.compute(ctx, opt, txn, None).await?.generate(tb, false)
|
||||||
}
|
}
|
||||||
// This SET expression had no 'id' field
|
// This SET expression had no 'id' field
|
||||||
_ => Ok(tb.generate()),
|
_ => Ok(tb.generate()),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::fnc;
|
use crate::fnc;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
|
@ -101,13 +102,19 @@ impl Expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
let (l, o, r) = match self {
|
let (l, o, r) = match self {
|
||||||
Self::Unary {
|
Self::Unary {
|
||||||
o,
|
o,
|
||||||
v,
|
v,
|
||||||
} => {
|
} => {
|
||||||
let operand = v.compute(ctx, opt).await?;
|
let operand = v.compute(ctx, opt, txn, doc).await?;
|
||||||
return match o {
|
return match o {
|
||||||
Operator::Neg => fnc::operate::neg(operand),
|
Operator::Neg => fnc::operate::neg(operand),
|
||||||
Operator::Not => fnc::operate::not(operand),
|
Operator::Not => fnc::operate::not(operand),
|
||||||
|
@ -121,7 +128,7 @@ impl Expression {
|
||||||
} => (l, o, r),
|
} => (l, o, r),
|
||||||
};
|
};
|
||||||
|
|
||||||
let l = l.compute(ctx, opt).await?;
|
let l = l.compute(ctx, opt, txn, doc).await?;
|
||||||
match o {
|
match o {
|
||||||
Operator::Or => {
|
Operator::Or => {
|
||||||
if let true = l.is_truthy() {
|
if let true = l.is_truthy() {
|
||||||
|
@ -145,7 +152,7 @@ impl Expression {
|
||||||
}
|
}
|
||||||
_ => {} // Continue
|
_ => {} // Continue
|
||||||
}
|
}
|
||||||
let r = r.compute(ctx, opt).await?;
|
let r = r.compute(ctx, opt, txn, doc).await?;
|
||||||
match o {
|
match o {
|
||||||
Operator::Or => fnc::operate::or(l, r),
|
Operator::Or => fnc::operate::or(l, r),
|
||||||
Operator::And => fnc::operate::and(l, r),
|
Operator::And => fnc::operate::and(l, r),
|
||||||
|
@ -181,7 +188,7 @@ impl Expression {
|
||||||
Operator::NoneInside => fnc::operate::inside_none(&l, &r),
|
Operator::NoneInside => fnc::operate::inside_none(&l, &r),
|
||||||
Operator::Outside => fnc::operate::outside(&l, &r),
|
Operator::Outside => fnc::operate::outside(&l, &r),
|
||||||
Operator::Intersects => fnc::operate::intersects(&l, &r),
|
Operator::Intersects => fnc::operate::intersects(&l, &r),
|
||||||
Operator::Matches(_) => fnc::operate::matches(ctx, self).await,
|
Operator::Matches(_) => fnc::operate::matches(ctx, txn, doc, self).await,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::common::commas;
|
use crate::sql::common::commas;
|
||||||
|
@ -75,17 +76,31 @@ impl Fields {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
group: bool,
|
group: bool,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
// Ensure futures are run
|
// Ensure futures are run
|
||||||
|
if let Some(doc) = doc {
|
||||||
|
self.compute_value(ctx, opt, txn, doc, group).await
|
||||||
|
} else {
|
||||||
|
let doc = CursorDoc::new(None, None, &Value::None);
|
||||||
|
self.compute_value(ctx, opt, txn, &doc, group).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn compute_value(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: &CursorDoc<'_>,
|
||||||
|
group: bool,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
let opt = &opt.new_with_futures(true);
|
let opt = &opt.new_with_futures(true);
|
||||||
//
|
|
||||||
let doc = ctx.doc().unwrap_or(&Value::None);
|
|
||||||
let mut ctx = Context::new(ctx);
|
|
||||||
ctx.add_cursor_doc(doc);
|
|
||||||
// Process the desired output
|
// Process the desired output
|
||||||
let mut out = match self.is_all() {
|
let mut out = match self.is_all() {
|
||||||
true => doc.compute(&ctx, opt).await?,
|
true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?,
|
||||||
false => Value::base(),
|
false => Value::base(),
|
||||||
};
|
};
|
||||||
for v in self.other() {
|
for v in self.other() {
|
||||||
|
@ -104,13 +119,13 @@ impl Fields {
|
||||||
Value::Function(f) if group && f.is_aggregate() => {
|
Value::Function(f) if group && f.is_aggregate() => {
|
||||||
let x = match f.args().len() {
|
let x = match f.args().len() {
|
||||||
// If no function arguments, then compute the result
|
// If no function arguments, then compute the result
|
||||||
0 => f.compute(&ctx, opt).await?,
|
0 => f.compute(ctx, opt, txn, Some(doc)).await?,
|
||||||
// If arguments, then pass the first value through
|
// If arguments, then pass the first value through
|
||||||
_ => f.args()[0].compute(&ctx, opt).await?,
|
_ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?,
|
||||||
};
|
};
|
||||||
// Check if this is a single VALUE field expression
|
// Check if this is a single VALUE field expression
|
||||||
match self.single().is_some() {
|
match self.single().is_some() {
|
||||||
false => out.set(&ctx, opt, idiom.as_ref(), x).await?,
|
false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?,
|
||||||
true => out = x,
|
true => out = x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,11 +138,15 @@ impl Fields {
|
||||||
// Use the last fetched value for each fetch
|
// Use the last fetched value for each fetch
|
||||||
let x = match res.last() {
|
let x = match res.last() {
|
||||||
Some((_, r)) => r,
|
Some((_, r)) => r,
|
||||||
None => doc,
|
None => doc.doc.as_ref(),
|
||||||
};
|
};
|
||||||
// Continue fetching the next idiom part
|
// Continue fetching the next idiom part
|
||||||
let x =
|
let x = x
|
||||||
x.get(&ctx, opt, v).await?.compute(&ctx, opt).await?.flatten();
|
.get(ctx, opt, txn, Some(doc), v)
|
||||||
|
.await?
|
||||||
|
.compute(ctx, opt, txn, Some(doc))
|
||||||
|
.await?
|
||||||
|
.flatten();
|
||||||
// Add the result to the temporary store
|
// Add the result to the temporary store
|
||||||
res.push((v, x));
|
res.push((v, x));
|
||||||
}
|
}
|
||||||
|
@ -137,23 +156,24 @@ impl Fields {
|
||||||
// This is an alias expression part
|
// This is an alias expression part
|
||||||
Some(a) => {
|
Some(a) => {
|
||||||
if let Some(i) = alias {
|
if let Some(i) = alias {
|
||||||
out.set(&ctx, opt, i, x.clone()).await?;
|
out.set(ctx, opt, txn, i, x.clone()).await?;
|
||||||
}
|
}
|
||||||
out.set(&ctx, opt, a, x).await?;
|
out.set(ctx, opt, txn, a, x).await?;
|
||||||
}
|
}
|
||||||
// This is the end of the expression
|
// This is the end of the expression
|
||||||
None => {
|
None => {
|
||||||
out.set(&ctx, opt, alias.as_ref().unwrap_or(v), x).await?
|
out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x)
|
||||||
|
.await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This expression is a normal field expression
|
// This expression is a normal field expression
|
||||||
_ => {
|
_ => {
|
||||||
let x = expr.compute(&ctx, opt).await?;
|
let x = expr.compute(ctx, opt, txn, Some(doc)).await?;
|
||||||
// Check if this is a single VALUE field expression
|
// Check if this is a single VALUE field expression
|
||||||
match self.single().is_some() {
|
match self.single().is_some() {
|
||||||
false => out.set(&ctx, opt, idiom.as_ref(), x).await?,
|
false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?,
|
||||||
true => out = x,
|
true => out = x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::fnc;
|
use crate::fnc;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
|
@ -131,7 +132,13 @@ impl Function {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Prevent long function chains
|
// Prevent long function chains
|
||||||
let opt = &opt.dive(1)?;
|
let opt = &opt.dive(1)?;
|
||||||
// Ensure futures are run
|
// Ensure futures are run
|
||||||
|
@ -140,15 +147,13 @@ impl Function {
|
||||||
match self {
|
match self {
|
||||||
Self::Normal(s, x) => {
|
Self::Normal(s, x) => {
|
||||||
// Compute the function arguments
|
// Compute the function arguments
|
||||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||||
// Run the normal function
|
// Run the normal function
|
||||||
fnc::run(ctx, s, a).await
|
fnc::run(ctx, txn, doc, s, a).await
|
||||||
}
|
}
|
||||||
Self::Custom(s, x) => {
|
Self::Custom(s, x) => {
|
||||||
// Get the function definition
|
// Get the function definition
|
||||||
let val = {
|
let val = {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Get the function definition
|
// Get the function definition
|
||||||
|
@ -165,7 +170,7 @@ impl Function {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Compute the function arguments
|
// Compute the function arguments
|
||||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Process the function arguments
|
// Process the function arguments
|
||||||
|
@ -173,16 +178,16 @@ impl Function {
|
||||||
ctx.add_value(name.to_raw(), val.coerce_to(&kind)?);
|
ctx.add_value(name.to_raw(), val.coerce_to(&kind)?);
|
||||||
}
|
}
|
||||||
// Run the custom function
|
// Run the custom function
|
||||||
val.block.compute(&ctx, opt).await
|
val.block.compute(&ctx, opt, txn, doc).await
|
||||||
}
|
}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
Self::Script(s, x) => {
|
Self::Script(s, x) => {
|
||||||
#[cfg(feature = "scripting")]
|
#[cfg(feature = "scripting")]
|
||||||
{
|
{
|
||||||
// Compute the function arguments
|
// Compute the function arguments
|
||||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||||
// Run the script function
|
// Run the script function
|
||||||
fnc::script::run(ctx, opt, s, a).await
|
fnc::script::run(ctx, opt, txn, doc, s, a).await
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "scripting"))]
|
#[cfg(not(feature = "scripting"))]
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::block::{block, Block};
|
use crate::sql::block::{block, Block};
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
|
@ -24,12 +25,18 @@ impl From<Value> for Future {
|
||||||
|
|
||||||
impl Future {
|
impl Future {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Prevent long future chains
|
// Prevent long future chains
|
||||||
let opt = &opt.dive(1)?;
|
let opt = &opt.dive(1)?;
|
||||||
// Process the future if enabled
|
// Process the future if enabled
|
||||||
match opt.futures {
|
match opt.futures {
|
||||||
true => self.0.compute(ctx, opt).await?.ok(),
|
true => self.0.compute(ctx, opt, txn, doc).await?.ok(),
|
||||||
false => Ok(self.clone().into()),
|
false => Ok(self.clone().into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::cnf::ID_CHARS;
|
use crate::cnf::ID_CHARS;
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::array::{array, Array};
|
use crate::sql::array::{array, Array};
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -166,15 +167,21 @@ impl Display for Id {
|
||||||
|
|
||||||
impl Id {
|
impl Id {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Id, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Id, Error> {
|
||||||
match self {
|
match self {
|
||||||
Id::Number(v) => Ok(Id::Number(*v)),
|
Id::Number(v) => Ok(Id::Number(*v)),
|
||||||
Id::String(v) => Ok(Id::String(v.clone())),
|
Id::String(v) => Ok(Id::String(v.clone())),
|
||||||
Id::Object(v) => match v.compute(ctx, opt).await? {
|
Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? {
|
||||||
Value::Object(v) => Ok(Id::Object(v)),
|
Value::Object(v) => Ok(Id::Object(v)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
Id::Array(v) => match v.compute(ctx, opt).await? {
|
Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? {
|
||||||
Value::Array(v) => Ok(Id::Array(v)),
|
Value::Array(v) => Ok(Id::Array(v)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::common::commas;
|
use crate::sql::common::commas;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -127,21 +128,29 @@ impl Idiom {
|
||||||
self.0.iter().any(|v| v.writeable())
|
self.0.iter().any(|v| v.writeable())
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self.first() {
|
match self.first() {
|
||||||
// The starting part is a value
|
// The starting part is a value
|
||||||
Some(Part::Value(v)) => {
|
Some(Part::Value(v)) => {
|
||||||
v.compute(ctx, opt)
|
v.compute(ctx, opt, txn, doc)
|
||||||
.await?
|
.await?
|
||||||
.get(ctx, opt, self.as_ref().next())
|
.get(ctx, opt, txn, doc, self.as_ref().next())
|
||||||
.await?
|
.await?
|
||||||
.compute(ctx, opt)
|
.compute(ctx, opt, txn, doc)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
// Otherwise use the current document
|
// Otherwise use the current document
|
||||||
_ => match ctx.doc() {
|
_ => match doc {
|
||||||
// There is a current document
|
// There is a current document
|
||||||
Some(v) => v.get(ctx, opt, self).await?.compute(ctx, opt).await,
|
Some(v) => {
|
||||||
|
v.doc.get(ctx, opt, txn, doc, self).await?.compute(ctx, opt, txn, doc).await
|
||||||
|
}
|
||||||
// There isn't any document
|
// There isn't any document
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -15,8 +16,14 @@ use std::fmt;
|
||||||
pub struct Limit(pub Value);
|
pub struct Limit(pub Value);
|
||||||
|
|
||||||
impl Limit {
|
impl Limit {
|
||||||
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> {
|
pub(crate) async fn process(
|
||||||
match self.0.compute(ctx, opt).await {
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
match self.0.compute(ctx, opt, txn, doc).await {
|
||||||
// This is a valid limiting number
|
// This is a valid limiting number
|
||||||
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
||||||
// An invalid value was specified
|
// An invalid value was specified
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::common::{commas, val_char};
|
use crate::sql::common::{commas, val_char};
|
||||||
|
@ -124,10 +125,16 @@ impl Object {
|
||||||
|
|
||||||
impl Object {
|
impl Object {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
let mut x = BTreeMap::new();
|
let mut x = BTreeMap::new();
|
||||||
for (k, v) in self.iter() {
|
for (k, v) in self.iter() {
|
||||||
match v.compute(ctx, opt).await {
|
match v.compute(ctx, opt, txn, doc).await {
|
||||||
Ok(v) => x.insert(k.clone(), v),
|
Ok(v) => x.insert(k.clone(), v),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::ident::{ident, Ident};
|
use crate::sql::ident::{ident, Ident};
|
||||||
|
@ -43,24 +44,28 @@ impl Deref for Param {
|
||||||
|
|
||||||
impl Param {
|
impl Param {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Find the variable by name
|
// Find the variable by name
|
||||||
match self.as_str() {
|
match self.as_str() {
|
||||||
// This is a special param
|
// This is a special param
|
||||||
"this" | "self" => match ctx.doc() {
|
"this" | "self" => match doc {
|
||||||
// The base document exists
|
// The base document exists
|
||||||
Some(v) => v.compute(ctx, opt).await,
|
Some(v) => v.doc.compute(ctx, opt, txn, doc).await,
|
||||||
// The base document does not exist
|
// The base document does not exist
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
// This is a normal param
|
// This is a normal param
|
||||||
v => match ctx.value(v) {
|
v => match ctx.value(v) {
|
||||||
// The param has been set locally
|
// The param has been set locally
|
||||||
Some(v) => v.compute(ctx, opt).await,
|
Some(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
// The param has not been set locally
|
// The param has not been set locally
|
||||||
None => {
|
None => {
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Get the param definition
|
// Get the param definition
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::id::{id, Id};
|
use crate::sql::id::{id, Id};
|
||||||
|
@ -48,17 +49,23 @@ impl TryFrom<&str> for Range {
|
||||||
|
|
||||||
impl Range {
|
impl Range {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
Ok(Value::Range(Box::new(Range {
|
Ok(Value::Range(Box::new(Range {
|
||||||
tb: self.tb.clone(),
|
tb: self.tb.clone(),
|
||||||
beg: match &self.beg {
|
beg: match &self.beg {
|
||||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?),
|
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
||||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?),
|
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
||||||
Bound::Unbounded => Bound::Unbounded,
|
Bound::Unbounded => Bound::Unbounded,
|
||||||
},
|
},
|
||||||
end: match &self.end {
|
end: match &self.end {
|
||||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?),
|
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
||||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?),
|
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
||||||
Bound::Unbounded => Bound::Unbounded,
|
Bound::Unbounded => Bound::Unbounded,
|
||||||
},
|
},
|
||||||
})))
|
})))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -15,8 +16,14 @@ use std::fmt;
|
||||||
pub struct Start(pub Value);
|
pub struct Start(pub Value);
|
||||||
|
|
||||||
impl Start {
|
impl Start {
|
||||||
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> {
|
pub(crate) async fn process(
|
||||||
match self.0.compute(ctx, opt).await {
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
match self.0.compute(ctx, opt, txn, doc).await {
|
||||||
// This is a valid starting number
|
// This is a valid starting number
|
||||||
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
||||||
// An invalid value was specified
|
// An invalid value was specified
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::{comment, mightbespace};
|
use crate::sql::comment::{comment, mightbespace};
|
||||||
use crate::sql::common::colons;
|
use crate::sql::common::colons;
|
||||||
|
@ -138,25 +139,31 @@ impl Statement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::Analyze(v) => v.compute(ctx, opt).await,
|
Self::Analyze(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Create(v) => v.compute(ctx, opt).await,
|
Self::Create(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Delete(v) => v.compute(ctx, opt).await,
|
Self::Delete(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Define(v) => v.compute(ctx, opt).await,
|
Self::Define(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Ifelse(v) => v.compute(ctx, opt).await,
|
Self::Ifelse(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Info(v) => v.compute(ctx, opt).await,
|
Self::Info(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Insert(v) => v.compute(ctx, opt).await,
|
Self::Insert(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Kill(v) => v.compute(ctx, opt).await,
|
Self::Kill(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Live(v) => v.compute(ctx, opt).await,
|
Self::Live(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Output(v) => v.compute(ctx, opt).await,
|
Self::Output(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Relate(v) => v.compute(ctx, opt).await,
|
Self::Relate(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Remove(v) => v.compute(ctx, opt).await,
|
Self::Remove(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Select(v) => v.compute(ctx, opt).await,
|
Self::Select(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Set(v) => v.compute(ctx, opt).await,
|
Self::Set(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Show(v) => v.compute(ctx, opt).await,
|
Self::Show(v) => v.compute(ctx, opt, doc).await,
|
||||||
Self::Sleep(v) => v.compute(ctx, opt).await,
|
Self::Sleep(v) => v.compute(ctx, opt, doc).await,
|
||||||
Self::Update(v) => v.compute(ctx, opt).await,
|
Self::Update(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::ft::FtIndex;
|
use crate::idx::ft::FtIndex;
|
||||||
use crate::idx::IndexKeyBase;
|
use crate::idx::IndexKeyBase;
|
||||||
|
@ -22,15 +23,19 @@ pub enum AnalyzeStatement {
|
||||||
|
|
||||||
impl AnalyzeStatement {
|
impl AnalyzeStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
AnalyzeStatement::Idx(tb, idx) => {
|
AnalyzeStatement::Idx(tb, idx) => {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Read the index
|
// Read the index
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::data::{data, Data};
|
use crate::sql::data::{data, Data};
|
||||||
|
@ -42,7 +43,13 @@ impl CreateStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -53,11 +60,11 @@ impl CreateStatement {
|
||||||
let opt = &opt.new_with_futures(false);
|
let opt = &opt.new_with_futures(false);
|
||||||
// Loop over the create targets
|
// Loop over the create targets
|
||||||
for w in self.what.0.iter() {
|
for w in self.what.0.iter() {
|
||||||
let v = w.compute(ctx, opt).await?;
|
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => match &self.data {
|
Value::Table(v) => match &self.data {
|
||||||
// There is a data clause so check for a record id
|
// There is a data clause so check for a record id
|
||||||
Some(data) => match data.rid(ctx, opt, &v).await {
|
Some(data) => match data.rid(ctx, opt, txn, &v).await {
|
||||||
// There was a problem creating the record id
|
// There was a problem creating the record id
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
// There is an id field so use the record id
|
// There is an id field so use the record id
|
||||||
|
@ -116,7 +123,7 @@ impl CreateStatement {
|
||||||
// Assign the statement
|
// Assign the statement
|
||||||
let stm = Statement::from(self);
|
let stm = Statement::from(self);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::algorithm::{algorithm, Algorithm};
|
use crate::sql::algorithm::{algorithm, Algorithm};
|
||||||
use crate::sql::base::{base, base_or_scope, Base};
|
use crate::sql::base::{base, base_or_scope, Base};
|
||||||
|
@ -61,20 +62,26 @@ pub enum DefineStatement {
|
||||||
|
|
||||||
impl DefineStatement {
|
impl DefineStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::Namespace(ref v) => v.compute(ctx, opt).await,
|
Self::Namespace(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Database(ref v) => v.compute(ctx, opt).await,
|
Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Function(ref v) => v.compute(ctx, opt).await,
|
Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Login(ref v) => v.compute(ctx, opt).await,
|
Self::Login(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Token(ref v) => v.compute(ctx, opt).await,
|
Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Scope(ref v) => v.compute(ctx, opt).await,
|
Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Param(ref v) => v.compute(ctx, opt).await,
|
Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Table(ref v) => v.compute(ctx, opt).await,
|
Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Event(ref v) => v.compute(ctx, opt).await,
|
Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Field(ref v) => v.compute(ctx, opt).await,
|
Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Index(ref v) => v.compute(ctx, opt).await,
|
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Analyzer(ref v) => v.compute(ctx, opt).await,
|
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,15 +133,19 @@ pub struct DefineNamespaceStatement {
|
||||||
|
|
||||||
impl DefineNamespaceStatement {
|
impl DefineNamespaceStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// No need for NS/DB
|
// No need for NS/DB
|
||||||
opt.needs(Level::Kv)?;
|
opt.needs(Level::Kv)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
let key = crate::key::ns::new(&self.name);
|
let key = crate::key::ns::new(&self.name);
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
run.set(key, self).await?;
|
run.set(key, self).await?;
|
||||||
|
@ -175,13 +186,17 @@ pub struct DefineDatabaseStatement {
|
||||||
|
|
||||||
impl DefineDatabaseStatement {
|
impl DefineDatabaseStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected NS?
|
// Selected NS?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -252,13 +267,17 @@ pub struct DefineFunctionStatement {
|
||||||
|
|
||||||
impl DefineFunctionStatement {
|
impl DefineFunctionStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -330,13 +349,17 @@ pub struct DefineAnalyzerStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefineAnalyzerStatement {
|
impl DefineAnalyzerStatement {
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -400,15 +423,19 @@ pub struct DefineLoginStatement {
|
||||||
|
|
||||||
impl DefineLoginStatement {
|
impl DefineLoginStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self.base {
|
match self.base {
|
||||||
Base::Ns => {
|
Base::Ns => {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -423,8 +450,6 @@ impl DefineLoginStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -518,15 +543,19 @@ pub struct DefineTokenStatement {
|
||||||
|
|
||||||
impl DefineTokenStatement {
|
impl DefineTokenStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match &self.base {
|
match &self.base {
|
||||||
Base::Ns => {
|
Base::Ns => {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -541,8 +570,6 @@ impl DefineTokenStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -558,8 +585,6 @@ impl DefineTokenStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -633,13 +658,17 @@ pub struct DefineScopeStatement {
|
||||||
|
|
||||||
impl DefineScopeStatement {
|
impl DefineScopeStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -747,13 +776,17 @@ pub struct DefineParamStatement {
|
||||||
|
|
||||||
impl DefineParamStatement {
|
impl DefineParamStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -807,13 +840,17 @@ pub struct DefineTableStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefineTableStatement {
|
impl DefineTableStatement {
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -852,7 +889,7 @@ impl DefineTableStatement {
|
||||||
what: Values(vec![Value::Table(v.clone())]),
|
what: Values(vec![Value::Table(v.clone())]),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, doc).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ok all good
|
// Ok all good
|
||||||
|
@ -1006,13 +1043,17 @@ pub struct DefineEventStatement {
|
||||||
|
|
||||||
impl DefineEventStatement {
|
impl DefineEventStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -1086,13 +1127,17 @@ pub struct DefineFieldStatement {
|
||||||
|
|
||||||
impl DefineFieldStatement {
|
impl DefineFieldStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -1242,13 +1287,17 @@ pub struct DefineIndexStatement {
|
||||||
|
|
||||||
impl DefineIndexStatement {
|
impl DefineIndexStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -1279,7 +1328,7 @@ impl DefineIndexStatement {
|
||||||
what: Values(vec![Value::Table(self.what.clone().into())]),
|
what: Values(vec![Value::Table(self.what.clone().into())]),
|
||||||
..UpdateStatement::default()
|
..UpdateStatement::default()
|
||||||
};
|
};
|
||||||
stm.compute(ctx, opt).await?;
|
stm.compute(ctx, opt, txn, doc).await?;
|
||||||
// Ok all good
|
// Ok all good
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::cond::{cond, Cond};
|
use crate::sql::cond::{cond, Cond};
|
||||||
|
@ -42,7 +43,13 @@ impl DeleteStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -53,7 +60,7 @@ impl DeleteStatement {
|
||||||
let opt = &opt.new_with_futures(false);
|
let opt = &opt.new_with_futures(false);
|
||||||
// Loop over the delete targets
|
// Loop over the delete targets
|
||||||
for w in self.what.0.iter() {
|
for w in self.what.0.iter() {
|
||||||
let v = w.compute(ctx, opt).await?;
|
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
|
@ -109,7 +116,7 @@ impl DeleteStatement {
|
||||||
// Assign the statement
|
// Assign the statement
|
||||||
let stm = Statement::from(self);
|
let stm = Statement::from(self);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -29,15 +30,21 @@ impl IfelseStatement {
|
||||||
self.close.as_ref().map_or(false, |v| v.writeable())
|
self.close.as_ref().map_or(false, |v| v.writeable())
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
for (ref cond, ref then) in &self.exprs {
|
for (ref cond, ref then) in &self.exprs {
|
||||||
let v = cond.compute(ctx, opt).await?;
|
let v = cond.compute(ctx, opt, txn, doc).await?;
|
||||||
if v.is_truthy() {
|
if v.is_truthy() {
|
||||||
return then.compute(ctx, opt).await;
|
return then.compute(ctx, opt, txn, doc).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match self.close {
|
match self.close {
|
||||||
Some(ref v) => v.compute(ctx, opt).await,
|
Some(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -24,7 +25,13 @@ pub enum InfoStatement {
|
||||||
|
|
||||||
impl InfoStatement {
|
impl InfoStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
match self {
|
match self {
|
||||||
InfoStatement::Kv => {
|
InfoStatement::Kv => {
|
||||||
|
@ -34,8 +41,6 @@ impl InfoStatement {
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Create the result set
|
// Create the result set
|
||||||
let mut res = Object::default();
|
let mut res = Object::default();
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the statement
|
// Process the statement
|
||||||
|
@ -52,8 +57,6 @@ impl InfoStatement {
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Create the result set
|
// Create the result set
|
||||||
|
@ -84,8 +87,6 @@ impl InfoStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Create the result set
|
// Create the result set
|
||||||
|
@ -140,8 +141,6 @@ impl InfoStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Create the result set
|
// Create the result set
|
||||||
|
@ -160,8 +159,6 @@ impl InfoStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Create the result set
|
// Create the result set
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::data::{single, update, values, Data};
|
use crate::sql::data::{single, update, values, Data};
|
||||||
|
@ -45,7 +46,13 @@ impl InsertStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -63,8 +70,8 @@ impl InsertStatement {
|
||||||
let mut o = Value::base();
|
let mut o = Value::base();
|
||||||
// Set each field from the expression
|
// Set each field from the expression
|
||||||
for (k, v) in v.iter() {
|
for (k, v) in v.iter() {
|
||||||
let v = v.compute(ctx, opt).await?;
|
let v = v.compute(ctx, opt, txn, None).await?;
|
||||||
o.set(ctx, opt, k, v).await?;
|
o.set(ctx, opt, txn, k, v).await?;
|
||||||
}
|
}
|
||||||
// Specify the new table record id
|
// Specify the new table record id
|
||||||
let id = o.rid().generate(&self.into, true)?;
|
let id = o.rid().generate(&self.into, true)?;
|
||||||
|
@ -74,7 +81,7 @@ impl InsertStatement {
|
||||||
}
|
}
|
||||||
// Check if this is a modern statement
|
// Check if this is a modern statement
|
||||||
Data::SingleExpression(v) => {
|
Data::SingleExpression(v) => {
|
||||||
let v = v.compute(ctx, opt).await?;
|
let v = v.compute(ctx, opt, txn, doc).await?;
|
||||||
match v {
|
match v {
|
||||||
Value::Array(v) => {
|
Value::Array(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
@ -102,7 +109,7 @@ impl InsertStatement {
|
||||||
// Assign the statement
|
// Assign the statement
|
||||||
let stm = Statement::from(self);
|
let stm = Statement::from(self);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -18,15 +19,19 @@ pub struct KillStatement {
|
||||||
|
|
||||||
impl KillStatement {
|
impl KillStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.realtime()?;
|
opt.realtime()?;
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::No)?;
|
opt.check(Level::No)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Fetch the live query key
|
// Fetch the live query key
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::cond::{cond, Cond};
|
use crate::sql::cond::{cond, Cond};
|
||||||
|
@ -32,19 +33,23 @@ pub struct LiveStatement {
|
||||||
|
|
||||||
impl LiveStatement {
|
impl LiveStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.realtime()?;
|
opt.realtime()?;
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::No)?;
|
opt.check(Level::No)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Process the live query table
|
// Process the live query table
|
||||||
match self.what.compute(ctx, opt).await? {
|
match self.what.compute(ctx, opt, txn, doc).await? {
|
||||||
Value::Table(tb) => {
|
Value::Table(tb) => {
|
||||||
// Clone the current statement
|
// Clone the current statement
|
||||||
let mut stm = self.clone();
|
let mut stm = self.clone();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
|
@ -24,15 +25,21 @@ impl OutputStatement {
|
||||||
self.what.writeable()
|
self.what.writeable()
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Ensure futures are processed
|
// Ensure futures are processed
|
||||||
let opt = &opt.new_with_futures(true);
|
let opt = &opt.new_with_futures(true);
|
||||||
// Process the output value
|
// Process the output value
|
||||||
let mut val = self.what.compute(ctx, opt).await?;
|
let mut val = self.what.compute(ctx, opt, txn, doc).await?;
|
||||||
// Fetch any
|
// Fetch any
|
||||||
if let Some(fetchs) = &self.fetch {
|
if let Some(fetchs) = &self.fetch {
|
||||||
for fetch in fetchs.iter() {
|
for fetch in fetchs.iter() {
|
||||||
val.fetch(ctx, opt, fetch).await?;
|
val.fetch(ctx, opt, txn, fetch).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::array::array;
|
use crate::sql::array::array;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
|
@ -55,7 +56,13 @@ impl RelateStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -67,7 +74,7 @@ impl RelateStatement {
|
||||||
// Loop over the from targets
|
// Loop over the from targets
|
||||||
let from = {
|
let from = {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
match self.from.compute(ctx, opt).await? {
|
match self.from.compute(ctx, opt, txn, doc).await? {
|
||||||
Value::Thing(v) => out.push(v),
|
Value::Thing(v) => out.push(v),
|
||||||
Value::Array(v) => {
|
Value::Array(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
@ -109,7 +116,7 @@ impl RelateStatement {
|
||||||
// Loop over the with targets
|
// Loop over the with targets
|
||||||
let with = {
|
let with = {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
match self.with.compute(ctx, opt).await? {
|
match self.with.compute(ctx, opt, txn, doc).await? {
|
||||||
Value::Thing(v) => out.push(v),
|
Value::Thing(v) => out.push(v),
|
||||||
Value::Array(v) => {
|
Value::Array(v) => {
|
||||||
for v in v {
|
for v in v {
|
||||||
|
@ -158,7 +165,7 @@ impl RelateStatement {
|
||||||
// The relation does not have a specific record id
|
// The relation does not have a specific record id
|
||||||
Value::Table(tb) => match &self.data {
|
Value::Table(tb) => match &self.data {
|
||||||
// There is a data clause so check for a record id
|
// There is a data clause so check for a record id
|
||||||
Some(data) => match data.rid(ctx, opt, tb).await {
|
Some(data) => match data.rid(ctx, opt, txn, tb).await {
|
||||||
// There was a problem creating the record id
|
// There was a problem creating the record id
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
// There is an id field so use the record id
|
// There is an id field so use the record id
|
||||||
|
@ -175,7 +182,7 @@ impl RelateStatement {
|
||||||
// Assign the statement
|
// Assign the statement
|
||||||
let stm = Statement::from(self);
|
let stm = Statement::from(self);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::{Level, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::base::{base, base_or_scope, Base};
|
use crate::sql::base::{base, base_or_scope, Base};
|
||||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||||
|
@ -38,20 +39,26 @@ pub enum RemoveStatement {
|
||||||
|
|
||||||
impl RemoveStatement {
|
impl RemoveStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
Self::Namespace(ref v) => v.compute(ctx, opt).await,
|
Self::Namespace(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Database(ref v) => v.compute(ctx, opt).await,
|
Self::Database(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Function(ref v) => v.compute(ctx, opt).await,
|
Self::Function(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Login(ref v) => v.compute(ctx, opt).await,
|
Self::Login(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Token(ref v) => v.compute(ctx, opt).await,
|
Self::Token(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Scope(ref v) => v.compute(ctx, opt).await,
|
Self::Scope(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Param(ref v) => v.compute(ctx, opt).await,
|
Self::Param(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Table(ref v) => v.compute(ctx, opt).await,
|
Self::Table(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Event(ref v) => v.compute(ctx, opt).await,
|
Self::Event(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Field(ref v) => v.compute(ctx, opt).await,
|
Self::Field(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Index(ref v) => v.compute(ctx, opt).await,
|
Self::Index(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
Self::Analyzer(ref v) => v.compute(ctx, opt).await,
|
Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,13 +110,16 @@ pub struct RemoveNamespaceStatement {
|
||||||
|
|
||||||
impl RemoveNamespaceStatement {
|
impl RemoveNamespaceStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// No need for NS/DB
|
// No need for NS/DB
|
||||||
opt.needs(Level::Kv)?;
|
opt.needs(Level::Kv)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -154,13 +164,16 @@ pub struct RemoveDatabaseStatement {
|
||||||
|
|
||||||
impl RemoveDatabaseStatement {
|
impl RemoveDatabaseStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected NS?
|
// Selected NS?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -205,13 +218,16 @@ pub struct RemoveFunctionStatement {
|
||||||
|
|
||||||
impl RemoveFunctionStatement {
|
impl RemoveFunctionStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -260,13 +276,16 @@ pub struct RemoveAnalyzerStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RemoveAnalyzerStatement {
|
impl RemoveAnalyzerStatement {
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -310,15 +329,18 @@ pub struct RemoveLoginStatement {
|
||||||
|
|
||||||
impl RemoveLoginStatement {
|
impl RemoveLoginStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self.base {
|
match self.base {
|
||||||
Base::Ns => {
|
Base::Ns => {
|
||||||
// Selected NS?
|
// Selected NS?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -332,8 +354,6 @@ impl RemoveLoginStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -384,15 +404,18 @@ pub struct RemoveTokenStatement {
|
||||||
|
|
||||||
impl RemoveTokenStatement {
|
impl RemoveTokenStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match &self.base {
|
match &self.base {
|
||||||
Base::Ns => {
|
Base::Ns => {
|
||||||
// Selected NS?
|
// Selected NS?
|
||||||
opt.needs(Level::Ns)?;
|
opt.needs(Level::Ns)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Kv)?;
|
opt.check(Level::Kv)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -406,8 +429,6 @@ impl RemoveTokenStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Ns)?;
|
opt.check(Level::Ns)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -421,8 +442,6 @@ impl RemoveTokenStatement {
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -472,13 +491,16 @@ pub struct RemoveScopeStatement {
|
||||||
|
|
||||||
impl RemoveScopeStatement {
|
impl RemoveScopeStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -523,13 +545,16 @@ pub struct RemoveParamStatement {
|
||||||
|
|
||||||
impl RemoveParamStatement {
|
impl RemoveParamStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -572,13 +597,16 @@ pub struct RemoveTableStatement {
|
||||||
|
|
||||||
impl RemoveTableStatement {
|
impl RemoveTableStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -624,13 +652,16 @@ pub struct RemoveEventStatement {
|
||||||
|
|
||||||
impl RemoveEventStatement {
|
impl RemoveEventStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -682,13 +713,16 @@ pub struct RemoveFieldStatement {
|
||||||
|
|
||||||
impl RemoveFieldStatement {
|
impl RemoveFieldStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
@ -741,13 +775,16 @@ pub struct RemoveIndexStatement {
|
||||||
|
|
||||||
impl RemoveIndexStatement {
|
impl RemoveIndexStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
opt.check(Level::Db)?;
|
opt.check(Level::Db)?;
|
||||||
// Clone transaction
|
|
||||||
let txn = ctx.try_clone_transaction()?;
|
|
||||||
// Claim transaction
|
// Claim transaction
|
||||||
let mut run = txn.lock().await;
|
let mut run = txn.lock().await;
|
||||||
// Delete the definition
|
// Delete the definition
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::idx::planner::QueryPlanner;
|
use crate::idx::planner::QueryPlanner;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
|
@ -72,7 +73,13 @@ impl SelectStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -86,10 +93,10 @@ impl SelectStatement {
|
||||||
let mut planner = QueryPlanner::new(opt, &self.cond);
|
let mut planner = QueryPlanner::new(opt, &self.cond);
|
||||||
// Loop over the select targets
|
// Loop over the select targets
|
||||||
for w in self.what.0.iter() {
|
for w in self.what.0.iter() {
|
||||||
let v = w.compute(ctx, opt).await?;
|
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||||
match v {
|
match v {
|
||||||
Value::Table(t) => {
|
Value::Table(t) => {
|
||||||
i.ingest(planner.get_iterable(ctx, t).await?);
|
i.ingest(planner.get_iterable(ctx, txn, t).await?);
|
||||||
}
|
}
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||||
|
@ -124,10 +131,10 @@ impl SelectStatement {
|
||||||
let mut ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
ctx.set_query_executors(ex);
|
ctx.set_query_executors(ex);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(&ctx, opt, &stm).await
|
i.output(&ctx, opt, txn, &stm).await
|
||||||
} else {
|
} else {
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::dbs::Transaction;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::mightbespace;
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
|
@ -25,8 +27,14 @@ impl SetStatement {
|
||||||
self.what.writeable()
|
self.what.writeable()
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
self.what.compute(ctx, opt).await
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
|
self.what.compute(ctx, opt, txn, doc).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::common::take_u64;
|
use crate::sql::common::take_u64;
|
||||||
|
@ -27,7 +28,12 @@ pub struct ShowStatement {
|
||||||
|
|
||||||
impl ShowStatement {
|
impl ShowStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
_ctx: &Context<'_>,
|
||||||
|
_opt: &Options,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
Err(Error::FeatureNotYetImplemented {
|
Err(Error::FeatureNotYetImplemented {
|
||||||
feature: "change feed",
|
feature: "change feed",
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::duration::duration;
|
use crate::sql::duration::duration;
|
||||||
|
@ -18,7 +19,12 @@ pub struct SleepStatement {
|
||||||
|
|
||||||
impl SleepStatement {
|
impl SleepStatement {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
_doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// No need for NS/DB
|
// No need for NS/DB
|
||||||
opt.needs(Level::Kv)?;
|
opt.needs(Level::Kv)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -87,9 +93,9 @@ mod tests {
|
||||||
let sql = "SLEEP 500ms";
|
let sql = "SLEEP 500ms";
|
||||||
let time = SystemTime::now();
|
let time = SystemTime::now();
|
||||||
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
||||||
let (ctx, _) = mock().await;
|
let (ctx, _, _) = mock().await;
|
||||||
let (_, stm) = sleep(sql).unwrap();
|
let (_, stm) = sleep(sql).unwrap();
|
||||||
let value = stm.compute(&ctx, &opt).await.unwrap();
|
let value = stm.compute(&ctx, &opt, None).await.unwrap();
|
||||||
assert!(time.elapsed().unwrap() >= time::Duration::microseconds(500));
|
assert!(time.elapsed().unwrap() >= time::Duration::microseconds(500));
|
||||||
assert_eq!(value, Value::None);
|
assert_eq!(value, Value::None);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Iterable;
|
|
||||||
use crate::dbs::Iterator;
|
use crate::dbs::Iterator;
|
||||||
use crate::dbs::Level;
|
use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Statement;
|
use crate::dbs::Statement;
|
||||||
|
use crate::dbs::{Iterable, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::comment::shouldbespace;
|
use crate::sql::comment::shouldbespace;
|
||||||
use crate::sql::cond::{cond, Cond};
|
use crate::sql::cond::{cond, Cond};
|
||||||
|
@ -43,7 +44,13 @@ impl UpdateStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Selected DB?
|
// Selected DB?
|
||||||
opt.needs(Level::Db)?;
|
opt.needs(Level::Db)?;
|
||||||
// Allowed to run?
|
// Allowed to run?
|
||||||
|
@ -54,7 +61,7 @@ impl UpdateStatement {
|
||||||
let opt = &opt.new_with_futures(false);
|
let opt = &opt.new_with_futures(false);
|
||||||
// Loop over the update targets
|
// Loop over the update targets
|
||||||
for w in self.what.0.iter() {
|
for w in self.what.0.iter() {
|
||||||
let v = w.compute(ctx, opt).await?;
|
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||||
match v {
|
match v {
|
||||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||||
|
@ -110,7 +117,7 @@ impl UpdateStatement {
|
||||||
// Assign the statement
|
// Assign the statement
|
||||||
let stm = Statement::from(self);
|
let stm = Statement::from(self);
|
||||||
// Output the results
|
// Output the results
|
||||||
i.output(ctx, opt, &stm).await
|
i.output(ctx, opt, txn, &stm).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::common::{closeparentheses, openparentheses};
|
use crate::sql::common::{closeparentheses, openparentheses};
|
||||||
use crate::sql::ending::subquery as ending;
|
use crate::sql::ending::subquery as ending;
|
||||||
|
@ -59,25 +60,31 @@ impl Subquery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
// Prevent deep recursion
|
// Prevent deep recursion
|
||||||
let opt = &opt.dive(2)?;
|
let opt = &opt.dive(2)?;
|
||||||
// Process the subquery
|
// Process the subquery
|
||||||
match self {
|
match self {
|
||||||
Self::Value(ref v) => v.compute(ctx, opt).await,
|
Self::Value(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Ifelse(ref v) => v.compute(ctx, opt).await,
|
Self::Ifelse(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Output(ref v) => v.compute(ctx, opt).await,
|
Self::Output(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Self::Select(ref v) => {
|
Self::Select(ref v) => {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
@ -93,13 +100,13 @@ impl Subquery {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
@ -115,13 +122,13 @@ impl Subquery {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
@ -137,13 +144,13 @@ impl Subquery {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
@ -159,13 +166,13 @@ impl Subquery {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
@ -181,13 +188,13 @@ impl Subquery {
|
||||||
// Is this a single output?
|
// Is this a single output?
|
||||||
let one = v.single();
|
let one = v.single();
|
||||||
// Duplicate context
|
// Duplicate context
|
||||||
let mut child_ctx = Context::new(ctx);
|
let mut ctx = Context::new(ctx);
|
||||||
// Add parent document
|
// Add parent document
|
||||||
if let Some(doc) = ctx.doc() {
|
if let Some(doc) = doc {
|
||||||
child_ctx.add_value("parent", doc);
|
ctx.add_value("parent", doc.doc.as_ref());
|
||||||
}
|
}
|
||||||
// Process subquery
|
// Process subquery
|
||||||
match v.compute(&child_ctx, opt).await? {
|
match v.compute(&ctx, opt, txn, doc).await? {
|
||||||
// This is a single record result
|
// This is a single record result
|
||||||
Value::Array(mut a) if one => match a.len() {
|
Value::Array(mut a) if one => match a.len() {
|
||||||
// There was at least one result
|
// There was at least one result
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::escape::escape_rid;
|
use crate::sql::escape::escape_rid;
|
||||||
|
@ -102,10 +103,16 @@ impl fmt::Display for Thing {
|
||||||
|
|
||||||
impl Thing {
|
impl Thing {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
Ok(Value::Thing(Thing {
|
Ok(Value::Thing(Thing {
|
||||||
tb: self.tb.clone(),
|
tb: self.tb.clone(),
|
||||||
id: self.id.compute(ctx, opt).await?,
|
id: self.id.compute(ctx, opt, txn, doc).await?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,121 +102,121 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_none() {
|
async fn del_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::default();
|
let idi = Idiom::default();
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_reset() {
|
async fn del_reset() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ }");
|
let res = Value::parse("{ }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_basic() {
|
async fn del_basic() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something");
|
let idi = Idiom::parse("test.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null } }");
|
let res = Value::parse("{ test: { other: null } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_wrong() {
|
async fn del_wrong() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.wrong");
|
let idi = Idiom::parse("test.something.wrong");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_other() {
|
async fn del_other() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.other.something");
|
let idi = Idiom::parse("test.other.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array() {
|
async fn del_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1]");
|
let idi = Idiom::parse("test.something[1]");
|
||||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||||
let res = Value::parse("{ test: { something: [123, 789] } }");
|
let res = Value::parse("{ test: { something: [123, 789] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_field() {
|
async fn del_array_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1].age");
|
let idi = Idiom::parse("test.something[1].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_fields() {
|
async fn del_array_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[*].age");
|
let idi = Idiom::parse("test.something[*].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_fields_flat() {
|
async fn del_array_fields_flat() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.age");
|
let idi = Idiom::parse("test.something.age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_where_field() {
|
async fn del_array_where_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_where_fields() {
|
async fn del_array_where_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::number::Number;
|
use crate::sql::number::Number;
|
||||||
use crate::sql::part::Part;
|
use crate::sql::part::Part;
|
||||||
|
@ -11,21 +11,22 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
val: Value,
|
val: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match self.get(ctx, opt, path).await? {
|
match self.get(ctx, opt, txn, None, path).await? {
|
||||||
Value::Number(v) => match val {
|
Value::Number(v) => match val {
|
||||||
Value::Number(x) => self.set(ctx, opt, path, Value::from(v - x)).await,
|
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
Value::Array(v) => match val {
|
Value::Array(v) => match val {
|
||||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(v - x)).await,
|
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||||
x => self.set(ctx, opt, path, Value::from(v - x)).await,
|
x => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||||
},
|
},
|
||||||
Value::None => match val {
|
Value::None => match val {
|
||||||
Value::Number(x) => {
|
Value::Number(x) => {
|
||||||
self.set(ctx, opt, path, Value::from(Number::from(0) - x)).await
|
self.set(ctx, opt, txn, path, Value::from(Number::from(0) - x)).await
|
||||||
}
|
}
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
|
@ -44,51 +45,51 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn decrement_none() {
|
async fn decrement_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("other");
|
let idi = Idiom::parse("other");
|
||||||
let mut val = Value::parse("{ test: 100 }");
|
let mut val = Value::parse("{ test: 100 }");
|
||||||
let res = Value::parse("{ test: 100, other: -10 }");
|
let res = Value::parse("{ test: 100, other: -10 }");
|
||||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn decrement_number() {
|
async fn decrement_number() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: 100 }");
|
let mut val = Value::parse("{ test: 100 }");
|
||||||
let res = Value::parse("{ test: 90 }");
|
let res = Value::parse("{ test: 90 }");
|
||||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn decrement_array_number() {
|
async fn decrement_array_number() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test[1]");
|
let idi = Idiom::parse("test[1]");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 190, 300] }");
|
let res = Value::parse("{ test: [100, 190, 300] }");
|
||||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn decrement_array_value() {
|
async fn decrement_array_value() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 300] }");
|
let res = Value::parse("{ test: [100, 300] }");
|
||||||
val.decrement(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
val.decrement(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn decrement_array_array() {
|
async fn decrement_array_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [200] }");
|
let res = Value::parse("{ test: [200] }");
|
||||||
val.decrement(&ctx, &opt, &idi, Value::parse("[100, 300]")).await.unwrap();
|
val.decrement(&ctx, &opt, &txn, &idi, Value::parse("[100, 300]")).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::exe::try_join_all_buffered;
|
use crate::exe::try_join_all_buffered;
|
||||||
use crate::sql::array::Abolish;
|
use crate::sql::array::Abolish;
|
||||||
|
@ -17,6 +18,7 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match path.first() {
|
match path.first() {
|
||||||
|
@ -30,7 +32,7 @@ impl Value {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => match v.get_mut(f.as_str()) {
|
_ => match v.get_mut(f.as_str()) {
|
||||||
Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await,
|
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -40,7 +42,7 @@ impl Value {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => match v.get_mut(&i.to_string()) {
|
_ => match v.get_mut(&i.to_string()) {
|
||||||
Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await,
|
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -55,7 +57,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, path));
|
let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path));
|
||||||
try_join_all_buffered(futs).await?;
|
try_join_all_buffered(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -69,7 +71,7 @@ impl Value {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => match v.first_mut() {
|
_ => match v.first_mut() {
|
||||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -82,7 +84,7 @@ impl Value {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => match v.last_mut() {
|
_ => match v.last_mut() {
|
||||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -94,7 +96,7 @@ impl Value {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => match v.get_mut(i.to_usize()) {
|
_ => match v.get_mut(i.to_usize()) {
|
||||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -104,9 +106,8 @@ impl Value {
|
||||||
// iterate in reverse, and call swap_remove
|
// iterate in reverse, and call swap_remove
|
||||||
let mut m = HashSet::new();
|
let mut m = HashSet::new();
|
||||||
for (i, v) in v.iter().enumerate() {
|
for (i, v) in v.iter().enumerate() {
|
||||||
let mut child_ctx = Context::new(ctx);
|
let cur = CursorDoc::new(None, None, v);
|
||||||
child_ctx.add_cursor_doc(v);
|
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
|
||||||
m.insert(i);
|
m.insert(i);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -116,17 +117,16 @@ impl Value {
|
||||||
_ => {
|
_ => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
for v in v.iter_mut() {
|
for v in v.iter_mut() {
|
||||||
let mut child_ctx = Context::new(ctx);
|
let cur = CursorDoc::new(None, None, v);
|
||||||
child_ctx.add_cursor_doc(v);
|
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
v.del(ctx, opt, txn, path).await?;
|
||||||
v.del(ctx, opt, path).await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, path));
|
let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path));
|
||||||
try_join_all_buffered(futs).await?;
|
try_join_all_buffered(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -150,121 +150,121 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_none() {
|
async fn del_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::default();
|
let idi = Idiom::default();
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_reset() {
|
async fn del_reset() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ }");
|
let res = Value::parse("{ }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_basic() {
|
async fn del_basic() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something");
|
let idi = Idiom::parse("test.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null } }");
|
let res = Value::parse("{ test: { other: null } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_wrong() {
|
async fn del_wrong() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.wrong");
|
let idi = Idiom::parse("test.something.wrong");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_other() {
|
async fn del_other() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.other.something");
|
let idi = Idiom::parse("test.other.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array() {
|
async fn del_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1]");
|
let idi = Idiom::parse("test.something[1]");
|
||||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||||
let res = Value::parse("{ test: { something: [123, 789] } }");
|
let res = Value::parse("{ test: { something: [123, 789] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_field() {
|
async fn del_array_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1].age");
|
let idi = Idiom::parse("test.something[1].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_fields() {
|
async fn del_array_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[*].age");
|
let idi = Idiom::parse("test.something[*].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_fields_flat() {
|
async fn del_array_fields_flat() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.age");
|
let idi = Idiom::parse("test.something.age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_where_field() {
|
async fn del_array_where_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn del_array_where_fields() {
|
async fn del_array_where_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let mut val = Value::parse(
|
let mut val = Value::parse(
|
||||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||||
);
|
);
|
||||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
||||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::array::Uniq;
|
use crate::sql::array::Uniq;
|
||||||
use crate::sql::part::Part;
|
use crate::sql::part::Part;
|
||||||
|
@ -10,17 +10,18 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
val: Value,
|
val: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match self.get(ctx, opt, path).await? {
|
match self.get(ctx, opt, txn, None, path).await? {
|
||||||
Value::Array(v) => match val {
|
Value::Array(v) => match val {
|
||||||
Value::Array(x) => self.set(ctx, opt, path, Value::from((v + x).uniq())).await,
|
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||||
x => self.set(ctx, opt, path, Value::from((v + x).uniq())).await,
|
x => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||||
},
|
},
|
||||||
Value::None => match val {
|
Value::None => match val {
|
||||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await,
|
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
|
||||||
x => self.set(ctx, opt, path, Value::from(vec![x])).await,
|
x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
|
||||||
},
|
},
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
|
@ -37,21 +38,21 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extend_array_value() {
|
async fn extend_array_value() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 200, 300] }");
|
let res = Value::parse("{ test: [100, 200, 300] }");
|
||||||
val.extend(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
val.extend(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extend_array_array() {
|
async fn extend_array_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 200, 300, 400, 500] }");
|
let res = Value::parse("{ test: [100, 200, 300, 400, 500] }");
|
||||||
val.extend(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
val.extend(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::edges::Edges;
|
use crate::sql::edges::Edges;
|
||||||
use crate::sql::field::{Field, Fields};
|
use crate::sql::field::{Field, Fields};
|
||||||
|
@ -17,6 +18,7 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match path.first() {
|
match path.first() {
|
||||||
|
@ -25,53 +27,52 @@ impl Value {
|
||||||
// Current path part is an object
|
// Current path part is an object
|
||||||
Value::Object(v) => match p {
|
Value::Object(v) => match p {
|
||||||
Part::Graph(_) => match v.rid() {
|
Part::Graph(_) => match v.rid() {
|
||||||
Some(v) => Value::Thing(v).fetch(ctx, opt, path.next()).await,
|
Some(v) => Value::Thing(v).fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Field(f) => match v.get_mut(f as &str) {
|
Part::Field(f) => match v.get_mut(f as &str) {
|
||||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
||||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::All => self.fetch(ctx, opt, path.next()).await,
|
Part::All => self.fetch(ctx, opt, txn, path.next()).await,
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
// Current path part is an array
|
// Current path part is an array
|
||||||
Value::Array(v) => match p {
|
Value::Array(v) => match p {
|
||||||
Part::All => {
|
Part::All => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||||
try_join_all(futs).await?;
|
try_join_all(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Part::First => match v.first_mut() {
|
Part::First => match v.first_mut() {
|
||||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Last => match v.last_mut() {
|
Part::Last => match v.last_mut() {
|
||||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
||||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Where(w) => {
|
Part::Where(w) => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
for v in v.iter_mut() {
|
for v in v.iter_mut() {
|
||||||
let mut child_ctx = Context::new(ctx);
|
let cur = CursorDoc::new(None, None, v);
|
||||||
child_ctx.add_cursor_doc(v);
|
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
v.fetch(ctx, opt, txn, path).await?;
|
||||||
v.fetch(ctx, opt, path).await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||||
try_join_all(futs).await?;
|
try_join_all(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,10 +96,10 @@ impl Value {
|
||||||
..SelectStatement::default()
|
..SelectStatement::default()
|
||||||
};
|
};
|
||||||
*self = stm
|
*self = stm
|
||||||
.compute(ctx, opt)
|
.compute(ctx, opt, txn, None)
|
||||||
.await?
|
.await?
|
||||||
.all()
|
.all()
|
||||||
.get(ctx, opt, path.next())
|
.get(ctx, opt, txn, None, path.next())
|
||||||
.await?
|
.await?
|
||||||
.flatten()
|
.flatten()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
@ -111,7 +112,7 @@ impl Value {
|
||||||
what: Values(vec![Value::from(val)]),
|
what: Values(vec![Value::from(val)]),
|
||||||
..SelectStatement::default()
|
..SelectStatement::default()
|
||||||
};
|
};
|
||||||
*self = stm.compute(ctx, opt).await?.first();
|
*self = stm.compute(ctx, opt, txn, None).await?.first();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +124,7 @@ impl Value {
|
||||||
None => match self {
|
None => match self {
|
||||||
// Current path part is an array
|
// Current path part is an array
|
||||||
Value::Array(v) => {
|
Value::Array(v) => {
|
||||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||||
try_join_all(futs).await?;
|
try_join_all(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ impl Value {
|
||||||
what: Values(vec![Value::from(val)]),
|
what: Values(vec![Value::from(val)]),
|
||||||
..SelectStatement::default()
|
..SelectStatement::default()
|
||||||
};
|
};
|
||||||
*self = stm.compute(ctx, opt).await?.first();
|
*self = stm.compute(ctx, opt, txn, None).await?.first();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// Ignore everything else
|
// Ignore everything else
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::exe::try_join_all_buffered;
|
use crate::exe::try_join_all_buffered;
|
||||||
use crate::sql::edges::Edges;
|
use crate::sql::edges::Edges;
|
||||||
|
@ -21,6 +22,8 @@ impl Value {
|
||||||
&self,
|
&self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
match path.first() {
|
match path.first() {
|
||||||
|
@ -30,15 +33,15 @@ impl Value {
|
||||||
Value::Geometry(v) => match p {
|
Value::Geometry(v) => match p {
|
||||||
// If this is the 'type' field then continue
|
// If this is the 'type' field then continue
|
||||||
Part::Field(f) if f.is_type() => {
|
Part::Field(f) if f.is_type() => {
|
||||||
Value::from(v.as_type()).get(ctx, opt, path.next()).await
|
Value::from(v.as_type()).get(ctx, opt, txn, doc, path.next()).await
|
||||||
}
|
}
|
||||||
// If this is the 'coordinates' field then continue
|
// If this is the 'coordinates' field then continue
|
||||||
Part::Field(f) if f.is_coordinates() && v.is_geometry() => {
|
Part::Field(f) if f.is_coordinates() && v.is_geometry() => {
|
||||||
v.as_coordinates().get(ctx, opt, path.next()).await
|
v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await
|
||||||
}
|
}
|
||||||
// If this is the 'geometries' field then continue
|
// If this is the 'geometries' field then continue
|
||||||
Part::Field(f) if f.is_geometries() && v.is_collection() => {
|
Part::Field(f) if f.is_geometries() && v.is_collection() => {
|
||||||
v.as_coordinates().get(ctx, opt, path.next()).await
|
v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await
|
||||||
}
|
}
|
||||||
// otherwise return none
|
// otherwise return none
|
||||||
_ => Ok(Value::None),
|
_ => Ok(Value::None),
|
||||||
|
@ -54,9 +57,9 @@ impl Value {
|
||||||
// Ensure the future is processed
|
// Ensure the future is processed
|
||||||
let fut = &opt.new_with_futures(true);
|
let fut = &opt.new_with_futures(true);
|
||||||
// Get the future return value
|
// Get the future return value
|
||||||
let val = v.compute(ctx, fut).await?;
|
let val = v.compute(ctx, fut, txn, doc).await?;
|
||||||
// Fetch the embedded field
|
// Fetch the embedded field
|
||||||
val.get(ctx, opt, path).await
|
val.get(ctx, opt, txn, doc, path).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,58 +70,57 @@ impl Value {
|
||||||
Some(Value::Thing(Thing {
|
Some(Value::Thing(Thing {
|
||||||
id: Id::Object(v),
|
id: Id::Object(v),
|
||||||
..
|
..
|
||||||
})) => Value::Object(v.clone()).get(ctx, opt, path.next()).await,
|
})) => Value::Object(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
|
||||||
Some(Value::Thing(Thing {
|
Some(Value::Thing(Thing {
|
||||||
id: Id::Array(v),
|
id: Id::Array(v),
|
||||||
..
|
..
|
||||||
})) => Value::Array(v.clone()).get(ctx, opt, path.next()).await,
|
})) => Value::Array(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
|
||||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::Graph(_) => match v.rid() {
|
Part::Graph(_) => match v.rid() {
|
||||||
Some(v) => Value::Thing(v).get(ctx, opt, path).await,
|
Some(v) => Value::Thing(v).get(ctx, opt, txn, doc, path).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::Field(f) => match v.get(f as &str) {
|
Part::Field(f) => match v.get(f as &str) {
|
||||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::All => self.get(ctx, opt, path.next()).await,
|
Part::All => self.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
_ => Ok(Value::None),
|
_ => Ok(Value::None),
|
||||||
},
|
},
|
||||||
// Current path part is an array
|
// Current path part is an array
|
||||||
Value::Array(v) => match p {
|
Value::Array(v) => match p {
|
||||||
Part::All => {
|
Part::All => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
let futs = v.iter().map(|v| v.get(ctx, opt, path));
|
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
|
||||||
try_join_all_buffered(futs).await.map(Into::into)
|
try_join_all_buffered(futs).await.map(Into::into)
|
||||||
}
|
}
|
||||||
Part::First => match v.first() {
|
Part::First => match v.first() {
|
||||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::Last => match v.last() {
|
Part::Last => match v.last() {
|
||||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::Index(i) => match v.get(i.to_usize()) {
|
Part::Index(i) => match v.get(i.to_usize()) {
|
||||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
},
|
},
|
||||||
Part::Where(w) => {
|
Part::Where(w) => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
let mut a = Vec::new();
|
let mut a = Vec::new();
|
||||||
for v in v.iter() {
|
for v in v.iter() {
|
||||||
let mut child_ctx = Context::new(ctx);
|
let cur = Some(CursorDoc::new(None, None, v));
|
||||||
child_ctx.add_cursor_doc(v);
|
if w.compute(ctx, opt, txn, cur.as_ref()).await?.is_truthy() {
|
||||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
a.push(v.get(ctx, opt, txn, cur.as_ref(), path).await?)
|
||||||
a.push(v.get(&child_ctx, opt, path).await?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(a.into())
|
Ok(a.into())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let futs = v.iter().map(|v| v.get(ctx, opt, path));
|
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
|
||||||
try_join_all_buffered(futs).await.map(Into::into)
|
try_join_all_buffered(futs).await.map(Into::into)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -137,7 +139,11 @@ impl Value {
|
||||||
what: Values(vec![Value::from(val)]),
|
what: Values(vec![Value::from(val)]),
|
||||||
..SelectStatement::default()
|
..SelectStatement::default()
|
||||||
};
|
};
|
||||||
stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await
|
stm.compute(ctx, opt, txn, None)
|
||||||
|
.await?
|
||||||
|
.first()
|
||||||
|
.get(ctx, opt, txn, None, path)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,18 +171,18 @@ impl Value {
|
||||||
};
|
};
|
||||||
match path.len() {
|
match path.len() {
|
||||||
1 => stm
|
1 => stm
|
||||||
.compute(ctx, opt)
|
.compute(ctx, opt, txn, None)
|
||||||
.await?
|
.await?
|
||||||
.all()
|
.all()
|
||||||
.get(ctx, opt, ID.as_ref())
|
.get(ctx, opt, txn, None, ID.as_ref())
|
||||||
.await?
|
.await?
|
||||||
.flatten()
|
.flatten()
|
||||||
.ok(),
|
.ok(),
|
||||||
_ => stm
|
_ => stm
|
||||||
.compute(ctx, opt)
|
.compute(ctx, opt, txn, None)
|
||||||
.await?
|
.await?
|
||||||
.all()
|
.all()
|
||||||
.get(ctx, opt, path.next())
|
.get(ctx, opt, txn, None, path.next())
|
||||||
.await?
|
.await?
|
||||||
.flatten()
|
.flatten()
|
||||||
.ok(),
|
.ok(),
|
||||||
|
@ -189,7 +195,11 @@ impl Value {
|
||||||
what: Values(vec![Value::from(val)]),
|
what: Values(vec![Value::from(val)]),
|
||||||
..SelectStatement::default()
|
..SelectStatement::default()
|
||||||
};
|
};
|
||||||
stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await
|
stm.compute(ctx, opt, txn, None)
|
||||||
|
.await?
|
||||||
|
.first()
|
||||||
|
.get(ctx, opt, txn, None, path)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -215,28 +225,28 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_none() {
|
async fn get_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::default();
|
let idi = Idiom::default();
|
||||||
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_basic() {
|
async fn get_basic() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something");
|
let idi = Idiom::parse("test.something");
|
||||||
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(123));
|
assert_eq!(res, Value::from(123));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_thing() {
|
async fn get_thing() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.other");
|
let idi = Idiom::parse("test.other");
|
||||||
let val = Value::parse("{ test: { other: test:tobie, something: 123 } }");
|
let val = Value::parse("{ test: { other: test:tobie, something: 123 } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Value::from(Thing {
|
Value::from(Thing {
|
||||||
|
@ -248,19 +258,19 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array() {
|
async fn get_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1]");
|
let idi = Idiom::parse("test.something[1]");
|
||||||
let val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
let val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(456));
|
assert_eq!(res, Value::from(456));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_thing() {
|
async fn get_array_thing() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1]");
|
let idi = Idiom::parse("test.something[1]");
|
||||||
let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }");
|
let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Value::from(Thing {
|
Value::from(Thing {
|
||||||
|
@ -272,46 +282,46 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_field() {
|
async fn get_array_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1].age");
|
let idi = Idiom::parse("test.something[1].age");
|
||||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(36));
|
assert_eq!(res, Value::from(36));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_fields() {
|
async fn get_array_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[*].age");
|
let idi = Idiom::parse("test.something[*].age");
|
||||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(vec![34, 36]));
|
assert_eq!(res, Value::from(vec![34, 36]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_fields_flat() {
|
async fn get_array_fields_flat() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.age");
|
let idi = Idiom::parse("test.something.age");
|
||||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(vec![34, 36]));
|
assert_eq!(res, Value::from(vec![34, 36]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_where_field() {
|
async fn get_array_where_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(res, Value::from(vec![36]));
|
assert_eq!(res, Value::from(vec![36]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_array_where_fields() {
|
async fn get_array_where_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Value::from(vec![Value::from(map! {
|
Value::from(vec![Value::from(map! {
|
||||||
|
@ -322,10 +332,10 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_future_embedded_field() {
|
async fn get_future_embedded_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let val = Value::parse("{ test: <future> { { something: [{ age: 34 }, { age: 36 }] } } }");
|
let val = Value::parse("{ test: <future> { { something: [{ age: 34 }, { age: 36 }] } } }");
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Value::from(vec![Value::from(map! {
|
Value::from(vec![Value::from(map! {
|
||||||
|
@ -336,12 +346,12 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn get_future_embedded_field_with_reference() {
|
async fn get_future_embedded_field_with_reference() {
|
||||||
let (mut ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }");
|
let doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }");
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let val = Value::parse("{ test: <future> { { something: something } } }");
|
let val = Value::parse("{ test: <future> { { something: something } } }");
|
||||||
ctx.add_cursor_doc(&doc);
|
let cur = CursorDoc::new(None, None, &doc);
|
||||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
let res = val.get(&ctx, &opt, &txn, Some(&cur), &idi).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
res,
|
res,
|
||||||
Value::from(vec![Value::from(map! {
|
Value::from(vec![Value::from(map! {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::number::Number;
|
use crate::sql::number::Number;
|
||||||
use crate::sql::part::Part;
|
use crate::sql::part::Part;
|
||||||
|
@ -11,24 +11,25 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
val: Value,
|
val: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match self.get(ctx, opt, path).await? {
|
match self.get(ctx, opt, txn, None, path).await? {
|
||||||
Value::Number(v) => match val {
|
Value::Number(v) => match val {
|
||||||
Value::Number(x) => self.set(ctx, opt, path, Value::from(v + x)).await,
|
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
},
|
},
|
||||||
Value::Array(v) => match val {
|
Value::Array(v) => match val {
|
||||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(v + x)).await,
|
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||||
x => self.set(ctx, opt, path, Value::from(v + x)).await,
|
x => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||||
},
|
},
|
||||||
Value::None => match val {
|
Value::None => match val {
|
||||||
Value::Number(x) => {
|
Value::Number(x) => {
|
||||||
self.set(ctx, opt, path, Value::from(Number::from(0) + x)).await
|
self.set(ctx, opt, txn, path, Value::from(Number::from(0) + x)).await
|
||||||
}
|
}
|
||||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await,
|
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
|
||||||
x => self.set(ctx, opt, path, Value::from(vec![x])).await,
|
x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
|
||||||
},
|
},
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
|
@ -45,51 +46,51 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn increment_none() {
|
async fn increment_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("other");
|
let idi = Idiom::parse("other");
|
||||||
let mut val = Value::parse("{ test: 100 }");
|
let mut val = Value::parse("{ test: 100 }");
|
||||||
let res = Value::parse("{ test: 100, other: +10 }");
|
let res = Value::parse("{ test: 100, other: +10 }");
|
||||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn increment_number() {
|
async fn increment_number() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: 100 }");
|
let mut val = Value::parse("{ test: 100 }");
|
||||||
let res = Value::parse("{ test: 110 }");
|
let res = Value::parse("{ test: 110 }");
|
||||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn increment_array_number() {
|
async fn increment_array_number() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test[1]");
|
let idi = Idiom::parse("test[1]");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 210, 300] }");
|
let res = Value::parse("{ test: [100, 210, 300] }");
|
||||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn increment_array_value() {
|
async fn increment_array_value() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 200, 300, 200] }");
|
let res = Value::parse("{ test: [100, 200, 300, 200] }");
|
||||||
val.increment(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
val.increment(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn increment_array_array() {
|
async fn increment_array_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||||
let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }");
|
let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }");
|
||||||
val.increment(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
val.increment(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::exe::try_join_all_buffered;
|
use crate::exe::try_join_all_buffered;
|
||||||
use crate::sql::part::Next;
|
use crate::sql::part::Next;
|
||||||
|
@ -15,6 +16,7 @@ impl Value {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
opt: &Options,
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
path: &[Part],
|
path: &[Part],
|
||||||
val: Value,
|
val: Value,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
@ -24,28 +26,28 @@ impl Value {
|
||||||
// Current path part is an object
|
// Current path part is an object
|
||||||
Value::Object(v) => match p {
|
Value::Object(v) => match p {
|
||||||
Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) {
|
Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) {
|
||||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
_ => {
|
_ => {
|
||||||
let mut obj = Value::base();
|
let mut obj = Value::base();
|
||||||
obj.set(ctx, opt, path.next(), val).await?;
|
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||||
v.insert(g.to_raw(), obj);
|
v.insert(g.to_raw(), obj);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Part::Field(f) => match v.get_mut(f as &str) {
|
Part::Field(f) => match v.get_mut(f as &str) {
|
||||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
_ => {
|
_ => {
|
||||||
let mut obj = Value::base();
|
let mut obj = Value::base();
|
||||||
obj.set(ctx, opt, path.next(), val).await?;
|
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||||
v.insert(f.to_raw(), obj);
|
v.insert(f.to_raw(), obj);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
||||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
_ => {
|
_ => {
|
||||||
let mut obj = Value::base();
|
let mut obj = Value::base();
|
||||||
obj.set(ctx, opt, path.next(), val).await?;
|
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||||
v.insert(i.to_string(), obj);
|
v.insert(i.to_string(), obj);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -56,35 +58,34 @@ impl Value {
|
||||||
Value::Array(v) => match p {
|
Value::Array(v) => match p {
|
||||||
Part::All => {
|
Part::All => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone()));
|
let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||||
try_join_all_buffered(futs).await?;
|
try_join_all_buffered(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Part::First => match v.first_mut() {
|
Part::First => match v.first_mut() {
|
||||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Last => match v.last_mut() {
|
Part::Last => match v.last_mut() {
|
||||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
||||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
},
|
},
|
||||||
Part::Where(w) => {
|
Part::Where(w) => {
|
||||||
let path = path.next();
|
let path = path.next();
|
||||||
for v in v.iter_mut() {
|
for v in v.iter_mut() {
|
||||||
let mut child_ctx = Context::new(ctx);
|
let cur = CursorDoc::new(None, None, v);
|
||||||
child_ctx.add_cursor_doc(v);
|
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
v.set(ctx, opt, txn, path, val.clone()).await?;
|
||||||
v.set(ctx, opt, path, val.clone()).await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone()));
|
let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||||
try_join_all_buffered(futs).await?;
|
try_join_all_buffered(futs).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -92,12 +93,12 @@ impl Value {
|
||||||
// Current path part is empty
|
// Current path part is empty
|
||||||
Value::Null => {
|
Value::Null => {
|
||||||
*self = Value::base();
|
*self = Value::base();
|
||||||
self.set(ctx, opt, path, val).await
|
self.set(ctx, opt, txn, path, val).await
|
||||||
}
|
}
|
||||||
// Current path part is empty
|
// Current path part is empty
|
||||||
Value::None => {
|
Value::None => {
|
||||||
*self = Value::base();
|
*self = Value::base();
|
||||||
self.set(ctx, opt, path, val).await
|
self.set(ctx, opt, txn, path, val).await
|
||||||
}
|
}
|
||||||
// Ignore everything else
|
// Ignore everything else
|
||||||
_ => Ok(()),
|
_ => Ok(()),
|
||||||
|
@ -121,141 +122,141 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_none() {
|
async fn set_none() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::default();
|
let idi = Idiom::default();
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("999");
|
let res = Value::parse("999");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_empty() {
|
async fn set_empty() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::None;
|
let mut val = Value::None;
|
||||||
let res = Value::parse("{ test: 999 }");
|
let res = Value::parse("{ test: 999 }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_blank() {
|
async fn set_blank() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something");
|
let idi = Idiom::parse("test.something");
|
||||||
let mut val = Value::None;
|
let mut val = Value::None;
|
||||||
let res = Value::parse("{ test: { something: 999 } }");
|
let res = Value::parse("{ test: { something: 999 } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_reset() {
|
async fn set_reset() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test");
|
let idi = Idiom::parse("test");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: 999 }");
|
let res = Value::parse("{ test: 999 }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_basic() {
|
async fn set_basic() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something");
|
let idi = Idiom::parse("test.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 999 } }");
|
let res = Value::parse("{ test: { other: null, something: 999 } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_allow() {
|
async fn set_allow() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.allow");
|
let idi = Idiom::parse("test.something.allow");
|
||||||
let mut val = Value::parse("{ test: { other: null } }");
|
let mut val = Value::parse("{ test: { other: null } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }");
|
let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_wrong() {
|
async fn set_wrong() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.wrong");
|
let idi = Idiom::parse("test.something.wrong");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_other() {
|
async fn set_other() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.other.something");
|
let idi = Idiom::parse("test.other.something");
|
||||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||||
let res = Value::parse("{ test: { other: { something: 999 }, something: 123 } }");
|
let res = Value::parse("{ test: { other: { something: 999 }, something: 123 } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array() {
|
async fn set_array() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1]");
|
let idi = Idiom::parse("test.something[1]");
|
||||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||||
let res = Value::parse("{ test: { something: [123, 999, 789] } }");
|
let res = Value::parse("{ test: { something: [123, 999, 789] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array_field() {
|
async fn set_array_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[1].age");
|
let idi = Idiom::parse("test.something[1].age");
|
||||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array_fields() {
|
async fn set_array_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[*].age");
|
let idi = Idiom::parse("test.something[*].age");
|
||||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array_fields_flat() {
|
async fn set_array_fields_flat() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something.age");
|
let idi = Idiom::parse("test.something.age");
|
||||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array_where_field() {
|
async fn set_array_where_field() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn set_array_where_fields() {
|
async fn set_array_where_fields() {
|
||||||
let (ctx, opt) = mock().await;
|
let (ctx, opt, txn) = mock().await;
|
||||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||||
let res = Value::parse("{ test: { something: [{ age: 34 }, 21] } }");
|
let res = Value::parse("{ test: { something: [{ age: 34 }, 21] } }");
|
||||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||||
assert_eq!(res, val);
|
assert_eq!(res, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#![allow(clippy::derive_ord_xor_partial_ord)]
|
#![allow(clippy::derive_ord_xor_partial_ord)]
|
||||||
|
|
||||||
use crate::ctx::Context;
|
use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::{Options, Transaction};
|
||||||
|
use crate::doc::CursorDoc;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::array::Uniq;
|
use crate::sql::array::Uniq;
|
||||||
use crate::sql::array::{array, Array};
|
use crate::sql::array::{array, Array};
|
||||||
|
@ -2484,21 +2485,27 @@ impl Value {
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(
|
||||||
|
&self,
|
||||||
|
ctx: &Context<'_>,
|
||||||
|
opt: &Options,
|
||||||
|
txn: &Transaction,
|
||||||
|
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||||
|
) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
Value::Cast(v) => v.compute(ctx, opt).await,
|
Value::Cast(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Thing(v) => v.compute(ctx, opt).await,
|
Value::Thing(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Block(v) => v.compute(ctx, opt).await,
|
Value::Block(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Range(v) => v.compute(ctx, opt).await,
|
Value::Range(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Param(v) => v.compute(ctx, opt).await,
|
Value::Param(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Idiom(v) => v.compute(ctx, opt).await,
|
Value::Idiom(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Array(v) => v.compute(ctx, opt).await,
|
Value::Array(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Object(v) => v.compute(ctx, opt).await,
|
Value::Object(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Future(v) => v.compute(ctx, opt).await,
|
Value::Future(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Constant(v) => v.compute(ctx, opt).await,
|
Value::Constant(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Function(v) => v.compute(ctx, opt).await,
|
Value::Function(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Subquery(v) => v.compute(ctx, opt).await,
|
Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
Value::Expression(v) => v.compute(ctx, opt).await,
|
Value::Expression(v) => v.compute(ctx, opt, txn, doc).await,
|
||||||
_ => Ok(self.to_owned()),
|
_ => Ok(self.to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,14 +92,20 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(), Error> {
|
||||||
async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> {
|
let sql = format!(
|
||||||
let sql = r"
|
r"
|
||||||
CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr'];
|
CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr'];
|
||||||
DEFINE ANALYZER simple TOKENIZERS blank,class;
|
DEFINE ANALYZER simple TOKENIZERS blank,class;
|
||||||
DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS;
|
DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS;
|
||||||
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' EXPLAIN;
|
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {} EXPLAIN;
|
||||||
";
|
",
|
||||||
|
if parallel {
|
||||||
|
"PARALLEL"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
);
|
||||||
let dbs = Datastore::new("memory").await?;
|
let dbs = Datastore::new("memory").await?;
|
||||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
let res = &mut dbs.execute(&sql, &ses, None).await?;
|
let res = &mut dbs.execute(&sql, &ses, None).await?;
|
||||||
|
@ -141,6 +147,16 @@ async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn select_where_matches_using_index_and_arrays_non_parallel() -> Result<(), Error> {
|
||||||
|
select_where_matches_using_index_and_arrays(false).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn select_where_matches_using_index_and_arrays_with_parallel() -> Result<(), Error> {
|
||||||
|
select_where_matches_using_index_and_arrays(true).await
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
|
async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
|
||||||
let sql = r"
|
let sql = r"
|
||||||
|
|
Loading…
Reference in a new issue