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-executor",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"base64 0.21.2",
|
||||
"bcrypt",
|
||||
"bincode",
|
||||
|
|
|
@ -54,7 +54,6 @@ targets = []
|
|||
addr = { version = "0.15.6", default-features = false, features = ["std"] }
|
||||
argon2 = "0.5.0"
|
||||
ascii = { version = "0.3.2", package = "any_ascii" }
|
||||
async-trait = "0.1.69"
|
||||
async-recursion = "1.0.4"
|
||||
base64_lib = { version = "0.21.2", package = "base64" }
|
||||
bcrypt = "0.14.0"
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
use crate::ctx::canceller::Canceller;
|
||||
use crate::ctx::reason::Reason;
|
||||
use crate::dbs::Notification;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::idx::planner::executor::QueryExecutor;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Thing;
|
||||
use channel::Sender;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
@ -36,18 +32,10 @@ pub struct Context<'a> {
|
|||
cancelled: Arc<AtomicBool>,
|
||||
// A collection of read only values stored in this context.
|
||||
values: HashMap<Cow<'static, str>, Cow<'a, Value>>,
|
||||
// Stores the current transaction if available
|
||||
transaction: Option<Transaction>,
|
||||
// Stores the notification channel if available
|
||||
notifications: Option<Sender<Notification>>,
|
||||
// An optional query executor
|
||||
query_executors: Option<Arc<HashMap<String, QueryExecutor>>>,
|
||||
// An optional record id
|
||||
thing: Option<&'a Thing>,
|
||||
// An optional doc id
|
||||
doc_id: Option<DocId>,
|
||||
// An optional cursor document
|
||||
cursor_doc: Option<&'a Value>,
|
||||
}
|
||||
|
||||
impl<'a> Default for Context<'a> {
|
||||
|
@ -63,8 +51,6 @@ impl<'a> Debug for Context<'a> {
|
|||
.field("deadline", &self.deadline)
|
||||
.field("cancelled", &self.cancelled)
|
||||
.field("values", &self.values)
|
||||
.field("thing", &self.thing)
|
||||
.field("doc", &self.cursor_doc)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -77,12 +63,8 @@ impl<'a> Context<'a> {
|
|||
parent: None,
|
||||
deadline: None,
|
||||
cancelled: Arc::new(AtomicBool::new(false)),
|
||||
transaction: None,
|
||||
notifications: None,
|
||||
query_executors: None,
|
||||
thing: None,
|
||||
doc_id: None,
|
||||
cursor_doc: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,12 +75,8 @@ impl<'a> Context<'a> {
|
|||
parent: Some(parent),
|
||||
deadline: parent.deadline,
|
||||
cancelled: Arc::new(AtomicBool::new(false)),
|
||||
transaction: parent.transaction.clone(),
|
||||
notifications: parent.notifications.clone(),
|
||||
query_executors: parent.query_executors.clone(),
|
||||
thing: parent.thing,
|
||||
doc_id: parent.doc_id,
|
||||
cursor_doc: parent.cursor_doc,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,34 +112,12 @@ impl<'a> Context<'a> {
|
|||
self.add_deadline(Instant::now() + timeout)
|
||||
}
|
||||
|
||||
/// Add the current transaction to the context, so that it can be fetched
|
||||
/// where necessary, including inside the query planner.
|
||||
pub fn add_transaction(&mut self, txn: Option<&Transaction>) {
|
||||
self.transaction = txn.cloned()
|
||||
}
|
||||
|
||||
/// Add the LIVE query notification channel to the context, so that we
|
||||
/// can send notifications to any subscribers.
|
||||
pub fn add_notifications(&mut self, chn: Option<&Sender<Notification>>) {
|
||||
self.notifications = chn.cloned()
|
||||
}
|
||||
|
||||
/// Add a cursor document to this context.
|
||||
/// Usage: A new child context is created by an iterator for each document.
|
||||
/// The iterator sets the value of the current document (known as cursor document).
|
||||
/// The cursor document is copied do the child contexts.
|
||||
pub fn add_cursor_doc(&mut self, doc: &'a Value) {
|
||||
self.cursor_doc = Some(doc);
|
||||
}
|
||||
|
||||
pub fn add_thing(&mut self, thing: &'a Thing) {
|
||||
self.thing = Some(thing);
|
||||
}
|
||||
|
||||
pub fn add_doc_id(&mut self, doc_id: DocId) {
|
||||
self.doc_id = Some(doc_id);
|
||||
}
|
||||
|
||||
/// Set the query executors
|
||||
pub(crate) fn set_query_executors(&mut self, executors: HashMap<String, QueryExecutor>) {
|
||||
self.query_executors = Some(Arc::new(executors));
|
||||
|
@ -173,28 +129,10 @@ impl<'a> Context<'a> {
|
|||
self.deadline.map(|v| v.saturating_duration_since(Instant::now()))
|
||||
}
|
||||
|
||||
/// Returns a transaction if any.
|
||||
/// Otherwise it fails by returning a Error::NoTx error.
|
||||
pub fn try_clone_transaction(&self) -> Result<Transaction, Error> {
|
||||
self.transaction.clone().ok_or(Error::Unreachable)
|
||||
}
|
||||
|
||||
pub fn notifications(&self) -> Option<Sender<Notification>> {
|
||||
self.notifications.clone()
|
||||
}
|
||||
|
||||
pub fn thing(&self) -> Option<&Thing> {
|
||||
self.thing
|
||||
}
|
||||
|
||||
pub fn doc_id(&self) -> Option<DocId> {
|
||||
self.doc_id
|
||||
}
|
||||
|
||||
pub fn doc(&self) -> Option<&Value> {
|
||||
self.cursor_doc
|
||||
}
|
||||
|
||||
pub(crate) fn get_query_executor(&self, tb: &str) -> Option<&QueryExecutor> {
|
||||
if let Some(qe) = &self.query_executors {
|
||||
qe.get(tb)
|
||||
|
|
|
@ -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
|
||||
/// - true if a new transaction has begun
|
||||
/// - false if
|
||||
|
@ -275,10 +279,7 @@ impl<'a> Executor<'a> {
|
|||
// Check if the variable is a protected variable
|
||||
let res = match PROTECTED_PARAM_NAMES.contains(&stm.name.as_str()) {
|
||||
// The variable isn't protected and can be stored
|
||||
false => {
|
||||
ctx.add_transaction(self.txn.as_ref());
|
||||
stm.compute(&ctx, &opt).await
|
||||
}
|
||||
false => stm.compute(&ctx, &opt, &self.txn(), None).await,
|
||||
// The user tried to set a protected variable
|
||||
true => Err(Error::InvalidParam {
|
||||
// Move the parameter name, as we no longer need it
|
||||
|
@ -338,16 +339,15 @@ impl<'a> Executor<'a> {
|
|||
true => Err(Error::TxFailure),
|
||||
// The transaction began successfully
|
||||
false => {
|
||||
let mut ctx = Context::new(&ctx);
|
||||
// Process the statement
|
||||
let res = match stm.timeout() {
|
||||
// There is a timeout clause
|
||||
Some(timeout) => {
|
||||
// Set statement timeout
|
||||
let mut ctx = Context::new(&ctx);
|
||||
ctx.add_timeout(timeout);
|
||||
ctx.add_transaction(self.txn.as_ref());
|
||||
// Process the statement
|
||||
let res = stm.compute(&ctx, &opt).await;
|
||||
let res = stm.compute(&ctx, &opt, &self.txn(), None).await;
|
||||
// Catch statement timeout
|
||||
match ctx.is_timedout() {
|
||||
true => Err(Error::QueryTimedout),
|
||||
|
@ -355,10 +355,7 @@ impl<'a> Executor<'a> {
|
|||
}
|
||||
}
|
||||
// There is no timeout clause
|
||||
None => {
|
||||
ctx.add_transaction(self.txn.as_ref());
|
||||
stm.compute(&ctx, &opt).await
|
||||
}
|
||||
None => stm.compute(&ctx, &opt, &self.txn(), None).await,
|
||||
};
|
||||
// Catch global timeout
|
||||
let res = match ctx.is_timedout() {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use crate::ctx::Canceller;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::idx::planner::plan::Plan;
|
||||
use crate::sql::array::Array;
|
||||
use crate::sql::edges::Edges;
|
||||
|
@ -74,6 +76,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Log the statement
|
||||
|
@ -82,29 +85,29 @@ impl Iterator {
|
|||
let mut cancel_ctx = Context::new(ctx);
|
||||
self.run = cancel_ctx.add_cancel();
|
||||
// Process the query LIMIT clause
|
||||
self.setup_limit(&cancel_ctx, opt, stm).await?;
|
||||
self.setup_limit(&cancel_ctx, opt, txn, stm).await?;
|
||||
// Process the query START clause
|
||||
self.setup_start(&cancel_ctx, opt, stm).await?;
|
||||
self.setup_start(&cancel_ctx, opt, txn, stm).await?;
|
||||
// Process any EXPLAIN clause
|
||||
let explanation = self.output_explain(&cancel_ctx, opt, stm)?;
|
||||
let explanation = self.output_explain(&cancel_ctx, opt, txn, stm)?;
|
||||
// Process prepared values
|
||||
self.iterate(&cancel_ctx, opt, stm).await?;
|
||||
self.iterate(&cancel_ctx, opt, txn, stm).await?;
|
||||
// Return any document errors
|
||||
if let Some(e) = self.error.take() {
|
||||
return Err(e);
|
||||
}
|
||||
// Process any SPLIT clause
|
||||
self.output_split(ctx, opt, stm).await?;
|
||||
self.output_split(ctx, opt, txn, stm).await?;
|
||||
// Process any GROUP clause
|
||||
self.output_group(ctx, opt, stm).await?;
|
||||
self.output_group(ctx, opt, txn, stm).await?;
|
||||
// Process any ORDER clause
|
||||
self.output_order(ctx, opt, stm).await?;
|
||||
self.output_order(ctx, opt, txn, stm).await?;
|
||||
// Process any START clause
|
||||
self.output_start(ctx, opt, stm).await?;
|
||||
self.output_start(ctx, opt, txn, stm).await?;
|
||||
// Process any LIMIT clause
|
||||
self.output_limit(ctx, opt, stm).await?;
|
||||
self.output_limit(ctx, opt, txn, stm).await?;
|
||||
// Process any FETCH clause
|
||||
self.output_fetch(ctx, opt, stm).await?;
|
||||
self.output_fetch(ctx, opt, txn, stm).await?;
|
||||
// Add the EXPLAIN clause to the result
|
||||
if let Some(e) = explanation {
|
||||
self.results.push(e);
|
||||
|
@ -118,10 +121,11 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(v) = stm.limit() {
|
||||
self.limit = Some(v.process(ctx, opt).await?);
|
||||
self.limit = Some(v.process(ctx, opt, txn, None).await?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -131,10 +135,11 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(v) = stm.start() {
|
||||
self.start = Some(v.process(ctx, opt).await?);
|
||||
self.start = Some(v.process(ctx, opt, txn, None).await?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -144,6 +149,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(splits) = stm.split() {
|
||||
|
@ -162,7 +168,7 @@ impl Iterator {
|
|||
// Make a copy of object
|
||||
let mut obj = obj.clone();
|
||||
// Set the value at the path
|
||||
obj.set(ctx, opt, split, val).await?;
|
||||
obj.set(ctx, opt, txn, split, val).await?;
|
||||
// Add the object to the results
|
||||
self.results.push(obj);
|
||||
}
|
||||
|
@ -171,7 +177,7 @@ impl Iterator {
|
|||
// Make a copy of object
|
||||
let mut obj = obj.clone();
|
||||
// Set the value at the path
|
||||
obj.set(ctx, opt, split, val).await?;
|
||||
obj.set(ctx, opt, txn, split, val).await?;
|
||||
// Add the object to the results
|
||||
self.results.push(obj);
|
||||
}
|
||||
|
@ -187,6 +193,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(fields) = stm.expr() {
|
||||
|
@ -234,20 +241,21 @@ impl Iterator {
|
|||
.unwrap_or_else(|| Cow::Owned(expr.to_idiom()));
|
||||
match expr {
|
||||
Value::Function(f) if f.is_aggregate() => {
|
||||
let x = vals.all().get(ctx, opt, idiom.as_ref()).await?;
|
||||
let x = f.aggregate(x).compute(ctx, opt).await?;
|
||||
obj.set(ctx, opt, idiom.as_ref(), x).await?;
|
||||
let x =
|
||||
vals.all().get(ctx, opt, txn, None, idiom.as_ref()).await?;
|
||||
let x = f.aggregate(x).compute(ctx, opt, txn, None).await?;
|
||||
obj.set(ctx, opt, txn, idiom.as_ref(), x).await?;
|
||||
}
|
||||
_ => {
|
||||
let x = vals.first();
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(&x);
|
||||
let x = if let Some(alias) = alias {
|
||||
alias.compute(&child_ctx, opt).await?
|
||||
let cur = CursorDoc::new(None, None, &x);
|
||||
alias.compute(ctx, opt, txn, Some(&cur)).await?
|
||||
} else {
|
||||
expr.compute(&child_ctx, opt).await?
|
||||
let cur = CursorDoc::new(None, None, &x);
|
||||
expr.compute(ctx, opt, txn, Some(&cur)).await?
|
||||
};
|
||||
obj.set(ctx, opt, idiom.as_ref(), x).await?;
|
||||
obj.set(ctx, opt, txn, idiom.as_ref(), x).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,6 +273,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(orders) = stm.order() {
|
||||
|
@ -303,6 +312,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(v) = self.start {
|
||||
|
@ -316,6 +326,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(v) = self.limit {
|
||||
|
@ -329,6 +340,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(fetchs) = stm.fetch() {
|
||||
|
@ -336,7 +348,7 @@ impl Iterator {
|
|||
// Loop over each result value
|
||||
for obj in &mut self.results {
|
||||
// Fetch the value at the path
|
||||
obj.fetch(ctx, opt, fetch).await?;
|
||||
obj.fetch(ctx, opt, txn, fetch).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -348,6 +360,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Option<Value>, Error> {
|
||||
Ok(if stm.explain() {
|
||||
|
@ -405,13 +418,14 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Prevent deep recursion
|
||||
let opt = &opt.dive(4)?;
|
||||
// Process all prepared values
|
||||
for v in mem::take(&mut self.entries) {
|
||||
v.iterate(ctx, opt, stm, self).await?;
|
||||
v.iterate(ctx, opt, txn, stm, self).await?;
|
||||
}
|
||||
// Everything processed ok
|
||||
Ok(())
|
||||
|
@ -423,6 +437,7 @@ impl Iterator {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Prevent deep recursion
|
||||
|
@ -433,7 +448,7 @@ impl Iterator {
|
|||
false => {
|
||||
// Process all prepared values
|
||||
for v in mem::take(&mut self.entries) {
|
||||
v.iterate(ctx, opt, stm, self).await?;
|
||||
v.iterate(ctx, opt, txn, stm, self).await?;
|
||||
}
|
||||
// Everything processed ok
|
||||
Ok(())
|
||||
|
@ -452,7 +467,7 @@ impl Iterator {
|
|||
let adocs = async {
|
||||
// Process all prepared values
|
||||
for v in vals {
|
||||
e.spawn(v.channel(ctx, opt, stm, chn.clone()))
|
||||
e.spawn(v.channel(ctx, opt, txn, stm, chn.clone()))
|
||||
// Ensure we detach the spawned task
|
||||
.detach();
|
||||
}
|
||||
|
@ -464,8 +479,8 @@ impl Iterator {
|
|||
// Create an async closure for received values
|
||||
let avals = async {
|
||||
// Process all received values
|
||||
while let Ok((k, v)) = docs.recv().await {
|
||||
e.spawn(Document::compute(ctx, opt, stm, chn.clone(), k, v))
|
||||
while let Ok((k, d, v)) = docs.recv().await {
|
||||
e.spawn(Document::compute(ctx, opt, txn, stm, chn.clone(), k, d, v))
|
||||
// Ensure we detach the spawned task
|
||||
.detach();
|
||||
}
|
||||
|
@ -494,11 +509,15 @@ impl Iterator {
|
|||
}
|
||||
|
||||
/// Process a new record Thing and Value
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn process(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
thg: Option<Thing>,
|
||||
doc_id: Option<DocId>,
|
||||
val: Operable,
|
||||
) {
|
||||
// Check current context
|
||||
|
@ -512,15 +531,15 @@ impl Iterator {
|
|||
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
||||
};
|
||||
// Setup a new document
|
||||
let mut doc = Document::new(ctx.thing(), &val, ext);
|
||||
let mut doc = Document::new(thg.as_ref(), doc_id, &val, ext);
|
||||
// Process the document
|
||||
let res = match stm {
|
||||
Statement::Select(_) => doc.select(ctx, opt, stm).await,
|
||||
Statement::Create(_) => doc.create(ctx, opt, stm).await,
|
||||
Statement::Update(_) => doc.update(ctx, opt, stm).await,
|
||||
Statement::Relate(_) => doc.relate(ctx, opt, stm).await,
|
||||
Statement::Delete(_) => doc.delete(ctx, opt, stm).await,
|
||||
Statement::Insert(_) => doc.insert(ctx, opt, stm).await,
|
||||
Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
|
||||
Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
|
||||
Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
|
||||
Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
|
||||
Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
|
||||
Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Process the result
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
//! and executors to process the operations. This module also gives a `context` to the transaction.
|
||||
mod auth;
|
||||
mod executor;
|
||||
mod iterate;
|
||||
mod iterator;
|
||||
mod notification;
|
||||
mod options;
|
||||
|
@ -26,13 +25,8 @@ pub(crate) use self::statement::*;
|
|||
pub(crate) use self::transaction::*;
|
||||
pub(crate) use self::variables::*;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod channel;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use self::channel::*;
|
||||
|
||||
pub mod cl;
|
||||
|
||||
mod processor;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test;
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Operable;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Iterator, Operable, Options, Statement, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::idx::planner::plan::Plan;
|
||||
use crate::key::graph;
|
||||
use crate::key::thing;
|
||||
use crate::key::{graph, thing};
|
||||
use crate::sql::dir::Dir;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::{Edges, Range, Table};
|
||||
use crate::sql::{Edges, Range, Table, Thing, Value};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use channel::Sender;
|
||||
use std::ops::Bound;
|
||||
|
||||
impl Iterable {
|
||||
|
@ -19,50 +15,105 @@ impl Iterable {
|
|||
self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
Processor::Iterator(ite).process_iterable(ctx, opt, txn, stm, self).await
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) async fn channel(
|
||||
self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
chn: Sender<(Option<Thing>, Option<DocId>, Operable)>,
|
||||
) -> Result<(), Error> {
|
||||
Processor::Channel(chn).process_iterable(ctx, opt, txn, stm, self).await
|
||||
}
|
||||
}
|
||||
|
||||
enum Processor<'a> {
|
||||
Iterator(&'a mut Iterator),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Channel(Sender<(Option<Thing>, Option<DocId>, Operable)>),
|
||||
}
|
||||
|
||||
impl<'a> Processor<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn process(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
rid: Option<Thing>,
|
||||
doc_id: Option<DocId>,
|
||||
val: Operable,
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Processor::Iterator(ite) => {
|
||||
ite.process(ctx, opt, txn, stm, rid, doc_id, val).await;
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
Processor::Channel(chn) => {
|
||||
chn.send((rid, doc_id, val)).await?;
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_iterable(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
iterable: Iterable,
|
||||
) -> Result<(), Error> {
|
||||
if ctx.is_ok() {
|
||||
match self {
|
||||
Iterable::Value(v) => Self::iterate_value(ctx, opt, stm, v, ite).await,
|
||||
Iterable::Thing(v) => Self::iterate_thing(ctx, opt, stm, v, ite).await?,
|
||||
Iterable::Table(v) => Self::iterate_table(ctx, opt, stm, v, ite).await?,
|
||||
Iterable::Range(v) => Self::iterate_range(ctx, opt, stm, v, ite).await?,
|
||||
Iterable::Edges(e) => Self::iterate_edge(ctx, opt, stm, e, ite).await?,
|
||||
Iterable::Index(t, p) => Self::iterate_index(ctx, opt, stm, t, p, ite).await?,
|
||||
match iterable {
|
||||
Iterable::Value(v) => self.process_value(ctx, opt, txn, stm, v).await?,
|
||||
Iterable::Thing(v) => self.process_thing(ctx, opt, txn, stm, v).await?,
|
||||
Iterable::Table(v) => self.process_table(ctx, opt, txn, stm, v).await?,
|
||||
Iterable::Range(v) => self.process_range(ctx, opt, txn, stm, v).await?,
|
||||
Iterable::Edges(e) => self.process_edge(ctx, opt, txn, stm, e).await?,
|
||||
Iterable::Index(t, p) => self.process_index(ctx, opt, txn, stm, t, p).await?,
|
||||
Iterable::Mergeable(v, o) => {
|
||||
Self::iterate_mergeable(ctx, opt, stm, v, o, ite).await?
|
||||
self.process_mergeable(ctx, opt, txn, stm, v, o).await?
|
||||
}
|
||||
Iterable::Relatable(f, v, w) => {
|
||||
Self::iterate_relatable(ctx, opt, stm, f, v, w, ite).await?
|
||||
self.process_relatable(ctx, opt, txn, stm, f, v, w).await?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_value(
|
||||
async fn process_value(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
v: Value,
|
||||
ite: &mut Iterator,
|
||||
) {
|
||||
) -> Result<(), Error> {
|
||||
// Pass the value through
|
||||
let val = Operable::Value(v);
|
||||
// Process the document record
|
||||
ite.process(ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, None, None, val).await
|
||||
}
|
||||
|
||||
async fn iterate_thing(
|
||||
async fn process_thing(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
v: Thing,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Fetch the data from the store
|
||||
|
@ -73,25 +124,21 @@ impl Iterable {
|
|||
Some(v) => Value::from(v),
|
||||
None => Value::None,
|
||||
});
|
||||
// Get the optional query executor
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_thing(&v);
|
||||
// Process the document record
|
||||
ite.process(&child_ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||
// Everything ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_mergeable(
|
||||
async fn process_mergeable(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
v: Thing,
|
||||
o: Value,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Fetch the data from the store
|
||||
|
@ -104,26 +151,23 @@ impl Iterable {
|
|||
};
|
||||
// Create a new operable value
|
||||
let val = Operable::Mergeable(x, o);
|
||||
// Create a new context to process the operable
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_thing(&v);
|
||||
// Process the document record
|
||||
ite.process(&child_ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||
// Everything ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_relatable(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn process_relatable(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
f: Thing,
|
||||
v: Thing,
|
||||
w: Thing,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Fetch the data from the store
|
||||
|
@ -136,24 +180,20 @@ impl Iterable {
|
|||
};
|
||||
// Create a new operable value
|
||||
let val = Operable::Relatable(f, x, w);
|
||||
// Create the child context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_thing(&v);
|
||||
// Process the document record
|
||||
ite.process(&child_ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(v), None, val).await?;
|
||||
// Everything ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_table(
|
||||
async fn process_table(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
v: Table,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v, opt.strict).await?;
|
||||
// Prepare the start and end keys
|
||||
|
@ -201,10 +241,8 @@ impl Iterable {
|
|||
let rid = Thing::from((key.tb, key.id));
|
||||
// Create a new operable value
|
||||
let val = Operable::Value(val);
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_thing(&rid);
|
||||
// Process the record
|
||||
ite.process(&child_ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -214,15 +252,14 @@ impl Iterable {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_range(
|
||||
async fn process_range(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
v: Range,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &v.tb, opt.strict).await?;
|
||||
// Prepare the range start key
|
||||
|
@ -285,12 +322,10 @@ impl Iterable {
|
|||
let key: crate::key::thing::Thing = (&k).into();
|
||||
let val: crate::sql::value::Value = (&v).into();
|
||||
let rid = Thing::from((key.tb, key.id));
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_thing(&rid);
|
||||
// Create a new operable value
|
||||
let val = Operable::Value(val);
|
||||
// Process the record
|
||||
ite.process(&ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -300,12 +335,13 @@ impl Iterable {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_edge(
|
||||
async fn process_edge(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
e: Edges,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Pull out options
|
||||
let ns = opt.ns();
|
||||
|
@ -390,13 +426,13 @@ impl Iterable {
|
|||
None => {
|
||||
let min = beg.clone();
|
||||
let max = end.clone();
|
||||
ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await?
|
||||
txn.lock().await.scan(min..max, 1000).await?
|
||||
}
|
||||
Some(ref mut beg) => {
|
||||
beg.push(0x00);
|
||||
let min = beg.clone();
|
||||
let max = end.clone();
|
||||
ctx.try_clone_transaction()?.lock().await.scan(min..max, 1000).await?
|
||||
txn.lock().await.scan(min..max, 1000).await?
|
||||
}
|
||||
};
|
||||
// If there are key-value entries then fetch them
|
||||
|
@ -421,17 +457,15 @@ impl Iterable {
|
|||
let gra: crate::key::graph::Graph = (&k).into();
|
||||
// Fetch the data from the store
|
||||
let key = thing::new(opt.ns(), opt.db(), gra.ft, &gra.fk);
|
||||
let val = ctx.try_clone_transaction()?.lock().await.get(key).await?;
|
||||
let val = txn.lock().await.get(key).await?;
|
||||
let rid = Thing::from((gra.ft, gra.fk));
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_thing(&rid);
|
||||
// Parse the data from the store
|
||||
let val = Operable::Value(match val {
|
||||
Some(v) => Value::from(v),
|
||||
None => Value::None,
|
||||
});
|
||||
// Process the record
|
||||
ite.process(&ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(rid), None, val).await?;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -442,22 +476,21 @@ impl Iterable {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn iterate_index(
|
||||
async fn process_index(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
table: Table,
|
||||
plan: Plan,
|
||||
ite: &mut Iterator,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check that the table exists
|
||||
txn.lock().await.check_ns_db_tb(opt.ns(), opt.db(), &table.0, opt.strict).await?;
|
||||
let exe = ctx.get_query_executor(&table.0);
|
||||
if let Some(exe) = exe {
|
||||
let mut iterator = plan.new_iterator(opt, &txn, exe).await?;
|
||||
let mut things = iterator.next_batch(&txn, 1000).await?;
|
||||
let mut iterator = plan.new_iterator(opt, txn, exe).await?;
|
||||
let mut things = iterator.next_batch(txn, 1000).await?;
|
||||
while !things.is_empty() {
|
||||
// Check if the context is finished
|
||||
if ctx.is_done() {
|
||||
|
@ -479,20 +512,17 @@ impl Iterable {
|
|||
let key = thing::new(opt.ns(), opt.db(), &table.0, &thing.id);
|
||||
let val = txn.lock().await.get(key.clone()).await?;
|
||||
let rid = Thing::from((key.tb, key.id));
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_thing(&rid);
|
||||
ctx.add_doc_id(doc_id);
|
||||
// Parse the data from the store
|
||||
let val = Operable::Value(match val {
|
||||
Some(v) => Value::from(v),
|
||||
None => Value::None,
|
||||
});
|
||||
// Process the document record
|
||||
ite.process(&ctx, opt, stm, val).await;
|
||||
self.process(ctx, opt, txn, stm, Some(rid), Some(doc_id), val).await?;
|
||||
}
|
||||
|
||||
// Collect the next batch of ids
|
||||
things = iterator.next_batch(&txn, 1000).await?;
|
||||
things = iterator.next_batch(txn, 1000).await?;
|
||||
}
|
||||
// Everything ok
|
||||
Ok(())
|
|
@ -1,15 +1,14 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::{Auth, Options};
|
||||
use crate::dbs::{Auth, Options, Transaction};
|
||||
use crate::kvs::Datastore;
|
||||
use futures::lock::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub async fn mock<'a>() -> (Context<'a>, Options) {
|
||||
let mut ctx = Context::default();
|
||||
pub async fn mock<'a>() -> (Context<'a>, Options, Transaction) {
|
||||
let ctx = Context::default();
|
||||
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
||||
let kvs = Datastore::new("memory").await.unwrap();
|
||||
let txn = kvs.transaction(true, false).await.unwrap();
|
||||
let txn = Arc::new(Mutex::new(txn));
|
||||
ctx.add_transaction(Some(&txn));
|
||||
(ctx, opt)
|
||||
(ctx, opt, txn)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::permission::Permission;
|
||||
|
@ -10,16 +10,15 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if this record exists
|
||||
if self.id.is_some() {
|
||||
// Should we run permissions checks?
|
||||
if opt.perms && opt.auth.perms() {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Get the table
|
||||
let tb = self.tb(opt, &txn).await?;
|
||||
let tb = self.tb(opt, txn).await?;
|
||||
// Get the permission clause
|
||||
let perms = if stm.is_delete() {
|
||||
&tb.permissions.delete
|
||||
|
@ -37,10 +36,8 @@ impl<'a> Document<'a> {
|
|||
Permission::Specific(e) => {
|
||||
// Disable permissions
|
||||
let opt = &opt.new_with_perms(false);
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Process the PERMISSION clause
|
||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
||||
if !e.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||
return Err(Error::Ignore);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Workable;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::data::Data;
|
||||
|
@ -13,57 +13,50 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Set default field values
|
||||
self.current.to_mut().def(rid);
|
||||
self.current.doc.to_mut().def(rid);
|
||||
// The statement has a data clause
|
||||
if let Some(v) = stm.data() {
|
||||
match v {
|
||||
Data::PatchExpression(data) => {
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let data = data.compute(¤t_ctx, opt).await?;
|
||||
self.current.to_mut().patch(data)?
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.doc.to_mut().patch(data)?
|
||||
}
|
||||
Data::MergeExpression(data) => {
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let data = data.compute(¤t_ctx, opt).await?;
|
||||
self.current.to_mut().merge(data)?
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.doc.to_mut().merge(data)?
|
||||
}
|
||||
Data::ReplaceExpression(data) => {
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let data = data.compute(¤t_ctx, opt).await?;
|
||||
self.current.to_mut().replace(data)?
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.doc.to_mut().replace(data)?
|
||||
}
|
||||
Data::ContentExpression(data) => {
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let data = data.compute(¤t_ctx, opt).await?;
|
||||
self.current.to_mut().replace(data)?
|
||||
let data = data.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.doc.to_mut().replace(data)?
|
||||
}
|
||||
Data::SetExpression(x) => {
|
||||
for x in x.iter() {
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let v = x.2.compute(¤t_ctx, opt).await?;
|
||||
let v = x.2.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
match x.1 {
|
||||
Operator::Equal => match v {
|
||||
Value::None => self.current.to_mut().del(ctx, opt, &x.0).await?,
|
||||
_ => self.current.to_mut().set(ctx, opt, &x.0, v).await?,
|
||||
Value::None => {
|
||||
self.current.doc.to_mut().del(ctx, opt, txn, &x.0).await?
|
||||
}
|
||||
_ => self.current.doc.to_mut().set(ctx, opt, txn, &x.0, v).await?,
|
||||
},
|
||||
Operator::Inc => {
|
||||
self.current.to_mut().increment(ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().increment(ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
Operator::Dec => {
|
||||
self.current.to_mut().decrement(ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().decrement(ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
Operator::Ext => {
|
||||
self.current.to_mut().extend(ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().extend(ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -71,7 +64,7 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
Data::UnsetExpression(i) => {
|
||||
for i in i.iter() {
|
||||
self.current.to_mut().del(ctx, opt, i).await?
|
||||
self.current.doc.to_mut().del(ctx, opt, txn, i).await?
|
||||
}
|
||||
}
|
||||
Data::UpdateExpression(x) => {
|
||||
|
@ -83,22 +76,22 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
// Process ON DUPLICATE KEY clause
|
||||
for x in x.iter() {
|
||||
let mut current_ctx = Context::new(&ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
let v = x.2.compute(¤t_ctx, opt).await?;
|
||||
let v = x.2.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||
match x.1 {
|
||||
Operator::Equal => match v {
|
||||
Value::None => self.current.to_mut().del(&ctx, opt, &x.0).await?,
|
||||
_ => self.current.to_mut().set(&ctx, opt, &x.0, v).await?,
|
||||
Value::None => {
|
||||
self.current.doc.to_mut().del(&ctx, opt, txn, &x.0).await?
|
||||
}
|
||||
_ => self.current.doc.to_mut().set(&ctx, opt, txn, &x.0, v).await?,
|
||||
},
|
||||
Operator::Inc => {
|
||||
self.current.to_mut().increment(&ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().increment(&ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
Operator::Dec => {
|
||||
self.current.to_mut().decrement(&ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().decrement(&ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
Operator::Ext => {
|
||||
self.current.to_mut().extend(&ctx, opt, &x.0, v).await?
|
||||
self.current.doc.to_mut().extend(&ctx, opt, txn, &x.0, v).await?
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -108,7 +101,7 @@ impl<'a> Document<'a> {
|
|||
};
|
||||
};
|
||||
// Set default field values
|
||||
self.current.to_mut().def(rid);
|
||||
self.current.doc.to_mut().def(rid);
|
||||
// Carry on
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
|
||||
|
@ -9,14 +9,13 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check where condition
|
||||
if let Some(cond) = stm.conds() {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Check if the expression is truthy
|
||||
if !cond.compute(&ctx, opt).await?.is_truthy() {
|
||||
if !cond.compute(ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||
// Ignore this document
|
||||
return Err(Error::Ignore);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
|
@ -10,43 +10,42 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Get the table
|
||||
let tb = self.tb(opt, &txn).await?;
|
||||
let tb = self.tb(opt, txn).await?;
|
||||
// This table is schemafull
|
||||
if tb.full {
|
||||
// Create a vector to store the keys
|
||||
let mut keys: Vec<Idiom> = vec![];
|
||||
// Loop through all field statements
|
||||
for fd in self.fd(opt, &txn).await?.iter() {
|
||||
for fd in self.fd(opt, txn).await?.iter() {
|
||||
// Is this a schemaless field?
|
||||
match fd.flex {
|
||||
false => {
|
||||
// Loop over this field in the document
|
||||
for k in self.current.each(&fd.name).into_iter() {
|
||||
for k in self.current.doc.each(&fd.name).into_iter() {
|
||||
keys.push(k);
|
||||
}
|
||||
}
|
||||
true => {
|
||||
// Loop over every field under this field in the document
|
||||
for k in self.current.every(Some(&fd.name), true, true).into_iter() {
|
||||
for k in self.current.doc.every(Some(&fd.name), true, true).into_iter() {
|
||||
keys.push(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Loop over every field in the document
|
||||
for fd in self.current.every(None, true, true).iter() {
|
||||
for fd in self.current.doc.every(None, true, true).iter() {
|
||||
if !keys.contains(fd) {
|
||||
match fd {
|
||||
fd if fd.is_id() => continue,
|
||||
fd if fd.is_in() => continue,
|
||||
fd if fd.is_out() => continue,
|
||||
fd if fd.is_meta() => continue,
|
||||
fd => self.current.to_mut().del(ctx, opt, fd).await?,
|
||||
fd => self.current.doc.to_mut().del(ctx, opt, txn, fd).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Operable;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Workable;
|
||||
use crate::dbs::{Operable, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use channel::Sender;
|
||||
|
||||
impl<'a> Document<'a> {
|
||||
#[allow(dead_code)]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) async fn compute(
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
chn: Sender<Result<Value, Error>>,
|
||||
thg: Option<Thing>,
|
||||
doc_id: Option<DocId>,
|
||||
val: Operable,
|
||||
) -> Result<(), Error> {
|
||||
let mut ctx = Context::new(ctx);
|
||||
if let Some(t) = &thg {
|
||||
ctx.add_thing(t);
|
||||
}
|
||||
// Setup a new workable
|
||||
let ins = match val {
|
||||
Operable::Value(v) => (v, Workable::Normal),
|
||||
|
@ -30,15 +30,15 @@ impl<'a> Document<'a> {
|
|||
Operable::Relatable(f, v, w) => (v, Workable::Relate(f, w)),
|
||||
};
|
||||
// Setup a new document
|
||||
let mut doc = Document::new(ctx.thing(), &ins.0, ins.1);
|
||||
let mut doc = Document::new(thg.as_ref(), doc_id, &ins.0, ins.1);
|
||||
// Process the statement
|
||||
let res = match stm {
|
||||
Statement::Select(_) => doc.select(&ctx, opt, stm).await,
|
||||
Statement::Create(_) => doc.create(&ctx, opt, stm).await,
|
||||
Statement::Update(_) => doc.update(&ctx, opt, stm).await,
|
||||
Statement::Relate(_) => doc.relate(&ctx, opt, stm).await,
|
||||
Statement::Delete(_) => doc.delete(&ctx, opt, stm).await,
|
||||
Statement::Insert(_) => doc.insert(&ctx, opt, stm).await,
|
||||
Statement::Select(_) => doc.select(ctx, opt, txn, stm).await,
|
||||
Statement::Create(_) => doc.create(ctx, opt, txn, stm).await,
|
||||
Statement::Update(_) => doc.update(ctx, opt, txn, stm).await,
|
||||
Statement::Relate(_) => doc.relate(ctx, opt, txn, stm).await,
|
||||
Statement::Delete(_) => doc.delete(ctx, opt, txn, stm).await,
|
||||
Statement::Insert(_) => doc.insert(ctx, opt, txn, stm).await,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// Send back the result
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,31 +10,32 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check if exists
|
||||
self.exist(ctx, opt, stm).await?;
|
||||
self.exist(ctx, opt, txn, stm).await?;
|
||||
// Alter record data
|
||||
self.alter(ctx, opt, stm).await?;
|
||||
self.alter(ctx, opt, txn, stm).await?;
|
||||
// Merge fields data
|
||||
self.field(ctx, opt, stm).await?;
|
||||
self.field(ctx, opt, txn, stm).await?;
|
||||
// Reset fields data
|
||||
self.reset(ctx, opt, stm).await?;
|
||||
self.reset(ctx, opt, txn, stm).await?;
|
||||
// Clean fields data
|
||||
self.clean(ctx, opt, stm).await?;
|
||||
self.clean(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Store index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Store record data
|
||||
self.store(ctx, opt, stm).await?;
|
||||
self.store(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,25 +10,26 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check where clause
|
||||
self.check(ctx, opt, stm).await?;
|
||||
self.check(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Erase document
|
||||
self.erase(ctx, opt, stm).await?;
|
||||
// Purge index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Purge record data
|
||||
self.purge(ctx, opt, stm).await?;
|
||||
self.purge(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::dbs::Options;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::dbs::Workable;
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::sql::statements::define::DefineEventStatement;
|
||||
use crate::sql::statements::define::DefineFieldStatement;
|
||||
use crate::sql::statements::define::DefineIndexStatement;
|
||||
|
@ -17,8 +18,24 @@ use std::sync::Arc;
|
|||
pub(crate) struct Document<'a> {
|
||||
pub(super) id: Option<&'a Thing>,
|
||||
pub(super) extras: Workable,
|
||||
pub(super) current: Cow<'a, Value>,
|
||||
pub(super) initial: Cow<'a, Value>,
|
||||
pub(super) initial: CursorDoc<'a>,
|
||||
pub(super) current: CursorDoc<'a>,
|
||||
}
|
||||
|
||||
pub struct CursorDoc<'a> {
|
||||
pub(crate) rid: Option<&'a Thing>,
|
||||
pub(crate) doc: Cow<'a, Value>,
|
||||
pub(crate) doc_id: Option<DocId>,
|
||||
}
|
||||
|
||||
impl<'a> CursorDoc<'a> {
|
||||
pub(crate) fn new(rid: Option<&'a Thing>, doc_id: Option<DocId>, doc: &'a Value) -> Self {
|
||||
Self {
|
||||
rid,
|
||||
doc: Cow::Borrowed(doc),
|
||||
doc_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for Document<'a> {
|
||||
|
@ -29,17 +46,22 @@ impl<'a> Debug for Document<'a> {
|
|||
|
||||
impl<'a> From<&Document<'a>> for Vec<u8> {
|
||||
fn from(val: &Document<'a>) -> Vec<u8> {
|
||||
val.current.as_ref().into()
|
||||
val.current.doc.as_ref().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Document<'a> {
|
||||
pub fn new(id: Option<&'a Thing>, val: &'a Value, ext: Workable) -> Self {
|
||||
pub fn new(
|
||||
id: Option<&'a Thing>,
|
||||
doc_id: Option<DocId>,
|
||||
val: &'a Value,
|
||||
extras: Workable,
|
||||
) -> Self {
|
||||
Document {
|
||||
id,
|
||||
extras: ext,
|
||||
current: Cow::Borrowed(val),
|
||||
initial: Cow::Borrowed(val),
|
||||
extras,
|
||||
current: CursorDoc::new(id, doc_id, val),
|
||||
initial: CursorDoc::new(id, doc_id, val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +69,11 @@ impl<'a> Document<'a> {
|
|||
impl<'a> Document<'a> {
|
||||
/// Check if document has changed
|
||||
pub fn changed(&self) -> bool {
|
||||
self.initial != self.current
|
||||
self.initial.doc != self.current.doc
|
||||
}
|
||||
/// Check if document has changed
|
||||
pub fn is_new(&self) -> bool {
|
||||
self.initial.is_none()
|
||||
self.initial.doc.is_none()
|
||||
}
|
||||
/// Get the table for this document
|
||||
pub async fn tb(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Workable;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::paths::EDGE;
|
||||
|
@ -13,14 +13,13 @@ use crate::sql::Dir;
|
|||
impl<'a> Document<'a> {
|
||||
pub async fn edges(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check if the table is a view
|
||||
if self.tb(opt, &txn).await?.drop {
|
||||
if self.tb(opt, txn).await?.drop {
|
||||
return Ok(());
|
||||
}
|
||||
// Claim transaction
|
||||
|
@ -44,9 +43,9 @@ impl<'a> Document<'a> {
|
|||
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
|
||||
run.set(key, vec![]).await?;
|
||||
// Store the edges on the record
|
||||
self.current.to_mut().put(&*EDGE, Value::Bool(true));
|
||||
self.current.to_mut().put(&*IN, l.clone().into());
|
||||
self.current.to_mut().put(&*OUT, r.clone().into());
|
||||
self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
|
||||
self.current.doc.to_mut().put(&*IN, l.clone().into());
|
||||
self.current.doc.to_mut().put(&*OUT, r.clone().into());
|
||||
}
|
||||
// Carry on
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
|
||||
|
@ -9,12 +10,13 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if this record exists
|
||||
if self.id.is_some() {
|
||||
// There is no current record
|
||||
if self.current.is_none() {
|
||||
if self.current.doc.is_none() {
|
||||
// Ignore this requested record
|
||||
return Err(Error::Ignore);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ impl<'a> Document<'a> {
|
|||
_opt: &Options,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
self.current.to_mut().clear()
|
||||
self.current.doc.to_mut().clear()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check events
|
||||
|
@ -23,10 +24,8 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
// Don't run permissions
|
||||
let opt = &opt.new_with_perms(false);
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Loop through all event statements
|
||||
for ev in self.ev(opt, &txn).await?.iter() {
|
||||
for ev in self.ev(opt, txn).await?.iter() {
|
||||
// Get the event action
|
||||
let met = if stm.is_delete() {
|
||||
Value::from("DELETE")
|
||||
|
@ -38,16 +37,15 @@ impl<'a> Document<'a> {
|
|||
// Configure the context
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_value("event", met);
|
||||
ctx.add_value("value", self.current.deref());
|
||||
ctx.add_value("after", self.current.deref());
|
||||
ctx.add_value("before", self.initial.deref());
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
ctx.add_value("value", self.current.doc.deref());
|
||||
ctx.add_value("after", self.current.doc.deref());
|
||||
ctx.add_value("before", self.initial.doc.deref());
|
||||
// Process conditional clause
|
||||
let val = ev.when.compute(&ctx, opt).await?;
|
||||
let val = ev.when.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||
// Execute event if value is truthy
|
||||
if val.is_truthy() {
|
||||
for v in ev.then.iter() {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
|
||||
|
@ -9,12 +9,13 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if this record exists
|
||||
if let Some(id) = &self.id {
|
||||
// If there is a current value
|
||||
if self.current.is_some() {
|
||||
if self.current.doc.is_some() {
|
||||
// The record already exists
|
||||
return Err(Error::RecordExists {
|
||||
thing: id.to_string(),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::permission::Permission;
|
||||
|
@ -11,6 +11,7 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check fields
|
||||
|
@ -20,15 +21,13 @@ impl<'a> Document<'a> {
|
|||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Get the user applied input
|
||||
let inp = self.initial.changed(self.current.as_ref());
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
let inp = self.initial.doc.changed(self.current.doc.as_ref());
|
||||
// Loop through all field statements
|
||||
for fd in self.fd(opt, &txn).await?.iter() {
|
||||
for fd in self.fd(opt, txn).await?.iter() {
|
||||
// Loop over each field in document
|
||||
for (k, mut val) in self.current.walk(&fd.name).into_iter() {
|
||||
for (k, mut val) in self.current.doc.walk(&fd.name).into_iter() {
|
||||
// Get the initial value
|
||||
let old = self.initial.pick(&k);
|
||||
let old = self.initial.doc.pick(&k);
|
||||
// Get the input value
|
||||
let inp = inp.pick(&k);
|
||||
// Check for a TYPE clause
|
||||
|
@ -58,9 +57,8 @@ impl<'a> Document<'a> {
|
|||
ctx.add_value("value", &val);
|
||||
ctx.add_value("after", &val);
|
||||
ctx.add_value("before", &old);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Process the VALUE clause
|
||||
val = expr.compute(&ctx, opt).await?;
|
||||
val = expr.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||
}
|
||||
// Check for a TYPE clause
|
||||
if let Some(kind) = &fd.kind {
|
||||
|
@ -87,9 +85,8 @@ impl<'a> Document<'a> {
|
|||
ctx.add_value("value", &val);
|
||||
ctx.add_value("after", &val);
|
||||
ctx.add_value("before", &old);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Process the ASSERT clause
|
||||
if !expr.compute(&ctx, opt).await?.is_truthy() {
|
||||
if !expr.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||
return Err(Error::FieldValue {
|
||||
thing: rid.to_string(),
|
||||
field: fd.name.clone(),
|
||||
|
@ -119,9 +116,8 @@ impl<'a> Document<'a> {
|
|||
ctx.add_value("value", &val);
|
||||
ctx.add_value("after", &val);
|
||||
ctx.add_value("before", &old);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Process the PERMISSION clause
|
||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
||||
if !e.compute(&ctx, opt, txn, Some(&self.current)).await?.is_truthy() {
|
||||
val = old
|
||||
}
|
||||
}
|
||||
|
@ -129,8 +125,8 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
// Set the value of the field
|
||||
match val {
|
||||
Value::None => self.current.to_mut().del(ctx, opt, &k).await?,
|
||||
_ => self.current.to_mut().set(ctx, opt, &k, val).await?,
|
||||
Value::None => self.current.doc.to_mut().del(ctx, opt, txn, &k).await?,
|
||||
_ => self.current.doc.to_mut().set(ctx, opt, txn, &k, val).await?,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::doc::Document;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::{CursorDoc, Document};
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::FtIndex;
|
||||
use crate::idx::IndexKeyBase;
|
||||
|
@ -9,7 +9,7 @@ use crate::sql::array::Array;
|
|||
use crate::sql::index::Index;
|
||||
use crate::sql::scoring::Scoring;
|
||||
use crate::sql::statements::DefineIndexStatement;
|
||||
use crate::sql::{Ident, Thing, Value};
|
||||
use crate::sql::{Ident, Thing};
|
||||
use crate::{key, kvs};
|
||||
|
||||
impl<'a> Document<'a> {
|
||||
|
@ -17,6 +17,7 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check indexes
|
||||
|
@ -27,21 +28,19 @@ impl<'a> Document<'a> {
|
|||
if !opt.force && !self.changed() {
|
||||
return Ok(());
|
||||
}
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check if the table is a view
|
||||
if self.tb(opt, &txn).await?.drop {
|
||||
if self.tb(opt, txn).await?.drop {
|
||||
return Ok(());
|
||||
}
|
||||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Loop through all index statements
|
||||
for ix in self.ix(opt, &txn).await?.iter() {
|
||||
for ix in self.ix(opt, txn).await?.iter() {
|
||||
// Calculate old values
|
||||
let o = Self::build_opt_array(ctx, opt, ix, &self.initial).await?;
|
||||
let o = Self::build_opt_array(ctx, opt, txn, ix, &self.initial).await?;
|
||||
|
||||
// Calculate new values
|
||||
let n = Self::build_opt_array(ctx, opt, ix, &self.current).await?;
|
||||
let n = Self::build_opt_array(ctx, opt, txn, ix, &self.current).await?;
|
||||
|
||||
// Update the index entries
|
||||
if opt.force || o != n {
|
||||
|
@ -75,17 +74,16 @@ impl<'a> Document<'a> {
|
|||
async fn build_opt_array(
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
ix: &DefineIndexStatement,
|
||||
value: &Value,
|
||||
doc: &CursorDoc<'_>,
|
||||
) -> Result<Option<Array>, Error> {
|
||||
if !value.is_some() {
|
||||
if !doc.doc.is_some() {
|
||||
return Ok(None);
|
||||
}
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(value);
|
||||
let mut o = Array::with_capacity(ix.cols.len());
|
||||
for i in ix.cols.iter() {
|
||||
let v = i.compute(&ctx, opt).await?;
|
||||
let v = i.compute(ctx, opt, txn, Some(doc)).await?;
|
||||
o.push(v);
|
||||
}
|
||||
Ok(Some(o))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,63 +10,64 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check current record
|
||||
match self.current.is_some() {
|
||||
match self.current.doc.is_some() {
|
||||
// Run INSERT clause
|
||||
false => {
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Merge record data
|
||||
self.merge(ctx, opt, stm).await?;
|
||||
self.merge(ctx, opt, txn, stm).await?;
|
||||
// Merge fields data
|
||||
self.field(ctx, opt, stm).await?;
|
||||
self.field(ctx, opt, txn, stm).await?;
|
||||
// Reset fields data
|
||||
self.reset(ctx, opt, stm).await?;
|
||||
self.reset(ctx, opt, txn, stm).await?;
|
||||
// Clean fields data
|
||||
self.clean(ctx, opt, stm).await?;
|
||||
self.clean(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Store index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Store record data
|
||||
self.store(ctx, opt, stm).await?;
|
||||
self.store(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
// Run UPDATE clause
|
||||
true => {
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Alter record data
|
||||
self.alter(ctx, opt, stm).await?;
|
||||
self.alter(ctx, opt, txn, stm).await?;
|
||||
// Merge fields data
|
||||
self.field(ctx, opt, stm).await?;
|
||||
self.field(ctx, opt, txn, stm).await?;
|
||||
// Reset fields data
|
||||
self.reset(ctx, opt, stm).await?;
|
||||
self.reset(ctx, opt, txn, stm).await?;
|
||||
// Clean fields data
|
||||
self.clean(ctx, opt, stm).await?;
|
||||
self.clean(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Store index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Store record data
|
||||
self.store(ctx, opt, stm).await?;
|
||||
self.store(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Action;
|
||||
use crate::dbs::Notification;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Action, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::Value;
|
||||
|
@ -12,14 +12,13 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if forced
|
||||
if !opt.force && !self.changed() {
|
||||
return Ok(());
|
||||
}
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Check if we can send notifications
|
||||
|
@ -27,11 +26,11 @@ impl<'a> Document<'a> {
|
|||
// Clone the sending channel
|
||||
let chn = chn.clone();
|
||||
// Loop through all index statements
|
||||
for lv in self.lv(opt, &txn).await?.iter() {
|
||||
for lv in self.lv(opt, txn).await?.iter() {
|
||||
// Create a new statement
|
||||
let lq = Statement::from(lv);
|
||||
// Check LIVE SELECT where condition
|
||||
if self.check(ctx, opt, &lq).await.is_err() {
|
||||
if self.check(ctx, opt, txn, &lq).await.is_err() {
|
||||
continue;
|
||||
}
|
||||
// Check what type of data change this is
|
||||
|
@ -54,7 +53,7 @@ impl<'a> Document<'a> {
|
|||
chn.send(Notification {
|
||||
id: lv.id.0,
|
||||
action: Action::Create,
|
||||
result: self.pluck(ctx, opt, &lq).await?,
|
||||
result: self.pluck(ctx, opt, txn, &lq).await?,
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
|
@ -66,7 +65,7 @@ impl<'a> Document<'a> {
|
|||
chn.send(Notification {
|
||||
id: lv.id.0,
|
||||
action: Action::Update,
|
||||
result: self.pluck(ctx, opt, &lq).await?,
|
||||
result: self.pluck(ctx, opt, txn, &lq).await?,
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Workable;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
|
||||
|
@ -10,21 +10,20 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Set default field values
|
||||
self.current.to_mut().def(rid);
|
||||
self.current.doc.to_mut().def(rid);
|
||||
// This is an INSERT statement
|
||||
if let Workable::Insert(v) = &self.extras {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
let v = v.compute(&ctx, opt).await?;
|
||||
self.current.to_mut().merge(v)?;
|
||||
let v = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
self.current.doc.to_mut().merge(v)?;
|
||||
}
|
||||
// Set default field values
|
||||
self.current.to_mut().def(rid);
|
||||
self.current.doc.to_mut().def(rid);
|
||||
// Carry on
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::idiom::Idiom;
|
||||
|
@ -14,6 +14,7 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Ensure futures are run
|
||||
|
@ -23,56 +24,34 @@ impl<'a> Document<'a> {
|
|||
Some(v) => match v {
|
||||
Output::None => Err(Error::Ignore),
|
||||
Output::Null => Ok(Value::Null),
|
||||
Output::Diff => Ok(self.initial.diff(&self.current, Idiom::default()).into()),
|
||||
Output::After => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
self.current.compute(&ctx, opt).await
|
||||
Output::Diff => {
|
||||
Ok(self.initial.doc.diff(self.current.doc.as_ref(), Idiom::default()).into())
|
||||
}
|
||||
Output::After => self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await,
|
||||
Output::Before => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.initial);
|
||||
self.initial.compute(&ctx, opt).await
|
||||
}
|
||||
Output::Fields(v) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
v.compute(&ctx, opt, false).await
|
||||
self.initial.doc.compute(ctx, opt, txn, Some(&self.initial)).await
|
||||
}
|
||||
Output::Fields(v) => v.compute(ctx, opt, txn, Some(&self.current), false).await,
|
||||
},
|
||||
None => match stm {
|
||||
Statement::Live(s) => match s.expr.len() {
|
||||
0 => Ok(self.initial.diff(&self.current, Idiom::default()).into()),
|
||||
_ => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
s.expr.compute(&ctx, opt, false).await
|
||||
}
|
||||
0 => Ok(self.initial.doc.diff(&self.current.doc, Idiom::default()).into()),
|
||||
_ => s.expr.compute(ctx, opt, txn, Some(&self.current), false).await,
|
||||
},
|
||||
Statement::Select(s) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
s.expr.compute(&ctx, opt, s.group.is_some()).await
|
||||
s.expr.compute(ctx, opt, txn, Some(&self.current), s.group.is_some()).await
|
||||
}
|
||||
Statement::Create(_) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
self.current.compute(&ctx, opt).await
|
||||
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||
}
|
||||
Statement::Update(_) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
self.current.compute(&ctx, opt).await
|
||||
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||
}
|
||||
Statement::Relate(_) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
self.current.compute(&ctx, opt).await
|
||||
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||
}
|
||||
Statement::Insert(_) => {
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
self.current.compute(&ctx, opt).await
|
||||
self.current.doc.compute(ctx, opt, txn, Some(&self.current)).await
|
||||
}
|
||||
_ => Err(Error::Ignore),
|
||||
},
|
||||
|
@ -81,28 +60,29 @@ impl<'a> Document<'a> {
|
|||
if self.id.is_some() {
|
||||
// Should we run permissions checks?
|
||||
if opt.perms && opt.auth.perms() {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Loop through all field statements
|
||||
for fd in self.fd(opt, &txn).await?.iter() {
|
||||
for fd in self.fd(opt, txn).await?.iter() {
|
||||
// Loop over each field in document
|
||||
for k in out.each(&fd.name).iter() {
|
||||
// Process the field permissions
|
||||
match &fd.permissions.select {
|
||||
Permission::Full => (),
|
||||
Permission::None => out.del(ctx, opt, k).await?,
|
||||
Permission::None => out.del(ctx, opt, txn, k).await?,
|
||||
Permission::Specific(e) => {
|
||||
// Disable permissions
|
||||
let opt = &opt.new_with_perms(false);
|
||||
// Get the current value
|
||||
let val = self.current.pick(k);
|
||||
let val = self.current.doc.pick(k);
|
||||
// Configure the context
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_value("value", &val);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Process the PERMISSION clause
|
||||
if !e.compute(&ctx, opt).await?.is_truthy() {
|
||||
out.del(&ctx, opt, k).await?
|
||||
if !e
|
||||
.compute(&ctx, opt, txn, Some(&self.current))
|
||||
.await?
|
||||
.is_truthy()
|
||||
{
|
||||
out.del(&ctx, opt, txn, k).await?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +91,7 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
}
|
||||
// Remove metadata fields on output
|
||||
out.del(ctx, opt, &*META).await?;
|
||||
out.del(ctx, opt, txn, &*META).await?;
|
||||
// Output result
|
||||
Ok(out)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::dir::Dir;
|
||||
|
@ -17,16 +17,15 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if forced
|
||||
if !opt.force && !self.changed() {
|
||||
return Ok(());
|
||||
}
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check if the table is a view
|
||||
if self.tb(opt, &txn).await?.drop {
|
||||
if self.tb(opt, txn).await?.drop {
|
||||
return Ok(());
|
||||
}
|
||||
// Clone transaction
|
||||
|
@ -39,7 +38,11 @@ impl<'a> Document<'a> {
|
|||
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
|
||||
run.del(key).await?;
|
||||
// Purge the record edges
|
||||
match (self.initial.pick(&*EDGE), self.initial.pick(&*IN), self.initial.pick(&*OUT)) {
|
||||
match (
|
||||
self.initial.doc.pick(&*EDGE),
|
||||
self.initial.doc.pick(&*IN),
|
||||
self.initial.doc.pick(&*OUT),
|
||||
) {
|
||||
(Value::Bool(true), Value::Thing(ref l), Value::Thing(ref r)) => {
|
||||
// Get temporary edge references
|
||||
let (ref o, ref i) = (Dir::Out, Dir::In);
|
||||
|
@ -69,7 +72,7 @@ impl<'a> Document<'a> {
|
|||
..DeleteStatement::default()
|
||||
};
|
||||
// Execute the delete statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Alter record data
|
||||
self.alter(ctx, opt, stm).await?;
|
||||
self.alter(ctx, opt, txn, stm).await?;
|
||||
// Merge fields data
|
||||
self.field(ctx, opt, stm).await?;
|
||||
self.field(ctx, opt, txn, stm).await?;
|
||||
// Reset fields data
|
||||
self.reset(ctx, opt, stm).await?;
|
||||
self.reset(ctx, opt, txn, stm).await?;
|
||||
// Clean fields data
|
||||
self.clean(ctx, opt, stm).await?;
|
||||
self.clean(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Store record edges
|
||||
self.edges(ctx, opt, stm).await?;
|
||||
self.edges(ctx, opt, txn, stm).await?;
|
||||
// Store index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Store record data
|
||||
self.store(ctx, opt, stm).await?;
|
||||
self.store(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::paths::EDGE;
|
||||
|
@ -13,17 +14,18 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Get the record id
|
||||
let rid = self.id.as_ref().unwrap();
|
||||
// Set default field values
|
||||
self.current.to_mut().def(rid);
|
||||
self.current.doc.to_mut().def(rid);
|
||||
// Ensure edge fields are reset
|
||||
if self.initial.pick(&*EDGE).is_true() {
|
||||
self.current.to_mut().put(&*EDGE, Value::Bool(true));
|
||||
self.current.to_mut().put(&*IN, self.initial.pick(&*IN));
|
||||
self.current.to_mut().put(&*OUT, self.initial.pick(&*OUT));
|
||||
if self.initial.doc.pick(&*EDGE).is_true() {
|
||||
self.current.doc.to_mut().put(&*EDGE, Value::Bool(true));
|
||||
self.current.doc.to_mut().put(&*IN, self.initial.doc.pick(&*IN));
|
||||
self.current.doc.to_mut().put(&*OUT, self.initial.doc.pick(&*OUT));
|
||||
}
|
||||
// Carry on
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,15 +10,16 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check if record exists
|
||||
self.empty(ctx, opt, stm).await?;
|
||||
self.empty(ctx, opt, txn, stm).await?;
|
||||
// Check where clause
|
||||
self.check(ctx, opt, stm).await?;
|
||||
self.check(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
|
||||
impl<'a> Document<'a> {
|
||||
pub async fn store(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check if forced
|
||||
if !opt.force && !self.changed() {
|
||||
return Ok(());
|
||||
}
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check if the table is a view
|
||||
if self.tb(opt, &txn).await?.drop {
|
||||
if self.tb(opt, txn).await?.drop {
|
||||
return Ok(());
|
||||
}
|
||||
// Claim transaction
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::data::Data;
|
||||
|
@ -33,6 +33,7 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<(), Error> {
|
||||
// Check tables
|
||||
|
@ -55,43 +56,41 @@ impl<'a> Document<'a> {
|
|||
} else {
|
||||
Action::Update
|
||||
};
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Loop through all foreign table statements
|
||||
for ft in self.ft(opt, &txn).await?.iter() {
|
||||
for ft in self.ft(opt, txn).await?.iter() {
|
||||
// Get the table definition
|
||||
let tb = ft.view.as_ref().unwrap();
|
||||
// Check if there is a GROUP BY clause
|
||||
match &tb.group {
|
||||
// There is a GROUP BY clause specified
|
||||
Some(group) => {
|
||||
let mut initial_ctx = Context::new(ctx);
|
||||
initial_ctx.add_cursor_doc(&self.initial);
|
||||
// Set the previous record id
|
||||
let old = Thing {
|
||||
tb: ft.name.to_raw(),
|
||||
id: try_join_all(group.iter().map(|v| v.compute(&initial_ctx, opt)))
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
id: try_join_all(
|
||||
group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.initial))),
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
};
|
||||
let mut current_ctx = Context::new(ctx);
|
||||
current_ctx.add_cursor_doc(&self.current);
|
||||
// Set the current record id
|
||||
let rid = Thing {
|
||||
tb: ft.name.to_raw(),
|
||||
id: try_join_all(group.iter().map(|v| v.compute(¤t_ctx, opt)))
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
id: try_join_all(
|
||||
group.iter().map(|v| v.compute(ctx, opt, txn, Some(&self.current))),
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
};
|
||||
// Check if a WHERE clause is specified
|
||||
match &tb.cond {
|
||||
// There is a WHERE clause specified
|
||||
Some(cond) => {
|
||||
match cond.compute(¤t_ctx, opt).await? {
|
||||
match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
|
||||
v if v.is_truthy() => {
|
||||
if !opt.force && act != Action::Create {
|
||||
// Delete the old value
|
||||
|
@ -99,11 +98,13 @@ impl<'a> Document<'a> {
|
|||
// Modify the value in the table
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::from(old)]),
|
||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
||||
data: Some(
|
||||
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||
),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
if act != Action::Delete {
|
||||
// Update the new value
|
||||
|
@ -111,11 +112,13 @@ impl<'a> Document<'a> {
|
|||
// Modify the value in the table
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::from(rid)]),
|
||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
||||
data: Some(
|
||||
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||
),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -125,11 +128,13 @@ impl<'a> Document<'a> {
|
|||
// Modify the value in the table
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::from(old)]),
|
||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
||||
data: Some(
|
||||
self.data(ctx, opt, txn, act, &tb.expr).await?,
|
||||
),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,11 +147,11 @@ impl<'a> Document<'a> {
|
|||
// Modify the value in the table
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::from(old)]),
|
||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
||||
data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
if act != Action::Delete {
|
||||
// Update the new value
|
||||
|
@ -154,11 +159,11 @@ impl<'a> Document<'a> {
|
|||
// Modify the value in the table
|
||||
let stm = UpdateStatement {
|
||||
what: Values(vec![Value::from(rid)]),
|
||||
data: Some(self.data(ctx, opt, act, &tb.expr).await?),
|
||||
data: Some(self.data(ctx, opt, txn, act, &tb.expr).await?),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,13 +176,11 @@ impl<'a> Document<'a> {
|
|||
id: rid.id.clone(),
|
||||
};
|
||||
// Use the current record data
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(&self.current);
|
||||
// Check if a WHERE clause is specified
|
||||
match &tb.cond {
|
||||
// There is a WHERE clause specified
|
||||
Some(cond) => {
|
||||
match cond.compute(&ctx, opt).await? {
|
||||
match cond.compute(ctx, opt, txn, Some(&self.current)).await? {
|
||||
v if v.is_truthy() => {
|
||||
// Define the statement
|
||||
let stm = match act {
|
||||
|
@ -190,13 +193,21 @@ impl<'a> Document<'a> {
|
|||
_ => Query::Update(UpdateStatement {
|
||||
what: Values(vec![Value::from(rid)]),
|
||||
data: Some(Data::ReplaceExpression(
|
||||
tb.expr.compute(&ctx, opt, false).await?,
|
||||
tb.expr
|
||||
.compute(
|
||||
ctx,
|
||||
opt,
|
||||
txn,
|
||||
Some(&self.current),
|
||||
false,
|
||||
)
|
||||
.await?,
|
||||
)),
|
||||
..UpdateStatement::default()
|
||||
}),
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(&ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
_ => {
|
||||
// Delete the value in the table
|
||||
|
@ -205,7 +216,7 @@ impl<'a> Document<'a> {
|
|||
..DeleteStatement::default()
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(&ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,13 +233,15 @@ impl<'a> Document<'a> {
|
|||
_ => Query::Update(UpdateStatement {
|
||||
what: Values(vec![Value::from(rid)]),
|
||||
data: Some(Data::ReplaceExpression(
|
||||
tb.expr.compute(&ctx, opt, false).await?,
|
||||
tb.expr
|
||||
.compute(ctx, opt, txn, Some(&self.current), false)
|
||||
.await?,
|
||||
)),
|
||||
..UpdateStatement::default()
|
||||
}),
|
||||
};
|
||||
// Execute the statement
|
||||
stm.compute(&ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, None).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,16 +255,16 @@ impl<'a> Document<'a> {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
act: Action,
|
||||
exp: &Fields,
|
||||
) -> Result<Data, Error> {
|
||||
//
|
||||
let mut ops: Ops = vec![];
|
||||
// Create a new context with the initial or the current doc
|
||||
let mut ctx = Context::new(ctx);
|
||||
match act {
|
||||
Action::Delete => ctx.add_cursor_doc(self.initial.as_ref()),
|
||||
Action::Update => ctx.add_cursor_doc(self.current.as_ref()),
|
||||
let doc = match act {
|
||||
Action::Delete => Some(&self.initial),
|
||||
Action::Update => Some(&self.current),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
//
|
||||
|
@ -266,29 +279,29 @@ impl<'a> Document<'a> {
|
|||
match expr {
|
||||
Value::Function(f) if f.is_rolling() => match f.name() {
|
||||
"count" => {
|
||||
let val = f.compute(&ctx, opt).await?;
|
||||
let val = f.compute(ctx, opt, txn, doc).await?;
|
||||
self.chg(&mut ops, &act, idiom, val);
|
||||
}
|
||||
"math::sum" => {
|
||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
||||
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||
self.chg(&mut ops, &act, idiom, val);
|
||||
}
|
||||
"math::min" => {
|
||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
||||
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||
self.min(&mut ops, &act, idiom, val);
|
||||
}
|
||||
"math::max" => {
|
||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
||||
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||
self.max(&mut ops, &act, idiom, val);
|
||||
}
|
||||
"math::mean" => {
|
||||
let val = f.args()[0].compute(&ctx, opt).await?;
|
||||
let val = f.args()[0].compute(ctx, opt, txn, doc).await?;
|
||||
self.mean(&mut ops, &act, idiom, val);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => {
|
||||
let val = expr.compute(&ctx, opt).await?;
|
||||
let val = expr.compute(ctx, opt, txn, doc).await?;
|
||||
self.set(&mut ops, idiom, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -10,33 +10,34 @@ impl<'a> Document<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
stm: &Statement<'_>,
|
||||
) -> Result<Value, Error> {
|
||||
// Check where clause
|
||||
self.check(ctx, opt, stm).await?;
|
||||
self.check(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Alter record data
|
||||
self.alter(ctx, opt, stm).await?;
|
||||
self.alter(ctx, opt, txn, stm).await?;
|
||||
// Merge fields data
|
||||
self.field(ctx, opt, stm).await?;
|
||||
self.field(ctx, opt, txn, stm).await?;
|
||||
// Reset fields data
|
||||
self.reset(ctx, opt, stm).await?;
|
||||
self.reset(ctx, opt, txn, stm).await?;
|
||||
// Clean fields data
|
||||
self.clean(ctx, opt, stm).await?;
|
||||
self.clean(ctx, opt, txn, stm).await?;
|
||||
// Check if allowed
|
||||
self.allow(ctx, opt, stm).await?;
|
||||
self.allow(ctx, opt, txn, stm).await?;
|
||||
// Store index data
|
||||
self.index(ctx, opt, stm).await?;
|
||||
self.index(ctx, opt, txn, stm).await?;
|
||||
// Store record data
|
||||
self.store(ctx, opt, stm).await?;
|
||||
self.store(ctx, opt, txn, stm).await?;
|
||||
// Run table queries
|
||||
self.table(ctx, opt, stm).await?;
|
||||
self.table(ctx, opt, txn, stm).await?;
|
||||
// Run lives queries
|
||||
self.lives(ctx, opt, stm).await?;
|
||||
self.lives(ctx, opt, txn, stm).await?;
|
||||
// Run event queries
|
||||
self.event(ctx, opt, stm).await?;
|
||||
self.event(ctx, opt, txn, stm).await?;
|
||||
// Yield document
|
||||
self.pluck(ctx, opt, stm).await
|
||||
self.pluck(ctx, opt, txn, stm).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Executes functions from SQL. If there is an SQL function it will be defined in this module.
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
|
@ -29,7 +31,13 @@ pub mod r#type;
|
|||
pub mod util;
|
||||
|
||||
/// Attempts to run any function
|
||||
pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn run(
|
||||
ctx: &Context<'_>,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
name: &str,
|
||||
args: Vec<Value>,
|
||||
) -> Result<Value, Error> {
|
||||
if name.eq("sleep")
|
||||
|| name.starts_with("search")
|
||||
|| name.starts_with("http")
|
||||
|
@ -38,7 +46,7 @@ pub async fn run(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Valu
|
|||
|| name.starts_with("crypto::pbkdf2")
|
||||
|| name.starts_with("crypto::scrypt")
|
||||
{
|
||||
asynchronous(ctx, name, args).await
|
||||
asynchronous(ctx, Some(txn), doc, name, args).await
|
||||
} else {
|
||||
synchronous(ctx, name, args)
|
||||
}
|
||||
|
@ -266,7 +274,13 @@ pub fn synchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Va
|
|||
}
|
||||
|
||||
/// Attempts to run any asynchronous function.
|
||||
pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Result<Value, Error> {
|
||||
pub async fn asynchronous(
|
||||
ctx: &Context<'_>,
|
||||
txn: Option<&Transaction>,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
name: &str,
|
||||
args: Vec<Value>,
|
||||
) -> Result<Value, Error> {
|
||||
// Wrappers return a function as opposed to a value so that the dispatch! method can always
|
||||
// perform a function call.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
@ -302,9 +316,9 @@ pub async fn asynchronous(ctx: &Context<'_>, name: &str, args: Vec<Value>) -> Re
|
|||
"http::patch" => http::patch(ctx).await,
|
||||
"http::delete" => http::delete(ctx).await,
|
||||
//
|
||||
"search::score" => search::score(ctx).await,
|
||||
"search::highlight" => search::highlight(ctx).await,
|
||||
"search::offsets" => search::offsets(ctx).await,
|
||||
"search::score" => search::score((ctx, txn, doc)).await,
|
||||
"search::highlight" => search::highlight((ctx,txn, doc)).await,
|
||||
"search::offsets" => search::offsets((ctx, txn, doc)).await,
|
||||
//
|
||||
"sleep" => sleep::sleep(ctx).await,
|
||||
)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::TryAdd;
|
||||
use crate::sql::value::TryDiv;
|
||||
|
@ -165,13 +167,18 @@ pub fn intersects(a: &Value, b: &Value) -> Result<Value, Error> {
|
|||
Ok(a.intersects(b).into())
|
||||
}
|
||||
|
||||
pub(crate) async fn matches(ctx: &Context<'_>, e: &Expression) -> Result<Value, Error> {
|
||||
if let Some(thg) = ctx.thing() {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Check the matches
|
||||
return exe.matches(&txn, thg, e).await;
|
||||
pub(crate) async fn matches(
|
||||
ctx: &Context<'_>,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
e: &Expression,
|
||||
) -> Result<Value, Error> {
|
||||
if let Some(doc) = doc {
|
||||
if let Some(thg) = doc.rid {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
// Check the matches
|
||||
return exe.matches(txn, thg, e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::Bool(false))
|
||||
|
|
|
@ -5,7 +5,8 @@ use super::modules;
|
|||
use super::modules::loader;
|
||||
use super::modules::resolver;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::value::Value;
|
||||
use js::async_with;
|
||||
|
@ -19,6 +20,8 @@ use js::Module;
|
|||
pub async fn run(
|
||||
ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
src: &str,
|
||||
arg: Vec<Value>,
|
||||
) -> Result<Value, Error> {
|
||||
|
@ -26,8 +29,6 @@ pub async fn run(
|
|||
if ctx.is_done() {
|
||||
return Ok(Value::None);
|
||||
}
|
||||
// Get the optional doc
|
||||
let doc = ctx.doc();
|
||||
// Create an JavaScript context
|
||||
let run = js::AsyncRuntime::new().unwrap();
|
||||
// Explicitly set max stack size to 256 KiB
|
||||
|
@ -68,6 +69,8 @@ pub async fn run(
|
|||
let res = ctx.compile("script", src)?;
|
||||
// Attempt to fetch the main export
|
||||
let fnc = res.get::<_, Function>("default")?;
|
||||
// Extract the doc if any
|
||||
let doc = doc.map(|v|v.doc.as_ref());
|
||||
// Execute the main function
|
||||
let promise: Promise<Value> = fnc.call((This(doc), Rest(arg)))?;
|
||||
promise.await
|
||||
|
|
|
@ -68,7 +68,7 @@ async fn fut(js_ctx: js::Ctx<'_>, name: &str, args: Vec<Value>) -> Result<Value>
|
|||
// Create a default context
|
||||
let ctx = Context::background();
|
||||
// Process the called function
|
||||
let res = fnc::asynchronous(&ctx, name, args).await;
|
||||
let res = fnc::asynchronous(&ctx, None, None, name, args).await;
|
||||
// Convert any response error
|
||||
res.map_err(|err| {
|
||||
js::Exception::from_message(js_ctx, &err.to_string())
|
||||
|
|
|
@ -1,37 +1,54 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::Value;
|
||||
|
||||
pub async fn score(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> {
|
||||
if let Some(thg) = ctx.thing() {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
return exe.score(txn, &match_ref, thg, ctx.doc_id()).await;
|
||||
}
|
||||
}
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
||||
pub async fn highlight(
|
||||
ctx: &Context<'_>,
|
||||
(prefix, suffix, match_ref): (Value, Value, Value),
|
||||
pub async fn score(
|
||||
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||
(match_ref,): (Value,),
|
||||
) -> Result<Value, Error> {
|
||||
if let Some(doc) = ctx.doc() {
|
||||
if let Some(thg) = ctx.thing() {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
return exe.highlight(txn, thg, prefix, suffix, &match_ref, doc).await;
|
||||
if let Some(txn) = txn {
|
||||
if let Some(doc) = doc {
|
||||
if let Some(thg) = doc.rid {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
return exe.score(txn, &match_ref, thg, doc.doc_id).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
||||
pub async fn offsets(ctx: &Context<'_>, (match_ref,): (Value,)) -> Result<Value, Error> {
|
||||
if let Some(thg) = ctx.thing() {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
return exe.offsets(txn, thg, &match_ref).await;
|
||||
pub async fn highlight(
|
||||
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||
(prefix, suffix, match_ref): (Value, Value, Value),
|
||||
) -> Result<Value, Error> {
|
||||
if let Some(txn) = txn {
|
||||
if let Some(doc) = doc {
|
||||
if let Some(thg) = doc.rid {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
return exe
|
||||
.highlight(txn, thg, prefix, suffix, &match_ref, doc.doc.as_ref())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
||||
pub async fn offsets(
|
||||
(ctx, txn, doc): (&Context<'_>, Option<&Transaction>, Option<&CursorDoc<'_>>),
|
||||
(match_ref,): (Value,),
|
||||
) -> Result<Value, Error> {
|
||||
if let Some(txn) = txn {
|
||||
if let Some(doc) = doc {
|
||||
if let Some(thg) = doc.rid {
|
||||
if let Some(exe) = ctx.get_query_executor(&thg.tb) {
|
||||
return exe.offsets(txn, thg, &match_ref).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::None)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::btree::Payload;
|
||||
use crate::kvs::Key;
|
||||
use async_trait::async_trait;
|
||||
use fst::{IntoStreamer, Map, MapBuilder, Streamer};
|
||||
use radix_trie::{SubTrie, Trie, TrieCommon};
|
||||
use serde::{de, ser, Deserialize, Serialize};
|
||||
|
@ -361,7 +360,6 @@ impl Display for TrieKeys {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BKeys for TrieKeys {
|
||||
fn with_key_val(key: Key, payload: Payload) -> Result<Self, Error> {
|
||||
let mut trie_keys = Self {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::bkeys::BKeys;
|
||||
use crate::idx::SerdeState;
|
||||
use crate::idx::{IndexKeyBase, SerdeState};
|
||||
use crate::kvs::{Key, Transaction};
|
||||
use crate::sql::{Object, Value};
|
||||
use async_trait::async_trait;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::VecDeque;
|
||||
|
@ -12,13 +11,39 @@ use std::fmt::Debug;
|
|||
pub(crate) type NodeId = u64;
|
||||
pub(super) type Payload = u64;
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
pub(super) trait KeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key;
|
||||
fn get_state_key(&self) -> Key {
|
||||
panic!("Not supported")
|
||||
#[derive(Clone)]
|
||||
pub(super) enum KeyProvider {
|
||||
DocIds(IndexKeyBase),
|
||||
DocLengths(IndexKeyBase),
|
||||
Postings(IndexKeyBase),
|
||||
Terms(IndexKeyBase),
|
||||
#[cfg(test)]
|
||||
Debug,
|
||||
}
|
||||
|
||||
impl KeyProvider {
|
||||
pub(super) fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
match self {
|
||||
KeyProvider::DocIds(ikb) => ikb.new_bd_key(Some(node_id)),
|
||||
KeyProvider::DocLengths(ikb) => ikb.new_bl_key(Some(node_id)),
|
||||
KeyProvider::Postings(ikb) => ikb.new_bp_key(Some(node_id)),
|
||||
KeyProvider::Terms(ikb) => ikb.new_bt_key(Some(node_id)),
|
||||
#[cfg(test)]
|
||||
KeyProvider::Debug => node_id.to_be_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_state_key(&self) -> Key {
|
||||
match self {
|
||||
KeyProvider::DocIds(ikb) => ikb.new_bd_key(None),
|
||||
KeyProvider::DocLengths(ikb) => ikb.new_bl_key(None),
|
||||
KeyProvider::Postings(ikb) => ikb.new_bp_key(None),
|
||||
KeyProvider::Terms(ikb) => ikb.new_bt_key(None),
|
||||
#[cfg(test)]
|
||||
KeyProvider::Debug => "".into(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn load_node<BK>(&self, tx: &mut Transaction, id: NodeId) -> Result<StoredNode<BK>, Error>
|
||||
where
|
||||
BK: BKeys + Serialize + DeserializeOwned,
|
||||
|
@ -34,11 +59,8 @@ pub(super) trait KeyProvider {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct BTree<K>
|
||||
where
|
||||
K: KeyProvider + Clone,
|
||||
{
|
||||
keys: K,
|
||||
pub(super) struct BTree {
|
||||
keys: KeyProvider,
|
||||
state: State,
|
||||
full_size: u32,
|
||||
updated: bool,
|
||||
|
@ -164,11 +186,8 @@ where
|
|||
median_key: Key,
|
||||
}
|
||||
|
||||
impl<K> BTree<K>
|
||||
where
|
||||
K: KeyProvider + Clone + Sync,
|
||||
{
|
||||
pub(super) fn new(keys: K, state: State) -> Self {
|
||||
impl BTree {
|
||||
pub(super) fn new(keys: KeyProvider, state: State) -> Self {
|
||||
Self {
|
||||
keys,
|
||||
full_size: state.minimum_degree * 2 - 1,
|
||||
|
@ -730,18 +749,6 @@ mod tests {
|
|||
use std::collections::{HashMap, VecDeque};
|
||||
use test_log::test;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TestKeyProvider {}
|
||||
|
||||
impl KeyProvider for TestKeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
node_id.to_be_bytes().to_vec()
|
||||
}
|
||||
fn get_state_key(&self) -> Key {
|
||||
"".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_btree_state_serde() {
|
||||
let s = State::new(3);
|
||||
|
@ -766,15 +773,14 @@ mod tests {
|
|||
let _: Node<TrieKeys> = Node::try_from_val(val).unwrap();
|
||||
}
|
||||
|
||||
async fn insertions_test<F, BK, K>(
|
||||
async fn insertions_test<F, BK>(
|
||||
tx: &mut Transaction,
|
||||
t: &mut BTree<K>,
|
||||
t: &mut BTree,
|
||||
samples_size: usize,
|
||||
sample_provider: F,
|
||||
) where
|
||||
F: Fn(usize) -> (Key, Payload),
|
||||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||
K: KeyProvider + Clone + Sync,
|
||||
{
|
||||
for i in 0..samples_size {
|
||||
let (key, payload) = sample_provider(i);
|
||||
|
@ -791,10 +797,10 @@ mod tests {
|
|||
|
||||
#[test(tokio::test)]
|
||||
async fn test_btree_fst_small_order_sequential_insertions() {
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(5));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(5));
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, get_key_value).await;
|
||||
insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, get_key_value).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -810,10 +816,10 @@ mod tests {
|
|||
|
||||
#[test(tokio::test)]
|
||||
async fn test_btree_trie_small_order_sequential_insertions() {
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(6));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(6));
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, get_key_value).await;
|
||||
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, get_key_value).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -831,11 +837,11 @@ mod tests {
|
|||
async fn test_btree_fst_small_order_random_insertions() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(8));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(8));
|
||||
let mut samples: Vec<usize> = (0..100).collect();
|
||||
let mut rng = thread_rng();
|
||||
samples.shuffle(&mut rng);
|
||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
||||
insertions_test::<_, FstKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
let s = t.statistics::<FstKeys>(&mut tx).await.unwrap();
|
||||
|
@ -846,12 +852,11 @@ mod tests {
|
|||
async fn test_btree_trie_small_order_random_insertions() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(75));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(75));
|
||||
let mut samples: Vec<usize> = (0..100).collect();
|
||||
let mut rng = thread_rng();
|
||||
samples.shuffle(&mut rng);
|
||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 100, |i| get_key_value(samples[i]))
|
||||
.await;
|
||||
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 100, |i| get_key_value(samples[i])).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
let s = t.statistics::<TrieKeys>(&mut tx).await.unwrap();
|
||||
|
@ -862,8 +867,8 @@ mod tests {
|
|||
async fn test_btree_fst_keys_large_order_sequential_insertions() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(60));
|
||||
insertions_test::<_, FstKeys, _>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(60));
|
||||
insertions_test::<_, FstKeys>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -881,8 +886,8 @@ mod tests {
|
|||
async fn test_btree_trie_keys_large_order_sequential_insertions() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(60));
|
||||
insertions_test::<_, TrieKeys, _>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(60));
|
||||
insertions_test::<_, TrieKeys>(&mut tx, &mut t, 10000, get_key_value).await;
|
||||
tx.commit().await.unwrap();
|
||||
let mut tx = ds.transaction(false, false).await.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -908,8 +913,8 @@ mod tests {
|
|||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(default_minimum_degree));
|
||||
insertions_test::<_, BK, _>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| {
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(default_minimum_degree));
|
||||
insertions_test::<_, BK>(&mut tx, &mut t, REAL_WORLD_TERMS.len(), |i| {
|
||||
(REAL_WORLD_TERMS[i].as_bytes().to_vec(), i as Payload)
|
||||
})
|
||||
.await;
|
||||
|
@ -1006,7 +1011,7 @@ mod tests {
|
|||
// This check node splitting. CLRS: Figure 18.7, page 498.
|
||||
async fn clrs_insertion_test() {
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
for (key, payload) in CLRS_EXAMPLE {
|
||||
t.insert::<TrieKeys>(&mut tx, key.into(), payload).await.unwrap();
|
||||
|
@ -1090,7 +1095,7 @@ mod tests {
|
|||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
for (key, payload) in CLRS_EXAMPLE {
|
||||
t.insert::<BK>(&mut tx, key.into(), payload).await.unwrap();
|
||||
|
@ -1180,7 +1185,7 @@ mod tests {
|
|||
BK: BKeys + Serialize + DeserializeOwned + Default,
|
||||
{
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let mut t = BTree::new(TestKeyProvider {}, State::new(3));
|
||||
let mut t = BTree::new(KeyProvider::Debug, State::new(3));
|
||||
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
let mut expected_keys = HashMap::new();
|
||||
|
@ -1191,13 +1196,13 @@ mod tests {
|
|||
tx.commit().await.unwrap();
|
||||
|
||||
let mut tx = ds.transaction(true, false).await.unwrap();
|
||||
print_tree::<BK, _>(&mut tx, &t).await;
|
||||
print_tree::<BK>(&mut tx, &t).await;
|
||||
|
||||
for (key, _) in CLRS_EXAMPLE {
|
||||
debug!("------------------------");
|
||||
debug!("Delete {}", key);
|
||||
t.delete::<BK>(&mut tx, key.into()).await.unwrap();
|
||||
print_tree::<BK, _>(&mut tx, &t).await;
|
||||
print_tree::<BK>(&mut tx, &t).await;
|
||||
|
||||
// Check that every expected keys are still found in the tree
|
||||
expected_keys.remove(key);
|
||||
|
@ -1259,9 +1264,8 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
async fn print_tree<BK, K>(tx: &mut Transaction, t: &BTree<K>)
|
||||
async fn print_tree<BK>(tx: &mut Transaction, t: &BTree)
|
||||
where
|
||||
K: KeyProvider + Clone + Sync,
|
||||
BK: BKeys + Serialize + DeserializeOwned,
|
||||
{
|
||||
debug!("----------------------------------");
|
||||
|
@ -1289,10 +1293,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K> BTree<K>
|
||||
where
|
||||
K: KeyProvider + Clone + Sync,
|
||||
{
|
||||
impl BTree {
|
||||
/// This is for debugging
|
||||
async fn inspect_nodes<BK, F>(
|
||||
&self,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::bkeys::TrieKeys;
|
||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
||||
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||
use crate::kvs::{Key, Transaction};
|
||||
use roaring::RoaringTreemap;
|
||||
|
@ -13,7 +13,7 @@ pub(crate) const NO_DOC_ID: u64 = u64::MAX;
|
|||
pub(crate) struct DocIds {
|
||||
state_key: Key,
|
||||
index_key_base: IndexKeyBase,
|
||||
btree: BTree<DocIdsKeyProvider>,
|
||||
btree: BTree,
|
||||
available_ids: Option<RoaringTreemap>,
|
||||
next_doc_id: DocId,
|
||||
updated: bool,
|
||||
|
@ -25,9 +25,7 @@ impl DocIds {
|
|||
index_key_base: IndexKeyBase,
|
||||
default_btree_order: u32,
|
||||
) -> Result<Self, Error> {
|
||||
let keys = DocIdsKeyProvider {
|
||||
index_key_base: index_key_base.clone(),
|
||||
};
|
||||
let keys = KeyProvider::DocIds(index_key_base.clone());
|
||||
let state_key: Key = keys.get_state_key();
|
||||
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||
State::try_from_val(val)?
|
||||
|
@ -179,20 +177,6 @@ impl Resolved {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DocIdsKeyProvider {
|
||||
index_key_base: IndexKeyBase,
|
||||
}
|
||||
|
||||
impl KeyProvider for DocIdsKeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
self.index_key_base.new_bd_key(Some(node_id))
|
||||
}
|
||||
fn get_state_key(&self) -> Key {
|
||||
self.index_key_base.new_bd_key(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idx::ft::docids::{DocIds, Resolved};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::bkeys::TrieKeys;
|
||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Payload, Statistics};
|
||||
use crate::idx::btree::{BTree, KeyProvider, Payload, Statistics};
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||
use crate::kvs::{Key, Transaction};
|
||||
|
@ -9,7 +9,7 @@ pub(super) type DocLength = u64;
|
|||
|
||||
pub(super) struct DocLengths {
|
||||
state_key: Key,
|
||||
btree: BTree<DocLengthsKeyProvider>,
|
||||
btree: BTree,
|
||||
}
|
||||
|
||||
impl DocLengths {
|
||||
|
@ -18,9 +18,7 @@ impl DocLengths {
|
|||
index_key_base: IndexKeyBase,
|
||||
default_btree_order: u32,
|
||||
) -> Result<Self, Error> {
|
||||
let keys = DocLengthsKeyProvider {
|
||||
index_key_base,
|
||||
};
|
||||
let keys = KeyProvider::DocLengths(index_key_base);
|
||||
let state_key: Key = keys.get_state_key();
|
||||
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||
btree::State::try_from_val(val)?
|
||||
|
@ -70,21 +68,6 @@ impl DocLengths {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DocLengthsKeyProvider {
|
||||
index_key_base: IndexKeyBase,
|
||||
}
|
||||
|
||||
impl KeyProvider for DocLengthsKeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
self.index_key_base.new_bl_key(Some(node_id))
|
||||
}
|
||||
|
||||
fn get_state_key(&self) -> Key {
|
||||
self.index_key_base.new_bl_key(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idx::ft::doclength::DocLengths;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::bkeys::TrieKeys;
|
||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
||||
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||
use crate::idx::ft::docids::DocId;
|
||||
use crate::idx::ft::terms::TermId;
|
||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||
|
@ -11,7 +11,7 @@ pub(super) type TermFrequency = u64;
|
|||
pub(super) struct Postings {
|
||||
state_key: Key,
|
||||
index_key_base: IndexKeyBase,
|
||||
btree: BTree<PostingsKeyProvider>,
|
||||
btree: BTree,
|
||||
}
|
||||
|
||||
impl Postings {
|
||||
|
@ -20,9 +20,7 @@ impl Postings {
|
|||
index_key_base: IndexKeyBase,
|
||||
order: u32,
|
||||
) -> Result<Self, Error> {
|
||||
let keys = PostingsKeyProvider {
|
||||
index_key_base: index_key_base.clone(),
|
||||
};
|
||||
let keys = KeyProvider::Postings(index_key_base.clone());
|
||||
let state_key: Key = keys.get_state_key();
|
||||
let state: btree::State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||
btree::State::try_from_val(val)?
|
||||
|
@ -79,20 +77,6 @@ impl Postings {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) struct PostingsKeyProvider {
|
||||
index_key_base: IndexKeyBase,
|
||||
}
|
||||
|
||||
impl KeyProvider for PostingsKeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
self.index_key_base.new_bp_key(Some(node_id))
|
||||
}
|
||||
fn get_state_key(&self) -> Key {
|
||||
self.index_key_base.new_bp_key(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idx::ft::postings::Postings;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::err::Error;
|
||||
use crate::idx::bkeys::FstKeys;
|
||||
use crate::idx::btree::{BTree, KeyProvider, NodeId, Statistics};
|
||||
use crate::idx::btree::{BTree, KeyProvider, Statistics};
|
||||
use crate::idx::{btree, IndexKeyBase, SerdeState};
|
||||
use crate::kvs::{Key, Transaction};
|
||||
use roaring::RoaringTreemap;
|
||||
|
@ -11,7 +11,7 @@ pub(crate) type TermId = u64;
|
|||
pub(super) struct Terms {
|
||||
state_key: Key,
|
||||
index_key_base: IndexKeyBase,
|
||||
btree: BTree<TermsKeyProvider>,
|
||||
btree: BTree,
|
||||
available_ids: Option<RoaringTreemap>,
|
||||
next_term_id: TermId,
|
||||
updated: bool,
|
||||
|
@ -23,9 +23,7 @@ impl Terms {
|
|||
index_key_base: IndexKeyBase,
|
||||
default_btree_order: u32,
|
||||
) -> Result<Self, Error> {
|
||||
let keys = TermsKeyProvider {
|
||||
index_key_base: index_key_base.clone(),
|
||||
};
|
||||
let keys = KeyProvider::Terms(index_key_base.clone());
|
||||
let state_key: Key = keys.get_state_key();
|
||||
let state: State = if let Some(val) = tx.get(state_key.clone()).await? {
|
||||
State::try_from_val(val)?
|
||||
|
@ -143,20 +141,6 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TermsKeyProvider {
|
||||
index_key_base: IndexKeyBase,
|
||||
}
|
||||
|
||||
impl KeyProvider for TermsKeyProvider {
|
||||
fn get_node_key(&self, node_id: NodeId) -> Key {
|
||||
self.index_key_base.new_bt_key(Some(node_id))
|
||||
}
|
||||
fn get_state_key(&self) -> Key {
|
||||
self.index_key_base.new_bt_key(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::idx::ft::postings::TermFrequency;
|
||||
|
|
|
@ -177,7 +177,7 @@ impl QueryExecutor {
|
|||
|
||||
pub(crate) async fn highlight(
|
||||
&self,
|
||||
txn: Transaction,
|
||||
txn: &Transaction,
|
||||
thg: &Thing,
|
||||
prefix: Value,
|
||||
suffix: Value,
|
||||
|
@ -195,7 +195,7 @@ impl QueryExecutor {
|
|||
|
||||
pub(crate) async fn offsets(
|
||||
&self,
|
||||
txn: Transaction,
|
||||
txn: &Transaction,
|
||||
thg: &Thing,
|
||||
match_ref: &Value,
|
||||
) -> Result<Value, Error> {
|
||||
|
@ -208,7 +208,7 @@ impl QueryExecutor {
|
|||
|
||||
pub(crate) async fn score(
|
||||
&self,
|
||||
txn: Transaction,
|
||||
txn: &Transaction,
|
||||
match_ref: &Value,
|
||||
rid: &Thing,
|
||||
mut doc_id: Option<DocId>,
|
||||
|
|
|
@ -3,7 +3,7 @@ pub(crate) mod plan;
|
|||
mod tree;
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::{Iterable, Options};
|
||||
use crate::dbs::{Iterable, Options, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::idx::planner::executor::QueryExecutor;
|
||||
use crate::idx::planner::plan::{Plan, PlanBuilder};
|
||||
|
@ -30,17 +30,17 @@ impl<'a> QueryPlanner<'a> {
|
|||
pub(crate) async fn get_iterable(
|
||||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
txn: &Transaction,
|
||||
t: Table,
|
||||
) -> Result<Iterable, Error> {
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
let res = Tree::build(ctx, self.opt, &txn, &t, self.cond).await?;
|
||||
let res = Tree::build(ctx, self.opt, txn, &t, self.cond).await?;
|
||||
if let Some((node, im)) = res {
|
||||
if let Some(plan) = AllAndStrategy::build(&node)? {
|
||||
let e = QueryExecutor::new(self.opt, &txn, &t, im, Some(plan.e.clone())).await?;
|
||||
let e = QueryExecutor::new(self.opt, txn, &t, im, Some(plan.e.clone())).await?;
|
||||
self.executors.insert(t.0.clone(), e);
|
||||
return Ok(Iterable::Index(t, plan));
|
||||
}
|
||||
let e = QueryExecutor::new(self.opt, &txn, &t, im, None).await?;
|
||||
let e = QueryExecutor::new(self.opt, txn, &t, im, None).await?;
|
||||
self.executors.insert(t.0.clone(), e);
|
||||
}
|
||||
Ok(Iterable::Table(t))
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::sql::index::Index;
|
|||
use crate::sql::scoring::Scoring;
|
||||
use crate::sql::statements::DefineIndexStatement;
|
||||
use crate::sql::{Array, Expression, Ident, Idiom, Object, Operator, Thing, Value};
|
||||
use async_trait::async_trait;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
|
@ -54,7 +53,7 @@ impl Plan {
|
|||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
exe: &QueryExecutor,
|
||||
) -> Result<Box<dyn ThingIterator>, Error> {
|
||||
) -> Result<ThingIterator, Error> {
|
||||
self.i.new_iterator(opt, txn, exe).await
|
||||
}
|
||||
|
||||
|
@ -128,11 +127,11 @@ impl IndexOption {
|
|||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
exe: &QueryExecutor,
|
||||
) -> Result<Box<dyn ThingIterator>, Error> {
|
||||
) -> Result<ThingIterator, Error> {
|
||||
match &self.ix().index {
|
||||
Index::Idx => {
|
||||
if self.op() == &Operator::Equal {
|
||||
return Ok(Box::new(NonUniqueEqualThingIterator::new(
|
||||
return Ok(ThingIterator::NonUniqueEqual(NonUniqueEqualThingIterator::new(
|
||||
opt,
|
||||
self.ix(),
|
||||
self.value(),
|
||||
|
@ -141,7 +140,7 @@ impl IndexOption {
|
|||
}
|
||||
Index::Uniq => {
|
||||
if self.op() == &Operator::Equal {
|
||||
return Ok(Box::new(UniqueEqualThingIterator::new(
|
||||
return Ok(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(
|
||||
opt,
|
||||
self.ix(),
|
||||
self.value(),
|
||||
|
@ -156,7 +155,7 @@ impl IndexOption {
|
|||
} => {
|
||||
if let Operator::Matches(_) = self.op() {
|
||||
let td = exe.pre_match_terms_docs();
|
||||
return Ok(Box::new(
|
||||
return Ok(ThingIterator::Matches(
|
||||
MatchesThingIterator::new(opt, txn, self.ix(), az, *hl, sc, *order, td)
|
||||
.await?,
|
||||
));
|
||||
|
@ -167,23 +166,37 @@ impl IndexOption {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
pub(crate) trait ThingIterator: Send {
|
||||
async fn next_batch(
|
||||
pub(crate) enum ThingIterator {
|
||||
NonUniqueEqual(NonUniqueEqualThingIterator),
|
||||
UniqueEqual(UniqueEqualThingIterator),
|
||||
Matches(MatchesThingIterator),
|
||||
}
|
||||
|
||||
impl ThingIterator {
|
||||
pub(crate) async fn next_batch(
|
||||
&mut self,
|
||||
tx: &Transaction,
|
||||
size: u32,
|
||||
) -> Result<Vec<(Thing, DocId)>, Error>;
|
||||
) -> Result<Vec<(Thing, DocId)>, Error> {
|
||||
match self {
|
||||
ThingIterator::NonUniqueEqual(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::UniqueEqual(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::Matches(i) => i.next_batch(tx, size).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NonUniqueEqualThingIterator {
|
||||
pub(crate) struct NonUniqueEqualThingIterator {
|
||||
beg: Vec<u8>,
|
||||
end: Vec<u8>,
|
||||
}
|
||||
|
||||
impl NonUniqueEqualThingIterator {
|
||||
fn new(opt: &Options, ix: &DefineIndexStatement, v: &Value) -> Result<Self, Error> {
|
||||
fn new(
|
||||
opt: &Options,
|
||||
ix: &DefineIndexStatement,
|
||||
v: &Value,
|
||||
) -> Result<NonUniqueEqualThingIterator, Error> {
|
||||
let v = Array::from(v.clone());
|
||||
let beg = key::index::prefix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
||||
let end = key::index::suffix_all_ids(opt.ns(), opt.db(), &ix.what, &ix.name, &v);
|
||||
|
@ -192,11 +205,7 @@ impl NonUniqueEqualThingIterator {
|
|||
end,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
impl ThingIterator for NonUniqueEqualThingIterator {
|
||||
async fn next_batch(
|
||||
&mut self,
|
||||
txn: &Transaction,
|
||||
|
@ -214,7 +223,7 @@ impl ThingIterator for NonUniqueEqualThingIterator {
|
|||
}
|
||||
}
|
||||
|
||||
struct UniqueEqualThingIterator {
|
||||
pub(crate) struct UniqueEqualThingIterator {
|
||||
key: Option<Key>,
|
||||
}
|
||||
|
||||
|
@ -226,11 +235,7 @@ impl UniqueEqualThingIterator {
|
|||
key: Some(key),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
impl ThingIterator for UniqueEqualThingIterator {
|
||||
async fn next_batch(
|
||||
&mut self,
|
||||
txn: &Transaction,
|
||||
|
@ -245,7 +250,7 @@ impl ThingIterator for UniqueEqualThingIterator {
|
|||
}
|
||||
}
|
||||
|
||||
struct MatchesThingIterator {
|
||||
pub(crate) struct MatchesThingIterator {
|
||||
hits: Option<HitsIterator>,
|
||||
}
|
||||
|
||||
|
@ -285,11 +290,7 @@ impl MatchesThingIterator {
|
|||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
impl ThingIterator for MatchesThingIterator {
|
||||
async fn next_batch(
|
||||
&mut self,
|
||||
txn: &Transaction,
|
||||
|
|
|
@ -79,7 +79,7 @@ impl<'a> TreeBuilder<'a> {
|
|||
Value::Bool(_) => Node::Scalar(v.to_owned()),
|
||||
Value::Subquery(s) => self.eval_subquery(s).await?,
|
||||
Value::Param(p) => {
|
||||
let v = p.compute(self.ctx, self.opt).await?;
|
||||
let v = p.compute(self.ctx, self.opt, self.txn, None).await?;
|
||||
self.eval_value(&v).await?
|
||||
}
|
||||
_ => Node::Unsupported,
|
||||
|
|
|
@ -447,8 +447,6 @@ impl Datastore {
|
|||
let txn = Arc::new(Mutex::new(txn));
|
||||
// Create a default context
|
||||
let mut ctx = Context::default();
|
||||
// Add the transaction
|
||||
ctx.add_transaction(Some(&txn));
|
||||
// Set the global query timeout
|
||||
if let Some(timeout) = self.query_timeout {
|
||||
ctx.add_timeout(timeout);
|
||||
|
@ -462,7 +460,7 @@ impl Datastore {
|
|||
// Store the query variables
|
||||
let ctx = vars.attach(ctx)?;
|
||||
// Compute the value
|
||||
let res = val.compute(&ctx, &opt).await?;
|
||||
let res = val.compute(&ctx, &opt, &txn, None).await?;
|
||||
// Store any data
|
||||
match val.writeable() {
|
||||
true => txn.lock().await.commit().await?,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{closebracket, commas, openbracket};
|
||||
|
@ -117,10 +118,16 @@ impl Array {
|
|||
|
||||
impl Array {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
let mut x = Self::with_capacity(self.len());
|
||||
for v in self.iter() {
|
||||
match v.compute(ctx, opt).await {
|
||||
match v.compute(ctx, opt, txn, doc).await {
|
||||
Ok(v) => x.push(v),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::cnf::PROTECTED_PARAM_NAMES;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::{comment, mightbespace};
|
||||
use crate::sql::common::{closebraces, colons, openbraces};
|
||||
|
@ -51,7 +52,13 @@ impl Block {
|
|||
self.iter().any(Entry::writeable)
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Duplicate context
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Loop over the statements
|
||||
|
@ -61,7 +68,7 @@ impl Block {
|
|||
// Check if the variable is a protected variable
|
||||
let val = match PROTECTED_PARAM_NAMES.contains(&v.name.as_str()) {
|
||||
// The variable isn't protected and can be stored
|
||||
false => v.compute(&ctx, opt).await,
|
||||
false => v.compute(&ctx, opt, txn, doc).await,
|
||||
// The user tried to set a protected variable
|
||||
true => {
|
||||
return Err(Error::InvalidParam {
|
||||
|
@ -73,31 +80,31 @@ impl Block {
|
|||
ctx.add_value(v.name.to_owned(), val);
|
||||
}
|
||||
Entry::Ifelse(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Select(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Create(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Update(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Delete(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Relate(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Insert(v) => {
|
||||
v.compute(&ctx, opt).await?;
|
||||
v.compute(&ctx, opt, txn, doc).await?;
|
||||
}
|
||||
Entry::Output(v) => {
|
||||
return v.compute(&ctx, opt).await;
|
||||
return v.compute(&ctx, opt, txn, doc).await;
|
||||
}
|
||||
Entry::Value(v) => {
|
||||
return v.compute(&ctx, opt).await;
|
||||
return v.compute(&ctx, opt, txn, doc).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -36,11 +37,17 @@ impl Cast {
|
|||
impl Cast {
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Prevent long cast chains
|
||||
let opt = &opt.dive(1)?;
|
||||
// Compute the value to be cast and convert it
|
||||
self.1.compute(ctx, opt).await?.convert_to(&self.0)
|
||||
self.1.compute(ctx, opt, txn, doc).await?.convert_to(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::value::Value;
|
||||
|
@ -78,7 +79,13 @@ impl Constant {
|
|||
}
|
||||
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Ok(match self.value() {
|
||||
ConstantValue::Datetime(d) => d.into(),
|
||||
ConstantValue::Float(f) => f.into(),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
|
@ -43,25 +43,26 @@ impl Data {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
tb: &Table,
|
||||
) -> Result<Thing, Error> {
|
||||
match self {
|
||||
Self::MergeExpression(v) => {
|
||||
// This MERGE expression has an 'id' field
|
||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
||||
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||
}
|
||||
Self::ReplaceExpression(v) => {
|
||||
// This REPLACE expression has an 'id' field
|
||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
||||
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||
}
|
||||
Self::ContentExpression(v) => {
|
||||
// This CONTENT expression has an 'id' field
|
||||
v.compute(ctx, opt).await?.rid().generate(tb, false)
|
||||
v.compute(ctx, opt, txn, None).await?.rid().generate(tb, false)
|
||||
}
|
||||
Self::SetExpression(v) => match v.iter().find(|f| f.0.is_id()) {
|
||||
Some((_, _, v)) => {
|
||||
// This SET expression has an 'id' field
|
||||
v.compute(ctx, opt).await?.generate(tb, false)
|
||||
v.compute(ctx, opt, txn, None).await?.generate(tb, false)
|
||||
}
|
||||
// This SET expression had no 'id' field
|
||||
_ => Ok(tb.generate()),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::comment::mightbespace;
|
||||
|
@ -101,13 +102,19 @@ impl Expression {
|
|||
}
|
||||
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
let (l, o, r) = match self {
|
||||
Self::Unary {
|
||||
o,
|
||||
v,
|
||||
} => {
|
||||
let operand = v.compute(ctx, opt).await?;
|
||||
let operand = v.compute(ctx, opt, txn, doc).await?;
|
||||
return match o {
|
||||
Operator::Neg => fnc::operate::neg(operand),
|
||||
Operator::Not => fnc::operate::not(operand),
|
||||
|
@ -121,7 +128,7 @@ impl Expression {
|
|||
} => (l, o, r),
|
||||
};
|
||||
|
||||
let l = l.compute(ctx, opt).await?;
|
||||
let l = l.compute(ctx, opt, txn, doc).await?;
|
||||
match o {
|
||||
Operator::Or => {
|
||||
if let true = l.is_truthy() {
|
||||
|
@ -145,7 +152,7 @@ impl Expression {
|
|||
}
|
||||
_ => {} // Continue
|
||||
}
|
||||
let r = r.compute(ctx, opt).await?;
|
||||
let r = r.compute(ctx, opt, txn, doc).await?;
|
||||
match o {
|
||||
Operator::Or => fnc::operate::or(l, r),
|
||||
Operator::And => fnc::operate::and(l, r),
|
||||
|
@ -181,7 +188,7 @@ impl Expression {
|
|||
Operator::NoneInside => fnc::operate::inside_none(&l, &r),
|
||||
Operator::Outside => fnc::operate::outside(&l, &r),
|
||||
Operator::Intersects => fnc::operate::intersects(&l, &r),
|
||||
Operator::Matches(_) => fnc::operate::matches(ctx, self).await,
|
||||
Operator::Matches(_) => fnc::operate::matches(ctx, txn, doc, self).await,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
|
@ -75,17 +76,31 @@ impl Fields {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
group: bool,
|
||||
) -> Result<Value, Error> {
|
||||
// Ensure futures are run
|
||||
if let Some(doc) = doc {
|
||||
self.compute_value(ctx, opt, txn, doc, group).await
|
||||
} else {
|
||||
let doc = CursorDoc::new(None, None, &Value::None);
|
||||
self.compute_value(ctx, opt, txn, &doc, group).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn compute_value(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: &CursorDoc<'_>,
|
||||
group: bool,
|
||||
) -> Result<Value, Error> {
|
||||
let opt = &opt.new_with_futures(true);
|
||||
//
|
||||
let doc = ctx.doc().unwrap_or(&Value::None);
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_cursor_doc(doc);
|
||||
// Process the desired output
|
||||
let mut out = match self.is_all() {
|
||||
true => doc.compute(&ctx, opt).await?,
|
||||
true => doc.doc.compute(ctx, opt, txn, Some(doc)).await?,
|
||||
false => Value::base(),
|
||||
};
|
||||
for v in self.other() {
|
||||
|
@ -104,13 +119,13 @@ impl Fields {
|
|||
Value::Function(f) if group && f.is_aggregate() => {
|
||||
let x = match f.args().len() {
|
||||
// If no function arguments, then compute the result
|
||||
0 => f.compute(&ctx, opt).await?,
|
||||
0 => f.compute(ctx, opt, txn, Some(doc)).await?,
|
||||
// If arguments, then pass the first value through
|
||||
_ => f.args()[0].compute(&ctx, opt).await?,
|
||||
_ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?,
|
||||
};
|
||||
// Check if this is a single VALUE field expression
|
||||
match self.single().is_some() {
|
||||
false => out.set(&ctx, opt, idiom.as_ref(), x).await?,
|
||||
false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?,
|
||||
true => out = x,
|
||||
}
|
||||
}
|
||||
|
@ -123,11 +138,15 @@ impl Fields {
|
|||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => doc,
|
||||
None => doc.doc.as_ref(),
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x =
|
||||
x.get(&ctx, opt, v).await?.compute(&ctx, opt).await?.flatten();
|
||||
let x = x
|
||||
.get(ctx, opt, txn, Some(doc), v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(doc))
|
||||
.await?
|
||||
.flatten();
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
|
@ -137,23 +156,24 @@ impl Fields {
|
|||
// This is an alias expression part
|
||||
Some(a) => {
|
||||
if let Some(i) = alias {
|
||||
out.set(&ctx, opt, i, x.clone()).await?;
|
||||
out.set(ctx, opt, txn, i, x.clone()).await?;
|
||||
}
|
||||
out.set(&ctx, opt, a, x).await?;
|
||||
out.set(ctx, opt, txn, a, x).await?;
|
||||
}
|
||||
// This is the end of the expression
|
||||
None => {
|
||||
out.set(&ctx, opt, alias.as_ref().unwrap_or(v), x).await?
|
||||
out.set(ctx, opt, txn, alias.as_ref().unwrap_or(v), x)
|
||||
.await?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This expression is a normal field expression
|
||||
_ => {
|
||||
let x = expr.compute(&ctx, opt).await?;
|
||||
let x = expr.compute(ctx, opt, txn, Some(doc)).await?;
|
||||
// Check if this is a single VALUE field expression
|
||||
match self.single().is_some() {
|
||||
false => out.set(&ctx, opt, idiom.as_ref(), x).await?,
|
||||
false => out.set(ctx, opt, txn, idiom.as_ref(), x).await?,
|
||||
true => out = x,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::fnc;
|
||||
use crate::sql::comment::mightbespace;
|
||||
|
@ -131,7 +132,13 @@ impl Function {
|
|||
/// Process this type returning a computed simple Value
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Prevent long function chains
|
||||
let opt = &opt.dive(1)?;
|
||||
// Ensure futures are run
|
||||
|
@ -140,15 +147,13 @@ impl Function {
|
|||
match self {
|
||||
Self::Normal(s, x) => {
|
||||
// Compute the function arguments
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||
// Run the normal function
|
||||
fnc::run(ctx, s, a).await
|
||||
fnc::run(ctx, txn, doc, s, a).await
|
||||
}
|
||||
Self::Custom(s, x) => {
|
||||
// Get the function definition
|
||||
let val = {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Get the function definition
|
||||
|
@ -165,7 +170,7 @@ impl Function {
|
|||
});
|
||||
}
|
||||
// Compute the function arguments
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||
// Duplicate context
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Process the function arguments
|
||||
|
@ -173,16 +178,16 @@ impl Function {
|
|||
ctx.add_value(name.to_raw(), val.coerce_to(&kind)?);
|
||||
}
|
||||
// Run the custom function
|
||||
val.block.compute(&ctx, opt).await
|
||||
val.block.compute(&ctx, opt, txn, doc).await
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
Self::Script(s, x) => {
|
||||
#[cfg(feature = "scripting")]
|
||||
{
|
||||
// Compute the function arguments
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt))).await?;
|
||||
let a = try_join_all(x.iter().map(|v| v.compute(ctx, opt, txn, doc))).await?;
|
||||
// Run the script function
|
||||
fnc::script::run(ctx, opt, s, a).await
|
||||
fnc::script::run(ctx, opt, txn, doc, s, a).await
|
||||
}
|
||||
#[cfg(not(feature = "scripting"))]
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::block::{block, Block};
|
||||
use crate::sql::comment::mightbespace;
|
||||
|
@ -24,12 +25,18 @@ impl From<Value> for Future {
|
|||
|
||||
impl Future {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Prevent long future chains
|
||||
let opt = &opt.dive(1)?;
|
||||
// Process the future if enabled
|
||||
match opt.futures {
|
||||
true => self.0.compute(ctx, opt).await?.ok(),
|
||||
true => self.0.compute(ctx, opt, txn, doc).await?.ok(),
|
||||
false => Ok(self.clone().into()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::cnf::ID_CHARS;
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::{array, Array};
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -166,15 +167,21 @@ impl Display for Id {
|
|||
|
||||
impl Id {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Id, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Id, Error> {
|
||||
match self {
|
||||
Id::Number(v) => Ok(Id::Number(*v)),
|
||||
Id::String(v) => Ok(Id::String(v.clone())),
|
||||
Id::Object(v) => match v.compute(ctx, opt).await? {
|
||||
Id::Object(v) => match v.compute(ctx, opt, txn, doc).await? {
|
||||
Value::Object(v) => Ok(Id::Object(v)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Id::Array(v) => match v.compute(ctx, opt).await? {
|
||||
Id::Array(v) => match v.compute(ctx, opt, txn, doc).await? {
|
||||
Value::Array(v) => Ok(Id::Array(v)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -127,21 +128,29 @@ impl Idiom {
|
|||
self.0.iter().any(|v| v.writeable())
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self.first() {
|
||||
// The starting part is a value
|
||||
Some(Part::Value(v)) => {
|
||||
v.compute(ctx, opt)
|
||||
v.compute(ctx, opt, txn, doc)
|
||||
.await?
|
||||
.get(ctx, opt, self.as_ref().next())
|
||||
.get(ctx, opt, txn, doc, self.as_ref().next())
|
||||
.await?
|
||||
.compute(ctx, opt)
|
||||
.compute(ctx, opt, txn, doc)
|
||||
.await
|
||||
}
|
||||
// Otherwise use the current document
|
||||
_ => match ctx.doc() {
|
||||
_ => match doc {
|
||||
// There is a current document
|
||||
Some(v) => v.get(ctx, opt, self).await?.compute(ctx, opt).await,
|
||||
Some(v) => {
|
||||
v.doc.get(ctx, opt, txn, doc, self).await?.compute(ctx, opt, txn, doc).await
|
||||
}
|
||||
// There isn't any document
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -15,8 +16,14 @@ use std::fmt;
|
|||
pub struct Limit(pub Value);
|
||||
|
||||
impl Limit {
|
||||
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> {
|
||||
match self.0.compute(ctx, opt).await {
|
||||
pub(crate) async fn process(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<usize, Error> {
|
||||
match self.0.compute(ctx, opt, txn, doc).await {
|
||||
// This is a valid limiting number
|
||||
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
||||
// An invalid value was specified
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::{commas, val_char};
|
||||
|
@ -124,10 +125,16 @@ impl Object {
|
|||
|
||||
impl Object {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
let mut x = BTreeMap::new();
|
||||
for (k, v) in self.iter() {
|
||||
match v.compute(ctx, opt).await {
|
||||
match v.compute(ctx, opt, txn, doc).await {
|
||||
Ok(v) => x.insert(k.clone(), v),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
|
@ -43,24 +44,28 @@ impl Deref for Param {
|
|||
|
||||
impl Param {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Find the variable by name
|
||||
match self.as_str() {
|
||||
// This is a special param
|
||||
"this" | "self" => match ctx.doc() {
|
||||
"this" | "self" => match doc {
|
||||
// The base document exists
|
||||
Some(v) => v.compute(ctx, opt).await,
|
||||
Some(v) => v.doc.compute(ctx, opt, txn, doc).await,
|
||||
// The base document does not exist
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
// This is a normal param
|
||||
v => match ctx.value(v) {
|
||||
// The param has been set locally
|
||||
Some(v) => v.compute(ctx, opt).await,
|
||||
Some(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
// The param has not been set locally
|
||||
None => {
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Get the param definition
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::id::{id, Id};
|
||||
|
@ -48,17 +49,23 @@ impl TryFrom<&str> for Range {
|
|||
|
||||
impl Range {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Ok(Value::Range(Box::new(Range {
|
||||
tb: self.tb.clone(),
|
||||
beg: match &self.beg {
|
||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?),
|
||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?),
|
||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
||||
Bound::Unbounded => Bound::Unbounded,
|
||||
},
|
||||
end: match &self.end {
|
||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt).await?),
|
||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt).await?),
|
||||
Bound::Included(id) => Bound::Included(id.compute(ctx, opt, txn, doc).await?),
|
||||
Bound::Excluded(id) => Bound::Excluded(id.compute(ctx, opt, txn, doc).await?),
|
||||
Bound::Unbounded => Bound::Unbounded,
|
||||
},
|
||||
})))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -15,8 +16,14 @@ use std::fmt;
|
|||
pub struct Start(pub Value);
|
||||
|
||||
impl Start {
|
||||
pub(crate) async fn process(&self, ctx: &Context<'_>, opt: &Options) -> Result<usize, Error> {
|
||||
match self.0.compute(ctx, opt).await {
|
||||
pub(crate) async fn process(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<usize, Error> {
|
||||
match self.0.compute(ctx, opt, txn, doc).await {
|
||||
// This is a valid starting number
|
||||
Ok(Value::Number(Number::Int(v))) if v >= 0 => Ok(v as usize),
|
||||
// An invalid value was specified
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::{comment, mightbespace};
|
||||
use crate::sql::common::colons;
|
||||
|
@ -138,25 +139,31 @@ impl Statement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Analyze(v) => v.compute(ctx, opt).await,
|
||||
Self::Create(v) => v.compute(ctx, opt).await,
|
||||
Self::Delete(v) => v.compute(ctx, opt).await,
|
||||
Self::Define(v) => v.compute(ctx, opt).await,
|
||||
Self::Ifelse(v) => v.compute(ctx, opt).await,
|
||||
Self::Info(v) => v.compute(ctx, opt).await,
|
||||
Self::Insert(v) => v.compute(ctx, opt).await,
|
||||
Self::Kill(v) => v.compute(ctx, opt).await,
|
||||
Self::Live(v) => v.compute(ctx, opt).await,
|
||||
Self::Output(v) => v.compute(ctx, opt).await,
|
||||
Self::Relate(v) => v.compute(ctx, opt).await,
|
||||
Self::Remove(v) => v.compute(ctx, opt).await,
|
||||
Self::Select(v) => v.compute(ctx, opt).await,
|
||||
Self::Set(v) => v.compute(ctx, opt).await,
|
||||
Self::Show(v) => v.compute(ctx, opt).await,
|
||||
Self::Sleep(v) => v.compute(ctx, opt).await,
|
||||
Self::Update(v) => v.compute(ctx, opt).await,
|
||||
Self::Analyze(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Create(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Delete(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Define(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Ifelse(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Info(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Insert(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Kill(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Live(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Output(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Relate(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Remove(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Select(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Set(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Show(v) => v.compute(ctx, opt, doc).await,
|
||||
Self::Sleep(v) => v.compute(ctx, opt, doc).await,
|
||||
Self::Update(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::idx::ft::FtIndex;
|
||||
use crate::idx::IndexKeyBase;
|
||||
|
@ -22,15 +23,19 @@ pub enum AnalyzeStatement {
|
|||
|
||||
impl AnalyzeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
AnalyzeStatement::Idx(tb, idx) => {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Read the index
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::data::{data, Data};
|
||||
|
@ -42,7 +43,13 @@ impl CreateStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -53,11 +60,11 @@ impl CreateStatement {
|
|||
let opt = &opt.new_with_futures(false);
|
||||
// Loop over the create targets
|
||||
for w in self.what.0.iter() {
|
||||
let v = w.compute(ctx, opt).await?;
|
||||
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Table(v) => match &self.data {
|
||||
// There is a data clause so check for a record id
|
||||
Some(data) => match data.rid(ctx, opt, &v).await {
|
||||
Some(data) => match data.rid(ctx, opt, txn, &v).await {
|
||||
// There was a problem creating the record id
|
||||
Err(e) => return Err(e),
|
||||
// There is an id field so use the record id
|
||||
|
@ -116,7 +123,7 @@ impl CreateStatement {
|
|||
// Assign the statement
|
||||
let stm = Statement::from(self);
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::algorithm::{algorithm, Algorithm};
|
||||
use crate::sql::base::{base, base_or_scope, Base};
|
||||
|
@ -61,20 +62,26 @@ pub enum DefineStatement {
|
|||
|
||||
impl DefineStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Login(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Login(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,15 +133,19 @@ pub struct DefineNamespaceStatement {
|
|||
|
||||
impl DefineNamespaceStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// No need for NS/DB
|
||||
opt.needs(Level::Kv)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Process the statement
|
||||
let key = crate::key::ns::new(&self.name);
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
run.set(key, self).await?;
|
||||
|
@ -175,13 +186,17 @@ pub struct DefineDatabaseStatement {
|
|||
|
||||
impl DefineDatabaseStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected NS?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -252,13 +267,17 @@ pub struct DefineFunctionStatement {
|
|||
|
||||
impl DefineFunctionStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -330,13 +349,17 @@ pub struct DefineAnalyzerStatement {
|
|||
}
|
||||
|
||||
impl DefineAnalyzerStatement {
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -400,15 +423,19 @@ pub struct DefineLoginStatement {
|
|||
|
||||
impl DefineLoginStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self.base {
|
||||
Base::Ns => {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -423,8 +450,6 @@ impl DefineLoginStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -518,15 +543,19 @@ pub struct DefineTokenStatement {
|
|||
|
||||
impl DefineTokenStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match &self.base {
|
||||
Base::Ns => {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -541,8 +570,6 @@ impl DefineTokenStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -558,8 +585,6 @@ impl DefineTokenStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -633,13 +658,17 @@ pub struct DefineScopeStatement {
|
|||
|
||||
impl DefineScopeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -747,13 +776,17 @@ pub struct DefineParamStatement {
|
|||
|
||||
impl DefineParamStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -807,13 +840,17 @@ pub struct DefineTableStatement {
|
|||
}
|
||||
|
||||
impl DefineTableStatement {
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -852,7 +889,7 @@ impl DefineTableStatement {
|
|||
what: Values(vec![Value::Table(v.clone())]),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, doc).await?;
|
||||
}
|
||||
}
|
||||
// Ok all good
|
||||
|
@ -1006,13 +1043,17 @@ pub struct DefineEventStatement {
|
|||
|
||||
impl DefineEventStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -1086,13 +1127,17 @@ pub struct DefineFieldStatement {
|
|||
|
||||
impl DefineFieldStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -1242,13 +1287,17 @@ pub struct DefineIndexStatement {
|
|||
|
||||
impl DefineIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -1279,7 +1328,7 @@ impl DefineIndexStatement {
|
|||
what: Values(vec![Value::Table(self.what.clone().into())]),
|
||||
..UpdateStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt).await?;
|
||||
stm.compute(ctx, opt, txn, doc).await?;
|
||||
// Ok all good
|
||||
Ok(Value::None)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
|
@ -42,7 +43,13 @@ impl DeleteStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -53,7 +60,7 @@ impl DeleteStatement {
|
|||
let opt = &opt.new_with_futures(false);
|
||||
// Loop over the delete targets
|
||||
for w in self.what.0.iter() {
|
||||
let v = w.compute(ctx, opt).await?;
|
||||
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
|
@ -109,7 +116,7 @@ impl DeleteStatement {
|
|||
// Assign the statement
|
||||
let stm = Statement::from(self);
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -29,15 +30,21 @@ impl IfelseStatement {
|
|||
self.close.as_ref().map_or(false, |v| v.writeable())
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
for (ref cond, ref then) in &self.exprs {
|
||||
let v = cond.compute(ctx, opt).await?;
|
||||
let v = cond.compute(ctx, opt, txn, doc).await?;
|
||||
if v.is_truthy() {
|
||||
return then.compute(ctx, opt).await;
|
||||
return then.compute(ctx, opt, txn, doc).await;
|
||||
}
|
||||
}
|
||||
match self.close {
|
||||
Some(ref v) => v.compute(ctx, opt).await,
|
||||
Some(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
None => Ok(Value::None),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -24,7 +25,13 @@ pub enum InfoStatement {
|
|||
|
||||
impl InfoStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
match self {
|
||||
InfoStatement::Kv => {
|
||||
|
@ -34,8 +41,6 @@ impl InfoStatement {
|
|||
opt.check(Level::Kv)?;
|
||||
// Create the result set
|
||||
let mut res = Object::default();
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the statement
|
||||
|
@ -52,8 +57,6 @@ impl InfoStatement {
|
|||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Create the result set
|
||||
|
@ -84,8 +87,6 @@ impl InfoStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Create the result set
|
||||
|
@ -140,8 +141,6 @@ impl InfoStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Create the result set
|
||||
|
@ -160,8 +159,6 @@ impl InfoStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Create the result set
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::data::{single, update, values, Data};
|
||||
|
@ -45,7 +46,13 @@ impl InsertStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -63,8 +70,8 @@ impl InsertStatement {
|
|||
let mut o = Value::base();
|
||||
// Set each field from the expression
|
||||
for (k, v) in v.iter() {
|
||||
let v = v.compute(ctx, opt).await?;
|
||||
o.set(ctx, opt, k, v).await?;
|
||||
let v = v.compute(ctx, opt, txn, None).await?;
|
||||
o.set(ctx, opt, txn, k, v).await?;
|
||||
}
|
||||
// Specify the new table record id
|
||||
let id = o.rid().generate(&self.into, true)?;
|
||||
|
@ -74,7 +81,7 @@ impl InsertStatement {
|
|||
}
|
||||
// Check if this is a modern statement
|
||||
Data::SingleExpression(v) => {
|
||||
let v = v.compute(ctx, opt).await?;
|
||||
let v = v.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Array(v) => {
|
||||
for v in v {
|
||||
|
@ -102,7 +109,7 @@ impl InsertStatement {
|
|||
// Assign the statement
|
||||
let stm = Statement::from(self);
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -18,15 +19,19 @@ pub struct KillStatement {
|
|||
|
||||
impl KillStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.realtime()?;
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::No)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Fetch the live query key
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
|
@ -32,19 +33,23 @@ pub struct LiveStatement {
|
|||
|
||||
impl LiveStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Allowed to run?
|
||||
opt.realtime()?;
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::No)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Process the live query table
|
||||
match self.what.compute(ctx, opt).await? {
|
||||
match self.what.compute(ctx, opt, txn, doc).await? {
|
||||
Value::Table(tb) => {
|
||||
// Clone the current statement
|
||||
let mut stm = self.clone();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
|
@ -24,15 +25,21 @@ impl OutputStatement {
|
|||
self.what.writeable()
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Ensure futures are processed
|
||||
let opt = &opt.new_with_futures(true);
|
||||
// Process the output value
|
||||
let mut val = self.what.compute(ctx, opt).await?;
|
||||
let mut val = self.what.compute(ctx, opt, txn, doc).await?;
|
||||
// Fetch any
|
||||
if let Some(fetchs) = &self.fetch {
|
||||
for fetch in fetchs.iter() {
|
||||
val.fetch(ctx, opt, fetch).await?;
|
||||
val.fetch(ctx, opt, txn, fetch).await?;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::array;
|
||||
use crate::sql::comment::mightbespace;
|
||||
|
@ -55,7 +56,13 @@ impl RelateStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -67,7 +74,7 @@ impl RelateStatement {
|
|||
// Loop over the from targets
|
||||
let from = {
|
||||
let mut out = Vec::new();
|
||||
match self.from.compute(ctx, opt).await? {
|
||||
match self.from.compute(ctx, opt, txn, doc).await? {
|
||||
Value::Thing(v) => out.push(v),
|
||||
Value::Array(v) => {
|
||||
for v in v {
|
||||
|
@ -109,7 +116,7 @@ impl RelateStatement {
|
|||
// Loop over the with targets
|
||||
let with = {
|
||||
let mut out = Vec::new();
|
||||
match self.with.compute(ctx, opt).await? {
|
||||
match self.with.compute(ctx, opt, txn, doc).await? {
|
||||
Value::Thing(v) => out.push(v),
|
||||
Value::Array(v) => {
|
||||
for v in v {
|
||||
|
@ -158,7 +165,7 @@ impl RelateStatement {
|
|||
// The relation does not have a specific record id
|
||||
Value::Table(tb) => match &self.data {
|
||||
// There is a data clause so check for a record id
|
||||
Some(data) => match data.rid(ctx, opt, tb).await {
|
||||
Some(data) => match data.rid(ctx, opt, txn, tb).await {
|
||||
// There was a problem creating the record id
|
||||
Err(e) => return Err(e),
|
||||
// There is an id field so use the record id
|
||||
|
@ -175,7 +182,7 @@ impl RelateStatement {
|
|||
// Assign the statement
|
||||
let stm = Statement::from(self);
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Level, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::base::{base, base_or_scope, Base};
|
||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||
|
@ -38,20 +39,26 @@ pub enum RemoveStatement {
|
|||
|
||||
impl RemoveStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Login(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Namespace(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Database(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Function(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Login(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Token(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Scope(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Param(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Table(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Event(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Field(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Index(ref v) => v.compute(ctx, opt, txn).await,
|
||||
Self::Analyzer(ref v) => v.compute(ctx, opt, txn).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,13 +110,16 @@ pub struct RemoveNamespaceStatement {
|
|||
|
||||
impl RemoveNamespaceStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// No need for NS/DB
|
||||
opt.needs(Level::Kv)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -154,13 +164,16 @@ pub struct RemoveDatabaseStatement {
|
|||
|
||||
impl RemoveDatabaseStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected NS?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -205,13 +218,16 @@ pub struct RemoveFunctionStatement {
|
|||
|
||||
impl RemoveFunctionStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -260,13 +276,16 @@ pub struct RemoveAnalyzerStatement {
|
|||
}
|
||||
|
||||
impl RemoveAnalyzerStatement {
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -310,15 +329,18 @@ pub struct RemoveLoginStatement {
|
|||
|
||||
impl RemoveLoginStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
match self.base {
|
||||
Base::Ns => {
|
||||
// Selected NS?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -332,8 +354,6 @@ impl RemoveLoginStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -384,15 +404,18 @@ pub struct RemoveTokenStatement {
|
|||
|
||||
impl RemoveTokenStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
match &self.base {
|
||||
Base::Ns => {
|
||||
// Selected NS?
|
||||
opt.needs(Level::Ns)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Kv)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -406,8 +429,6 @@ impl RemoveTokenStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Ns)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -421,8 +442,6 @@ impl RemoveTokenStatement {
|
|||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -472,13 +491,16 @@ pub struct RemoveScopeStatement {
|
|||
|
||||
impl RemoveScopeStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -523,13 +545,16 @@ pub struct RemoveParamStatement {
|
|||
|
||||
impl RemoveParamStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -572,13 +597,16 @@ pub struct RemoveTableStatement {
|
|||
|
||||
impl RemoveTableStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -624,13 +652,16 @@ pub struct RemoveEventStatement {
|
|||
|
||||
impl RemoveEventStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -682,13 +713,16 @@ pub struct RemoveFieldStatement {
|
|||
|
||||
impl RemoveFieldStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
@ -741,13 +775,16 @@ pub struct RemoveIndexStatement {
|
|||
|
||||
impl RemoveIndexStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
opt.check(Level::Db)?;
|
||||
// Clone transaction
|
||||
let txn = ctx.try_clone_transaction()?;
|
||||
// Claim transaction
|
||||
let mut run = txn.lock().await;
|
||||
// Delete the definition
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::idx::planner::QueryPlanner;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
|
@ -72,7 +73,13 @@ impl SelectStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -86,10 +93,10 @@ impl SelectStatement {
|
|||
let mut planner = QueryPlanner::new(opt, &self.cond);
|
||||
// Loop over the select targets
|
||||
for w in self.what.0.iter() {
|
||||
let v = w.compute(ctx, opt).await?;
|
||||
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Table(t) => {
|
||||
i.ingest(planner.get_iterable(ctx, t).await?);
|
||||
i.ingest(planner.get_iterable(ctx, txn, t).await?);
|
||||
}
|
||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
Value::Range(v) => i.ingest(Iterable::Range(*v)),
|
||||
|
@ -124,10 +131,10 @@ impl SelectStatement {
|
|||
let mut ctx = Context::new(ctx);
|
||||
ctx.set_query_executors(ex);
|
||||
// Output the results
|
||||
i.output(&ctx, opt, &stm).await
|
||||
i.output(&ctx, opt, txn, &stm).await
|
||||
} else {
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
|
@ -25,8 +27,14 @@ impl SetStatement {
|
|||
self.what.writeable()
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
self.what.compute(ctx, opt).await
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
self.what.compute(ctx, opt, txn, doc).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::take_u64;
|
||||
|
@ -27,7 +28,12 @@ pub struct ShowStatement {
|
|||
|
||||
impl ShowStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, _ctx: &Context<'_>, _opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
_ctx: &Context<'_>,
|
||||
_opt: &Options,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Err(Error::FeatureNotYetImplemented {
|
||||
feature: "change feed",
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::duration::duration;
|
||||
|
@ -18,7 +19,12 @@ pub struct SleepStatement {
|
|||
|
||||
impl SleepStatement {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
_doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// No need for NS/DB
|
||||
opt.needs(Level::Kv)?;
|
||||
// Allowed to run?
|
||||
|
@ -87,9 +93,9 @@ mod tests {
|
|||
let sql = "SLEEP 500ms";
|
||||
let time = SystemTime::now();
|
||||
let opt = Options::default().with_auth(Arc::new(Auth::Kv));
|
||||
let (ctx, _) = mock().await;
|
||||
let (ctx, _, _) = mock().await;
|
||||
let (_, stm) = sleep(sql).unwrap();
|
||||
let value = stm.compute(&ctx, &opt).await.unwrap();
|
||||
let value = stm.compute(&ctx, &opt, None).await.unwrap();
|
||||
assert!(time.elapsed().unwrap() >= time::Duration::microseconds(500));
|
||||
assert_eq!(value, Value::None);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Iterable;
|
||||
use crate::dbs::Iterator;
|
||||
use crate::dbs::Level;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Statement;
|
||||
use crate::dbs::{Iterable, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::cond::{cond, Cond};
|
||||
|
@ -43,7 +44,13 @@ impl UpdateStatement {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Selected DB?
|
||||
opt.needs(Level::Db)?;
|
||||
// Allowed to run?
|
||||
|
@ -54,7 +61,7 @@ impl UpdateStatement {
|
|||
let opt = &opt.new_with_futures(false);
|
||||
// Loop over the update targets
|
||||
for w in self.what.0.iter() {
|
||||
let v = w.compute(ctx, opt).await?;
|
||||
let v = w.compute(ctx, opt, txn, doc).await?;
|
||||
match v {
|
||||
Value::Table(v) => i.ingest(Iterable::Table(v)),
|
||||
Value::Thing(v) => i.ingest(Iterable::Thing(v)),
|
||||
|
@ -110,7 +117,7 @@ impl UpdateStatement {
|
|||
// Assign the statement
|
||||
let stm = Statement::from(self);
|
||||
// Output the results
|
||||
i.output(ctx, opt, &stm).await
|
||||
i.output(ctx, opt, txn, &stm).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::common::{closeparentheses, openparentheses};
|
||||
use crate::sql::ending::subquery as ending;
|
||||
|
@ -59,25 +60,31 @@ impl Subquery {
|
|||
}
|
||||
}
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
// Prevent deep recursion
|
||||
let opt = &opt.dive(2)?;
|
||||
// Process the subquery
|
||||
match self {
|
||||
Self::Value(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Ifelse(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Output(ref v) => v.compute(ctx, opt).await,
|
||||
Self::Value(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Ifelse(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Output(ref v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Self::Select(ref v) => {
|
||||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
@ -93,13 +100,13 @@ impl Subquery {
|
|||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
@ -115,13 +122,13 @@ impl Subquery {
|
|||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
@ -137,13 +144,13 @@ impl Subquery {
|
|||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
@ -159,13 +166,13 @@ impl Subquery {
|
|||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
@ -181,13 +188,13 @@ impl Subquery {
|
|||
// Is this a single output?
|
||||
let one = v.single();
|
||||
// Duplicate context
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
let mut ctx = Context::new(ctx);
|
||||
// Add parent document
|
||||
if let Some(doc) = ctx.doc() {
|
||||
child_ctx.add_value("parent", doc);
|
||||
if let Some(doc) = doc {
|
||||
ctx.add_value("parent", doc.doc.as_ref());
|
||||
}
|
||||
// Process subquery
|
||||
match v.compute(&child_ctx, opt).await? {
|
||||
match v.compute(&ctx, opt, txn, doc).await? {
|
||||
// This is a single record result
|
||||
Value::Array(mut a) if one => match a.len() {
|
||||
// There was at least one result
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_rid;
|
||||
|
@ -102,10 +103,16 @@ impl fmt::Display for Thing {
|
|||
|
||||
impl Thing {
|
||||
/// Process this type returning a computed simple Value
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
Ok(Value::Thing(Thing {
|
||||
tb: self.tb.clone(),
|
||||
id: self.id.compute(ctx, opt).await?,
|
||||
id: self.id.compute(ctx, opt, txn, doc).await?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,121 +102,121 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn del_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::default();
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_reset() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_basic() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_wrong() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.wrong");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_other() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.other.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1]");
|
||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||
let res = Value::parse("{ test: { something: [123, 789] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[*].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_fields_flat() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_where_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_where_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::part::Part;
|
||||
|
@ -11,21 +11,22 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, path).await? {
|
||||
match self.get(ctx, opt, txn, None, path).await? {
|
||||
Value::Number(v) => match val {
|
||||
Value::Number(x) => self.set(ctx, opt, path, Value::from(v - x)).await,
|
||||
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
Value::Array(v) => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(v - x)).await,
|
||||
x => self.set(ctx, opt, path, Value::from(v - x)).await,
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from(v - x)).await,
|
||||
},
|
||||
Value::None => match val {
|
||||
Value::Number(x) => {
|
||||
self.set(ctx, opt, path, Value::from(Number::from(0) - x)).await
|
||||
self.set(ctx, opt, txn, path, Value::from(Number::from(0) - x)).await
|
||||
}
|
||||
_ => Ok(()),
|
||||
},
|
||||
|
@ -44,51 +45,51 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn decrement_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("other");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
let res = Value::parse("{ test: 100, other: -10 }");
|
||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn decrement_number() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
let res = Value::parse("{ test: 90 }");
|
||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn decrement_array_number() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test[1]");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 190, 300] }");
|
||||
val.decrement(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.decrement(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn decrement_array_value() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 300] }");
|
||||
val.decrement(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
||||
val.decrement(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn decrement_array_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [200] }");
|
||||
val.decrement(&ctx, &opt, &idi, Value::parse("[100, 300]")).await.unwrap();
|
||||
val.decrement(&ctx, &opt, &txn, &idi, Value::parse("[100, 300]")).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::exe::try_join_all_buffered;
|
||||
use crate::sql::array::Abolish;
|
||||
|
@ -17,6 +18,7 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
) -> Result<(), Error> {
|
||||
match path.first() {
|
||||
|
@ -30,7 +32,7 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.get_mut(f.as_str()) {
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await,
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -40,7 +42,7 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.get_mut(&i.to_string()) {
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, path.next()).await,
|
||||
Some(v) if v.is_some() => v.del(ctx, opt, txn, path.next()).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -55,7 +57,7 @@ impl Value {
|
|||
}
|
||||
_ => {
|
||||
let path = path.next();
|
||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, path));
|
||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path));
|
||||
try_join_all_buffered(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -69,7 +71,7 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.first_mut() {
|
||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -82,7 +84,7 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.last_mut() {
|
||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -94,7 +96,7 @@ impl Value {
|
|||
Ok(())
|
||||
}
|
||||
_ => match v.get_mut(i.to_usize()) {
|
||||
Some(v) => v.del(ctx, opt, path.next()).await,
|
||||
Some(v) => v.del(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
},
|
||||
|
@ -104,9 +106,8 @@ impl Value {
|
|||
// iterate in reverse, and call swap_remove
|
||||
let mut m = HashSet::new();
|
||||
for (i, v) in v.iter().enumerate() {
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(v);
|
||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
||||
let cur = CursorDoc::new(None, None, v);
|
||||
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||
m.insert(i);
|
||||
};
|
||||
}
|
||||
|
@ -116,17 +117,16 @@ impl Value {
|
|||
_ => {
|
||||
let path = path.next();
|
||||
for v in v.iter_mut() {
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(v);
|
||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
||||
v.del(ctx, opt, path).await?;
|
||||
let cur = CursorDoc::new(None, None, v);
|
||||
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||
v.del(ctx, opt, txn, path).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, path));
|
||||
let futs = v.iter_mut().map(|v| v.del(ctx, opt, txn, path));
|
||||
try_join_all_buffered(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -150,121 +150,121 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn del_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::default();
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_reset() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_basic() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_wrong() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.wrong");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_other() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.other.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1]");
|
||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||
let res = Value::parse("{ test: { something: [123, 789] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[*].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_fields_flat() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A' }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_where_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }, { name: 'B' }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn del_array_where_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let mut val = Value::parse(
|
||||
"{ test: { something: [{ name: 'A', age: 34 }, { name: 'B', age: 36 }] } }",
|
||||
);
|
||||
let res = Value::parse("{ test: { something: [{ name: 'A', age: 34 }] } }");
|
||||
val.del(&ctx, &opt, &idi).await.unwrap();
|
||||
val.del(&ctx, &opt, &txn, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Uniq;
|
||||
use crate::sql::part::Part;
|
||||
|
@ -10,17 +10,18 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, path).await? {
|
||||
match self.get(ctx, opt, txn, None, path).await? {
|
||||
Value::Array(v) => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, path, Value::from((v + x).uniq())).await,
|
||||
x => self.set(ctx, opt, path, Value::from((v + x).uniq())).await,
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from((v + x).uniq())).await,
|
||||
},
|
||||
Value::None => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await,
|
||||
x => self.set(ctx, opt, path, Value::from(vec![x])).await,
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -37,21 +38,21 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn extend_array_value() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300] }");
|
||||
val.extend(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
||||
val.extend(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn extend_array_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300, 400, 500] }");
|
||||
val.extend(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||
val.extend(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::edges::Edges;
|
||||
use crate::sql::field::{Field, Fields};
|
||||
|
@ -17,6 +18,7 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
) -> Result<(), Error> {
|
||||
match path.first() {
|
||||
|
@ -25,53 +27,52 @@ impl Value {
|
|||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Graph(_) => match v.rid() {
|
||||
Some(v) => Value::Thing(v).fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => Value::Thing(v).fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Field(f) => match v.get_mut(f as &str) {
|
||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::All => self.fetch(ctx, opt, path.next()).await,
|
||||
Part::All => self.fetch(ctx, opt, txn, path.next()).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
// Current path part is an array
|
||||
Value::Array(v) => match p {
|
||||
Part::All => {
|
||||
let path = path.next();
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
Part::First => match v.first_mut() {
|
||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Last => match v.last_mut() {
|
||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
||||
Some(v) => v.fetch(ctx, opt, path.next()).await,
|
||||
Some(v) => v.fetch(ctx, opt, txn, path.next()).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Where(w) => {
|
||||
let path = path.next();
|
||||
for v in v.iter_mut() {
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(v);
|
||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
||||
v.fetch(ctx, opt, path).await?;
|
||||
let cur = CursorDoc::new(None, None, v);
|
||||
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||
v.fetch(ctx, opt, txn, path).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -95,10 +96,10 @@ impl Value {
|
|||
..SelectStatement::default()
|
||||
};
|
||||
*self = stm
|
||||
.compute(ctx, opt)
|
||||
.compute(ctx, opt, txn, None)
|
||||
.await?
|
||||
.all()
|
||||
.get(ctx, opt, path.next())
|
||||
.get(ctx, opt, txn, None, path.next())
|
||||
.await?
|
||||
.flatten()
|
||||
.ok()?;
|
||||
|
@ -111,7 +112,7 @@ impl Value {
|
|||
what: Values(vec![Value::from(val)]),
|
||||
..SelectStatement::default()
|
||||
};
|
||||
*self = stm.compute(ctx, opt).await?.first();
|
||||
*self = stm.compute(ctx, opt, txn, None).await?.first();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +124,7 @@ impl Value {
|
|||
None => match self {
|
||||
// Current path part is an array
|
||||
Value::Array(v) => {
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, path));
|
||||
let futs = v.iter_mut().map(|v| v.fetch(ctx, opt, txn, path));
|
||||
try_join_all(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -137,7 +138,7 @@ impl Value {
|
|||
what: Values(vec![Value::from(val)]),
|
||||
..SelectStatement::default()
|
||||
};
|
||||
*self = stm.compute(ctx, opt).await?.first();
|
||||
*self = stm.compute(ctx, opt, txn, None).await?.first();
|
||||
Ok(())
|
||||
}
|
||||
// Ignore everything else
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::exe::try_join_all_buffered;
|
||||
use crate::sql::edges::Edges;
|
||||
|
@ -21,6 +22,8 @@ impl Value {
|
|||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
path: &[Part],
|
||||
) -> Result<Self, Error> {
|
||||
match path.first() {
|
||||
|
@ -30,15 +33,15 @@ impl Value {
|
|||
Value::Geometry(v) => match p {
|
||||
// If this is the 'type' field then continue
|
||||
Part::Field(f) if f.is_type() => {
|
||||
Value::from(v.as_type()).get(ctx, opt, path.next()).await
|
||||
Value::from(v.as_type()).get(ctx, opt, txn, doc, path.next()).await
|
||||
}
|
||||
// If this is the 'coordinates' field then continue
|
||||
Part::Field(f) if f.is_coordinates() && v.is_geometry() => {
|
||||
v.as_coordinates().get(ctx, opt, path.next()).await
|
||||
v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await
|
||||
}
|
||||
// If this is the 'geometries' field then continue
|
||||
Part::Field(f) if f.is_geometries() && v.is_collection() => {
|
||||
v.as_coordinates().get(ctx, opt, path.next()).await
|
||||
v.as_coordinates().get(ctx, opt, txn, doc, path.next()).await
|
||||
}
|
||||
// otherwise return none
|
||||
_ => Ok(Value::None),
|
||||
|
@ -54,9 +57,9 @@ impl Value {
|
|||
// Ensure the future is processed
|
||||
let fut = &opt.new_with_futures(true);
|
||||
// Get the future return value
|
||||
let val = v.compute(ctx, fut).await?;
|
||||
let val = v.compute(ctx, fut, txn, doc).await?;
|
||||
// Fetch the embedded field
|
||||
val.get(ctx, opt, path).await
|
||||
val.get(ctx, opt, txn, doc, path).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,58 +70,57 @@ impl Value {
|
|||
Some(Value::Thing(Thing {
|
||||
id: Id::Object(v),
|
||||
..
|
||||
})) => Value::Object(v.clone()).get(ctx, opt, path.next()).await,
|
||||
})) => Value::Object(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
|
||||
Some(Value::Thing(Thing {
|
||||
id: Id::Array(v),
|
||||
..
|
||||
})) => Value::Array(v.clone()).get(ctx, opt, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
||||
})) => Value::Array(v.clone()).get(ctx, opt, txn, doc, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Graph(_) => match v.rid() {
|
||||
Some(v) => Value::Thing(v).get(ctx, opt, path).await,
|
||||
Some(v) => Value::Thing(v).get(ctx, opt, txn, doc, path).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Field(f) => match v.get(f as &str) {
|
||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::All => self.get(ctx, opt, path.next()).await,
|
||||
Part::All => self.get(ctx, opt, txn, doc, path.next()).await,
|
||||
_ => Ok(Value::None),
|
||||
},
|
||||
// Current path part is an array
|
||||
Value::Array(v) => match p {
|
||||
Part::All => {
|
||||
let path = path.next();
|
||||
let futs = v.iter().map(|v| v.get(ctx, opt, path));
|
||||
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
|
||||
try_join_all_buffered(futs).await.map(Into::into)
|
||||
}
|
||||
Part::First => match v.first() {
|
||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Last => match v.last() {
|
||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Index(i) => match v.get(i.to_usize()) {
|
||||
Some(v) => v.get(ctx, opt, path.next()).await,
|
||||
Some(v) => v.get(ctx, opt, txn, doc, path.next()).await,
|
||||
None => Ok(Value::None),
|
||||
},
|
||||
Part::Where(w) => {
|
||||
let path = path.next();
|
||||
let mut a = Vec::new();
|
||||
for v in v.iter() {
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(v);
|
||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
||||
a.push(v.get(&child_ctx, opt, path).await?)
|
||||
let cur = Some(CursorDoc::new(None, None, v));
|
||||
if w.compute(ctx, opt, txn, cur.as_ref()).await?.is_truthy() {
|
||||
a.push(v.get(ctx, opt, txn, cur.as_ref(), path).await?)
|
||||
}
|
||||
}
|
||||
Ok(a.into())
|
||||
}
|
||||
_ => {
|
||||
let futs = v.iter().map(|v| v.get(ctx, opt, path));
|
||||
let futs = v.iter().map(|v| v.get(ctx, opt, txn, doc, path));
|
||||
try_join_all_buffered(futs).await.map(Into::into)
|
||||
}
|
||||
},
|
||||
|
@ -137,7 +139,11 @@ impl Value {
|
|||
what: Values(vec![Value::from(val)]),
|
||||
..SelectStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await
|
||||
stm.compute(ctx, opt, txn, None)
|
||||
.await?
|
||||
.first()
|
||||
.get(ctx, opt, txn, None, path)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,18 +171,18 @@ impl Value {
|
|||
};
|
||||
match path.len() {
|
||||
1 => stm
|
||||
.compute(ctx, opt)
|
||||
.compute(ctx, opt, txn, None)
|
||||
.await?
|
||||
.all()
|
||||
.get(ctx, opt, ID.as_ref())
|
||||
.get(ctx, opt, txn, None, ID.as_ref())
|
||||
.await?
|
||||
.flatten()
|
||||
.ok(),
|
||||
_ => stm
|
||||
.compute(ctx, opt)
|
||||
.compute(ctx, opt, txn, None)
|
||||
.await?
|
||||
.all()
|
||||
.get(ctx, opt, path.next())
|
||||
.get(ctx, opt, txn, None, path.next())
|
||||
.await?
|
||||
.flatten()
|
||||
.ok(),
|
||||
|
@ -189,7 +195,11 @@ impl Value {
|
|||
what: Values(vec![Value::from(val)]),
|
||||
..SelectStatement::default()
|
||||
};
|
||||
stm.compute(ctx, opt).await?.first().get(ctx, opt, path).await
|
||||
stm.compute(ctx, opt, txn, None)
|
||||
.await?
|
||||
.first()
|
||||
.get(ctx, opt, txn, None, path)
|
||||
.await
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -215,28 +225,28 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn get_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::default();
|
||||
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_basic() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something");
|
||||
let val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(123));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_thing() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.other");
|
||||
let val = Value::parse("{ test: { other: test:tobie, something: 123 } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
Value::from(Thing {
|
||||
|
@ -248,19 +258,19 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn get_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1]");
|
||||
let val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(456));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_array_thing() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1]");
|
||||
let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
Value::from(Thing {
|
||||
|
@ -272,46 +282,46 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn get_array_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1].age");
|
||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(36));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_array_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[*].age");
|
||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(vec![34, 36]));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_array_fields_flat() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.age");
|
||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(vec![34, 36]));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_array_where_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(res, Value::from(vec![36]));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_array_where_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
Value::from(vec![Value::from(map! {
|
||||
|
@ -322,10 +332,10 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn get_future_embedded_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let val = Value::parse("{ test: <future> { { something: [{ age: 34 }, { age: 36 }] } } }");
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let res = val.get(&ctx, &opt, &txn, None, &idi).await.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
Value::from(vec![Value::from(map! {
|
||||
|
@ -336,12 +346,12 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn get_future_embedded_field_with_reference() {
|
||||
let (mut ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let doc = Value::parse("{ name: 'Tobie', something: [{ age: 34 }, { age: 36 }] }");
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let val = Value::parse("{ test: <future> { { something: something } } }");
|
||||
ctx.add_cursor_doc(&doc);
|
||||
let res = val.get(&ctx, &opt, &idi).await.unwrap();
|
||||
let cur = CursorDoc::new(None, None, &doc);
|
||||
let res = val.get(&ctx, &opt, &txn, Some(&cur), &idi).await.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
Value::from(vec![Value::from(map! {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::err::Error;
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::part::Part;
|
||||
|
@ -11,24 +11,25 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
match self.get(ctx, opt, path).await? {
|
||||
match self.get(ctx, opt, txn, None, path).await? {
|
||||
Value::Number(v) => match val {
|
||||
Value::Number(x) => self.set(ctx, opt, path, Value::from(v + x)).await,
|
||||
Value::Number(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||
_ => Ok(()),
|
||||
},
|
||||
Value::Array(v) => match val {
|
||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(v + x)).await,
|
||||
x => self.set(ctx, opt, path, Value::from(v + x)).await,
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from(v + x)).await,
|
||||
},
|
||||
Value::None => match val {
|
||||
Value::Number(x) => {
|
||||
self.set(ctx, opt, path, Value::from(Number::from(0) + x)).await
|
||||
self.set(ctx, opt, txn, path, Value::from(Number::from(0) + x)).await
|
||||
}
|
||||
Value::Array(x) => self.set(ctx, opt, path, Value::from(x)).await,
|
||||
x => self.set(ctx, opt, path, Value::from(vec![x])).await,
|
||||
Value::Array(x) => self.set(ctx, opt, txn, path, Value::from(x)).await,
|
||||
x => self.set(ctx, opt, txn, path, Value::from(vec![x])).await,
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -45,51 +46,51 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn increment_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("other");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
let res = Value::parse("{ test: 100, other: +10 }");
|
||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn increment_number() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: 100 }");
|
||||
let res = Value::parse("{ test: 110 }");
|
||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn increment_array_number() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test[1]");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 210, 300] }");
|
||||
val.increment(&ctx, &opt, &idi, Value::from(10)).await.unwrap();
|
||||
val.increment(&ctx, &opt, &txn, &idi, Value::from(10)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn increment_array_value() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300, 200] }");
|
||||
val.increment(&ctx, &opt, &idi, Value::from(200)).await.unwrap();
|
||||
val.increment(&ctx, &opt, &txn, &idi, Value::from(200)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn increment_array_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: [100, 200, 300] }");
|
||||
let res = Value::parse("{ test: [100, 200, 300, 100, 300, 400, 500] }");
|
||||
val.increment(&ctx, &opt, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||
val.increment(&ctx, &opt, &txn, &idi, Value::parse("[100, 300, 400, 500]")).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::exe::try_join_all_buffered;
|
||||
use crate::sql::part::Next;
|
||||
|
@ -15,6 +16,7 @@ impl Value {
|
|||
&mut self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
path: &[Part],
|
||||
val: Value,
|
||||
) -> Result<(), Error> {
|
||||
|
@ -24,28 +26,28 @@ impl Value {
|
|||
// Current path part is an object
|
||||
Value::Object(v) => match p {
|
||||
Part::Graph(g) => match v.get_mut(g.to_raw().as_str()) {
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
_ => {
|
||||
let mut obj = Value::base();
|
||||
obj.set(ctx, opt, path.next(), val).await?;
|
||||
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||
v.insert(g.to_raw(), obj);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Part::Field(f) => match v.get_mut(f as &str) {
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
_ => {
|
||||
let mut obj = Value::base();
|
||||
obj.set(ctx, opt, path.next(), val).await?;
|
||||
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||
v.insert(f.to_raw(), obj);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Part::Index(i) => match v.get_mut(&i.to_string()) {
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) if v.is_some() => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
_ => {
|
||||
let mut obj = Value::base();
|
||||
obj.set(ctx, opt, path.next(), val).await?;
|
||||
obj.set(ctx, opt, txn, path.next(), val).await?;
|
||||
v.insert(i.to_string(), obj);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -56,35 +58,34 @@ impl Value {
|
|||
Value::Array(v) => match p {
|
||||
Part::All => {
|
||||
let path = path.next();
|
||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone()));
|
||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||
try_join_all_buffered(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
Part::First => match v.first_mut() {
|
||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Last => match v.last_mut() {
|
||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Index(i) => match v.get_mut(i.to_usize()) {
|
||||
Some(v) => v.set(ctx, opt, path.next(), val).await,
|
||||
Some(v) => v.set(ctx, opt, txn, path.next(), val).await,
|
||||
None => Ok(()),
|
||||
},
|
||||
Part::Where(w) => {
|
||||
let path = path.next();
|
||||
for v in v.iter_mut() {
|
||||
let mut child_ctx = Context::new(ctx);
|
||||
child_ctx.add_cursor_doc(v);
|
||||
if w.compute(&child_ctx, opt).await?.is_truthy() {
|
||||
v.set(ctx, opt, path, val.clone()).await?;
|
||||
let cur = CursorDoc::new(None, None, v);
|
||||
if w.compute(ctx, opt, txn, Some(&cur)).await?.is_truthy() {
|
||||
v.set(ctx, opt, txn, path, val.clone()).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, path, val.clone()));
|
||||
let futs = v.iter_mut().map(|v| v.set(ctx, opt, txn, path, val.clone()));
|
||||
try_join_all_buffered(futs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -92,12 +93,12 @@ impl Value {
|
|||
// Current path part is empty
|
||||
Value::Null => {
|
||||
*self = Value::base();
|
||||
self.set(ctx, opt, path, val).await
|
||||
self.set(ctx, opt, txn, path, val).await
|
||||
}
|
||||
// Current path part is empty
|
||||
Value::None => {
|
||||
*self = Value::base();
|
||||
self.set(ctx, opt, path, val).await
|
||||
self.set(ctx, opt, txn, path, val).await
|
||||
}
|
||||
// Ignore everything else
|
||||
_ => Ok(()),
|
||||
|
@ -121,141 +122,141 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn set_none() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::default();
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("999");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_empty() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::None;
|
||||
let res = Value::parse("{ test: 999 }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_blank() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something");
|
||||
let mut val = Value::None;
|
||||
let res = Value::parse("{ test: { something: 999 } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_reset() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: 999 }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_basic() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 999 } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_allow() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.allow");
|
||||
let mut val = Value::parse("{ test: { other: null } }");
|
||||
let res = Value::parse("{ test: { other: null, something: { allow: 999 } } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_wrong() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.wrong");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_other() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.other.something");
|
||||
let mut val = Value::parse("{ test: { other: null, something: 123 } }");
|
||||
let res = Value::parse("{ test: { other: { something: 999 }, something: 123 } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1]");
|
||||
let mut val = Value::parse("{ test: { something: [123, 456, 789] } }");
|
||||
let res = Value::parse("{ test: { something: [123, 999, 789] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(999)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(999)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[1].age");
|
||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[*].age");
|
||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array_fields_flat() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something.age");
|
||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = Value::parse("{ test: { something: [{ age: 21 }, { age: 21 }] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array_where_field() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35].age");
|
||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = Value::parse("{ test: { something: [{ age: 34 }, { age: 21 }] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_array_where_fields() {
|
||||
let (ctx, opt) = mock().await;
|
||||
let (ctx, opt, txn) = mock().await;
|
||||
let idi = Idiom::parse("test.something[WHERE age > 35]");
|
||||
let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }");
|
||||
let res = Value::parse("{ test: { something: [{ age: 34 }, 21] } }");
|
||||
val.set(&ctx, &opt, &idi, Value::from(21)).await.unwrap();
|
||||
val.set(&ctx, &opt, &txn, &idi, Value::from(21)).await.unwrap();
|
||||
assert_eq!(res, val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#![allow(clippy::derive_ord_xor_partial_ord)]
|
||||
|
||||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::{Options, Transaction};
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::array::Uniq;
|
||||
use crate::sql::array::{array, Array};
|
||||
|
@ -2484,21 +2485,27 @@ impl Value {
|
|||
/// Process this type returning a computed simple Value
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
|
||||
#[cfg_attr(target_arch = "wasm32", async_recursion(?Send))]
|
||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&'async_recursion CursorDoc<'_>>,
|
||||
) -> Result<Value, Error> {
|
||||
match self {
|
||||
Value::Cast(v) => v.compute(ctx, opt).await,
|
||||
Value::Thing(v) => v.compute(ctx, opt).await,
|
||||
Value::Block(v) => v.compute(ctx, opt).await,
|
||||
Value::Range(v) => v.compute(ctx, opt).await,
|
||||
Value::Param(v) => v.compute(ctx, opt).await,
|
||||
Value::Idiom(v) => v.compute(ctx, opt).await,
|
||||
Value::Array(v) => v.compute(ctx, opt).await,
|
||||
Value::Object(v) => v.compute(ctx, opt).await,
|
||||
Value::Future(v) => v.compute(ctx, opt).await,
|
||||
Value::Constant(v) => v.compute(ctx, opt).await,
|
||||
Value::Function(v) => v.compute(ctx, opt).await,
|
||||
Value::Subquery(v) => v.compute(ctx, opt).await,
|
||||
Value::Expression(v) => v.compute(ctx, opt).await,
|
||||
Value::Cast(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Thing(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Block(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Range(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Param(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Idiom(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Array(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Object(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Future(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Constant(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Function(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Subquery(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
Value::Expression(v) => v.compute(ctx, opt, txn, doc).await,
|
||||
_ => Ok(self.to_owned()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,14 +92,20 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> {
|
||||
let sql = r"
|
||||
async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(), Error> {
|
||||
let sql = format!(
|
||||
r"
|
||||
CREATE blog:1 SET content = ['Hello World!', 'Be Bop', 'Foo Bãr'];
|
||||
DEFINE ANALYZER simple TOKENIZERS blank,class;
|
||||
DEFINE INDEX blog_content ON blog FIELDS content SEARCH ANALYZER simple BM25 HIGHLIGHTS;
|
||||
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' EXPLAIN;
|
||||
";
|
||||
SELECT id, search::highlight('<em>', '</em>', 1) AS content FROM blog WHERE content @1@ 'Hello Bãr' {} EXPLAIN;
|
||||
",
|
||||
if parallel {
|
||||
"PARALLEL"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
let dbs = Datastore::new("memory").await?;
|
||||
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(&sql, &ses, None).await?;
|
||||
|
@ -141,6 +147,16 @@ async fn select_where_matches_using_index_and_arrays() -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_where_matches_using_index_and_arrays_non_parallel() -> Result<(), Error> {
|
||||
select_where_matches_using_index_and_arrays(false).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_where_matches_using_index_and_arrays_with_parallel() -> Result<(), Error> {
|
||||
select_where_matches_using_index_and_arrays(true).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
|
||||
let sql = r"
|
||||
|
|
Loading…
Reference in a new issue