diff --git a/src/dbs/dbs.rs b/src/dbs/dbs.rs index 0afc10a9..0fe21d0f 100644 --- a/src/dbs/dbs.rs +++ b/src/dbs/dbs.rs @@ -19,7 +19,7 @@ pub async fn execute(txt: &str, session: Session, vars: Variables) -> Result Result { @@ -30,7 +30,7 @@ pub async fn process(ast: Query, session: Session, vars: Variables) -> Result Result { diff --git a/src/dbs/executor.rs b/src/dbs/executor.rs index 718eaf98..184b665c 100644 --- a/src/dbs/executor.rs +++ b/src/dbs/executor.rs @@ -3,7 +3,6 @@ use crate::dbs::response::{Response, Responses}; use crate::dbs::Auth; use crate::dbs::Level; use crate::dbs::Options; -use crate::dbs::Process; use crate::dbs::Runtime; use crate::err::Error; use crate::sql::query::Query; @@ -47,7 +46,7 @@ impl Executor { todo!() } - pub fn execute(&mut self, mut ctx: Runtime, qry: Query) -> Result { + pub async fn execute(&mut self, mut ctx: Runtime, qry: Query) -> Result { // Initialise array of responses let mut out: Vec = vec![]; // Create a new options @@ -75,25 +74,25 @@ impl Executor { } // Begin a new transaction Statement::Begin(stm) => { - let res = stm.process(&ctx, &opt, self, None); + let res = stm.compute(&ctx, &opt, self, None).await; self.err = res.err(); continue; } // Cancel a running transaction Statement::Cancel(stm) => { - let res = stm.process(&ctx, &opt, self, None); + let res = stm.compute(&ctx, &opt, self, None).await; self.err = res.err(); continue; } // Commit a running transaction Statement::Commit(stm) => { - let res = stm.process(&ctx, &opt, self, None); + let res = stm.compute(&ctx, &opt, self, None).await; self.err = res.err(); continue; } // Process param definition statements Statement::Set(stm) => { - match stm.process(&ctx, &opt, self, None) { + match stm.compute(&ctx, &opt, self, None).await { Ok(val) => { let mut new = Context::new(&ctx); let key = stm.name.to_owned(); @@ -115,7 +114,7 @@ impl Executor { ctx = new.freeze(); } // Process statement - let res = stm.process(&ctx, &opt, self, None); + let res = stm.compute(&ctx, &opt, self, None).await; // Catch statement timeout if let Some(timeout) = stm.timeout() { if ctx.is_timedout() { diff --git a/src/dbs/mod.rs b/src/dbs/mod.rs index 4fb2ea40..b7beeffb 100644 --- a/src/dbs/mod.rs +++ b/src/dbs/mod.rs @@ -3,7 +3,6 @@ mod dbs; mod executor; mod iterator; mod options; -mod process; mod response; mod runtime; mod session; @@ -13,7 +12,6 @@ pub use self::dbs::*; pub use self::executor::*; pub use self::iterator::*; pub use self::options::*; -pub use self::process::*; pub use self::response::*; pub use self::runtime::*; pub use self::session::*; diff --git a/src/dbs/process.rs b/src/dbs/process.rs deleted file mode 100644 index c51e3952..00000000 --- a/src/dbs/process.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::dbs::executor::Executor; -use crate::dbs::Options; -use crate::dbs::Runtime; -use crate::err::Error; -use crate::sql::value::Value; - -pub trait Process { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result; -} diff --git a/src/sql/array.rs b/src/sql/array.rs index 570a906f..3bc63cf5 100644 --- a/src/sql/array.rs +++ b/src/sql/array.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -92,6 +91,27 @@ impl Array { } } +impl Array { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + let mut x = Vec::new(); + for v in &self.value { + match v.compute(ctx, opt, exe, doc).await { + Ok(v) => x.push(v), + Err(e) => return Err(e), + }; + } + Ok(Value::Array(Array { + value: x, + })) + } +} + impl fmt::Display for Array { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -102,29 +122,6 @@ impl fmt::Display for Array { } } -impl dbs::Process for Array { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - self.value - .iter() - .map(|v| match v.process(ctx, opt, exe, doc) { - Ok(v) => Ok(v), - Err(e) => Err(e), - }) - .collect::, _>>() - .map(|v| { - Value::Array(Array { - value: v, - }) - }) - } -} - impl Serialize for Array { fn serialize(&self, serializer: S) -> Result where @@ -190,6 +187,38 @@ impl ops::Sub for Array { // ------------------------------ +pub trait Abolish { + fn abolish(&mut self, f: F) + where + F: FnMut(usize) -> bool; +} + +impl Abolish for Vec { + fn abolish(&mut self, mut f: F) + where + F: FnMut(usize) -> bool, + { + let len = self.len(); + let mut del = 0; + { + let v = &mut **self; + + for i in 0..len { + if f(i) { + del += 1; + } else if del > 0 { + v.swap(i - del, i); + } + } + } + if del > 0 { + self.truncate(len - del); + } + } +} + +// ------------------------------ + pub trait Uniq { fn uniq(self) -> Vec; } diff --git a/src/sql/expression.rs b/src/sql/expression.rs index d204a2c1..0e30da3c 100644 --- a/src/sql/expression.rs +++ b/src/sql/expression.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -28,21 +27,15 @@ impl Default for Expression { } } -impl fmt::Display for Expression { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {} {}", self.l, self.o, self.r) - } -} - -impl dbs::Process for Expression { - fn process( +impl Expression { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { - let l = self.l.process(ctx, opt, exe, doc)?; + let l = self.l.compute(ctx, opt, exe, doc).await?; match self.o { Operator::Or => match l.is_truthy() { true => return Ok(l), // No need to continue @@ -54,7 +47,7 @@ impl dbs::Process for Expression { }, _ => {} // Continue } - let r = self.r.process(ctx, opt, exe, doc)?; + let r = self.r.compute(ctx, opt, exe, doc).await?; match self.o { Operator::Or => fnc::operate::or(l, r), Operator::And => fnc::operate::and(l, r), @@ -91,6 +84,12 @@ impl dbs::Process for Expression { } } +impl fmt::Display for Expression { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {} {}", self.l, self.o, self.r) + } +} + pub fn expression(i: &str) -> IResult<&str, Expression> { let (i, l) = single(i)?; let (i, o) = operator(i)?; diff --git a/src/sql/function.rs b/src/sql/function.rs index e0439f29..e6429e91 100644 --- a/src/sql/function.rs +++ b/src/sql/function.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -31,6 +30,42 @@ impl PartialOrd for Function { } } +impl Function { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + match self { + Function::Future(ref e) => match opt.futures { + true => { + let a = e.compute(ctx, opt, exe, doc).await?; + fnc::future::run(ctx, a) + } + false => Ok(self.to_owned().into()), + }, + Function::Script(ref s) => { + let a = s.to_owned(); + fnc::script::run(ctx, a) + } + Function::Cast(ref s, ref e) => { + let a = e.compute(ctx, opt, exe, doc).await?; + fnc::cast::run(ctx, s, a) + } + Function::Normal(ref s, ref e) => { + let mut a: Vec = vec![]; + for v in e { + let v = v.compute(ctx, opt, exe, doc).await?; + a.push(v); + } + fnc::run(ctx, s, a) + } + } + } +} + impl fmt::Display for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -47,42 +82,6 @@ impl fmt::Display for Function { } } -impl dbs::Process for Function { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - match self { - Function::Future(ref e) => match opt.futures { - true => { - let a = e.process(ctx, opt, exe, doc)?; - fnc::future::run(ctx, a) - } - false => Ok(self.to_owned().into()), - }, - Function::Script(ref s) => { - let a = s.to_owned(); - fnc::script::run(ctx, a) - } - Function::Cast(ref s, ref e) => { - let a = e.process(ctx, opt, exe, doc)?; - fnc::cast::run(ctx, s, a) - } - Function::Normal(ref s, ref e) => { - let mut a: Vec = vec![]; - for v in e { - let v = v.process(ctx, opt, exe, doc)?; - a.push(v); - } - fnc::run(ctx, s, a) - } - } - } -} - pub fn function(i: &str) -> IResult<&str, Function> { alt((casts, langs, future, normal))(i) } @@ -397,7 +396,7 @@ mod tests { let res = function(sql); assert!(res.is_ok()); let out = res.unwrap().1; - assert_eq!("1.2345", format!("{}", out)); + assert_eq!(" 1.2345", format!("{}", out)); assert_eq!(out, Function::Cast(String::from("int"), 1.2345.into())); } @@ -407,7 +406,7 @@ mod tests { let res = function(sql); assert!(res.is_ok()); let out = res.unwrap().1; - assert_eq!("1.2345", format!("{}", out)); + assert_eq!(" 1.2345", format!("{}", out)); assert_eq!(out, Function::Cast(String::from("string"), 1.2345.into())); } diff --git a/src/sql/idiom.rs b/src/sql/idiom.rs index b85db6e1..2a1b5974 100644 --- a/src/sql/idiom.rs +++ b/src/sql/idiom.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -50,6 +49,23 @@ impl Idiom { } } +impl Idiom { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + match doc { + // There is a current document + Some(v) => v.get(ctx, opt, exe, self).await.ok(), + // There isn't any document + None => Ok(Value::None), + } + } +} + impl fmt::Display for Idiom { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -68,23 +84,6 @@ impl fmt::Display for Idiom { } } -impl dbs::Process for Idiom { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - match doc { - // There is a current document - Some(v) => v.get(ctx, opt, exe, self).ok(), - // There isn't any document - None => Ok(Value::None), - } - } -} - // Used in a DEFINE FIELD and DEFINE INDEX clause pub fn local(i: &str) -> IResult<&str, Idiom> { let (i, p) = first(i)?; diff --git a/src/sql/object.rs b/src/sql/object.rs index 1f774931..46c3d0e6 100644 --- a/src/sql/object.rs +++ b/src/sql/object.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -53,6 +52,27 @@ impl Object { } } +impl Object { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + let mut x = BTreeMap::new(); + for (k, v) in &self.value { + match v.compute(ctx, opt, exe, doc).await { + Ok(v) => x.insert(k.clone(), v), + Err(e) => return Err(e), + }; + } + Ok(Value::Object(Object { + value: x, + })) + } +} + impl fmt::Display for Object { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -67,29 +87,6 @@ impl fmt::Display for Object { } } -impl dbs::Process for Object { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - self.value - .iter() - .map(|(k, v)| match v.process(ctx, opt, exe, doc) { - Ok(v) => Ok((k.clone(), v)), - Err(e) => Err(e), - }) - .collect::, _>>() - .map(|v| { - Value::Object(Object { - value: v, - }) - }) - } -} - impl Serialize for Object { fn serialize(&self, serializer: S) -> Result where diff --git a/src/sql/param.rs b/src/sql/param.rs index ac8600a2..79921b96 100644 --- a/src/sql/param.rs +++ b/src/sql/param.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -26,17 +25,11 @@ impl From for Param { } } -impl fmt::Display for Param { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "${}", &self.name) - } -} - -impl dbs::Process for Param { - fn process( +impl Param { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -47,9 +40,9 @@ impl dbs::Process for Param { // The base variable exists Some(v) => { // Process the paramater value - let res = v.process(ctx, opt, exe, doc)?; + let res = v.compute(ctx, opt, exe, doc).await?; // Return the desired field - res.get(ctx, opt, exe, &self.name.next()).ok() + res.get(ctx, opt, exe, &self.name.next()).await.ok() } // The base variable does not exist None => Ok(Value::None), @@ -59,6 +52,12 @@ impl dbs::Process for Param { } } +impl fmt::Display for Param { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "${}", &self.name) + } +} + pub fn param(i: &str) -> IResult<&str, Param> { let (i, _) = tag("$")(i)?; let (i, v) = idiom::param(i)?; diff --git a/src/sql/statement.rs b/src/sql/statement.rs index fcbbc67c..403bd281 100644 --- a/src/sql/statement.rs +++ b/src/sql/statement.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -111,6 +110,38 @@ impl Statement { } } +impl Statement { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + match *self { + Statement::Use(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Set(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Info(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Live(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Kill(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Begin(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Cancel(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Commit(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Output(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Ifelse(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Select(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Create(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Update(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Relate(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Delete(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Insert(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Define(ref v) => v.compute(ctx, opt, exe, doc).await, + Statement::Remove(ref v) => v.compute(ctx, opt, exe, doc).await, + _ => unreachable!(), + } + } +} + impl fmt::Display for Statement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -137,38 +168,6 @@ impl fmt::Display for Statement { } } -impl dbs::Process for Statement { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - match *self { - Statement::Use(ref v) => v.process(ctx, opt, exe, doc), - Statement::Set(ref v) => v.process(ctx, opt, exe, doc), - Statement::Info(ref v) => v.process(ctx, opt, exe, doc), - Statement::Live(ref v) => v.process(ctx, opt, exe, doc), - Statement::Kill(ref v) => v.process(ctx, opt, exe, doc), - Statement::Begin(ref v) => v.process(ctx, opt, exe, doc), - Statement::Cancel(ref v) => v.process(ctx, opt, exe, doc), - Statement::Commit(ref v) => v.process(ctx, opt, exe, doc), - Statement::Output(ref v) => v.process(ctx, opt, exe, doc), - Statement::Ifelse(ref v) => v.process(ctx, opt, exe, doc), - Statement::Select(ref v) => v.process(ctx, opt, exe, doc), - Statement::Create(ref v) => v.process(ctx, opt, exe, doc), - Statement::Update(ref v) => v.process(ctx, opt, exe, doc), - Statement::Relate(ref v) => v.process(ctx, opt, exe, doc), - Statement::Delete(ref v) => v.process(ctx, opt, exe, doc), - Statement::Insert(ref v) => v.process(ctx, opt, exe, doc), - Statement::Define(ref v) => v.process(ctx, opt, exe, doc), - Statement::Remove(ref v) => v.process(ctx, opt, exe, doc), - _ => unreachable!(), - } - } -} - pub fn statement(i: &str) -> IResult<&str, Statement> { delimited( mightbespace, diff --git a/src/sql/statements/begin.rs b/src/sql/statements/begin.rs index 80c587ed..f6b98b86 100644 --- a/src/sql/statements/begin.rs +++ b/src/sql/statements/begin.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -16,17 +15,11 @@ use std::fmt; #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct BeginStatement; -impl fmt::Display for BeginStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "BEGIN TRANSACTION") - } -} - -impl dbs::Process for BeginStatement { - fn process( +impl BeginStatement { + pub async fn compute( &self, _ctx: &Runtime, - _opt: &Options, + _opt: &Options<'_>, _exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -34,6 +27,12 @@ impl dbs::Process for BeginStatement { } } +impl fmt::Display for BeginStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "BEGIN TRANSACTION") + } +} + pub fn begin(i: &str) -> IResult<&str, BeginStatement> { alt((begin_query, begin_basic))(i) } diff --git a/src/sql/statements/cancel.rs b/src/sql/statements/cancel.rs index 0188d88e..9b0e8cef 100644 --- a/src/sql/statements/cancel.rs +++ b/src/sql/statements/cancel.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -16,17 +15,11 @@ use std::fmt; #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct CancelStatement; -impl fmt::Display for CancelStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CANCEL TRANSACTION") - } -} - -impl dbs::Process for CancelStatement { - fn process( +impl CancelStatement { + pub async fn compute( &self, _ctx: &Runtime, - _opt: &Options, + _opt: &Options<'_>, _exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -34,6 +27,12 @@ impl dbs::Process for CancelStatement { } } +impl fmt::Display for CancelStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CANCEL TRANSACTION") + } +} + pub fn cancel(i: &str) -> IResult<&str, CancelStatement> { alt((cancel_query, cancel_basic))(i) } diff --git a/src/sql/statements/commit.rs b/src/sql/statements/commit.rs index 00af5f79..b88cf373 100644 --- a/src/sql/statements/commit.rs +++ b/src/sql/statements/commit.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -16,17 +15,11 @@ use std::fmt; #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct CommitStatement; -impl fmt::Display for CommitStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "COMMIT TRANSACTION") - } -} - -impl dbs::Process for CommitStatement { - fn process( +impl CommitStatement { + pub async fn compute( &self, _ctx: &Runtime, - _opt: &Options, + _opt: &Options<'_>, _exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -34,6 +27,12 @@ impl dbs::Process for CommitStatement { } } +impl fmt::Display for CommitStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "COMMIT TRANSACTION") + } +} + pub fn commit(i: &str) -> IResult<&str, CommitStatement> { alt((commit_query, commit_basic))(i) } diff --git a/src/sql/statements/create.rs b/src/sql/statements/create.rs index 84e7c1a7..464f075f 100644 --- a/src/sql/statements/create.rs +++ b/src/sql/statements/create.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -28,27 +27,11 @@ pub struct CreateStatement { pub timeout: Option, } -impl fmt::Display for CreateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CREATE {}", self.what)?; - if let Some(ref v) = self.data { - write!(f, " {}", v)? - } - if let Some(ref v) = self.output { - write!(f, " {}", v)? - } - if let Some(ref v) = self.timeout { - write!(f, " {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for CreateStatement { - fn process( +impl CreateStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -62,7 +45,7 @@ impl dbs::Process for CreateStatement { let opt = &opt.futures(false); // Loop over the create targets for w in self.what.0.iter() { - match w.process(ctx, opt, exe, doc)? { + match w.compute(ctx, opt, exe, doc).await? { Value::Table(v) => { i.process_table(ctx, exe, v); } @@ -90,6 +73,22 @@ impl dbs::Process for CreateStatement { } } +impl fmt::Display for CreateStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CREATE {}", self.what)?; + if let Some(ref v) = self.data { + write!(f, " {}", v)? + } + if let Some(ref v) = self.output { + write!(f, " {}", v)? + } + if let Some(ref v) = self.timeout { + write!(f, " {}", v)? + } + Ok(()) + } +} + pub fn create(i: &str) -> IResult<&str, CreateStatement> { let (i, _) = tag_no_case("CREATE")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/define.rs b/src/sql/statements/define.rs index f8e97ea6..0df19e6b 100644 --- a/src/sql/statements/define.rs +++ b/src/sql/statements/define.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Level; use crate::dbs::Options; @@ -38,6 +37,28 @@ pub enum DefineStatement { Index(DefineIndexStatement), } +impl DefineStatement { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + match self { + DefineStatement::Namespace(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Database(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Login(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Token(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Scope(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Table(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Event(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Field(ref v) => v.compute(ctx, opt, exe, doc).await, + DefineStatement::Index(ref v) => v.compute(ctx, opt, exe, doc).await, + } + } +} + impl fmt::Display for DefineStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -54,28 +75,6 @@ impl fmt::Display for DefineStatement { } } -impl dbs::Process for DefineStatement { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - match self { - DefineStatement::Namespace(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Database(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Login(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Token(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Scope(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Table(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Event(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Field(ref v) => v.process(ctx, opt, exe, doc), - DefineStatement::Index(ref v) => v.process(ctx, opt, exe, doc), - } - } -} - pub fn define(i: &str) -> IResult<&str, DefineStatement> { alt(( map(namespace, |v| DefineStatement::Namespace(v)), @@ -99,17 +98,11 @@ pub struct DefineNamespaceStatement { pub name: String, } -impl fmt::Display for DefineNamespaceStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE NAMESPACE {}", self.name) - } -} - -impl dbs::Process for DefineNamespaceStatement { - fn process( +impl DefineNamespaceStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -120,6 +113,12 @@ impl dbs::Process for DefineNamespaceStatement { } } +impl fmt::Display for DefineNamespaceStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DEFINE NAMESPACE {}", self.name) + } +} + fn namespace(i: &str) -> IResult<&str, DefineNamespaceStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -143,17 +142,11 @@ pub struct DefineDatabaseStatement { pub name: String, } -impl fmt::Display for DefineDatabaseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE DATABASE {}", self.name) - } -} - -impl dbs::Process for DefineDatabaseStatement { - fn process( +impl DefineDatabaseStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -164,6 +157,12 @@ impl dbs::Process for DefineDatabaseStatement { } } +impl fmt::Display for DefineDatabaseStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DEFINE DATABASE {}", self.name) + } +} + fn database(i: &str) -> IResult<&str, DefineDatabaseStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -192,24 +191,11 @@ pub struct DefineLoginStatement { pub hash: Option, } -impl fmt::Display for DefineLoginStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE LOGIN {} ON {}", self.name, self.base)?; - if let Some(ref v) = self.pass { - write!(f, " PASSWORD {}", v)? - } - if let Some(ref v) = self.hash { - write!(f, " PASSHASH {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for DefineLoginStatement { - fn process( +impl DefineLoginStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -224,6 +210,19 @@ impl dbs::Process for DefineLoginStatement { } } +impl fmt::Display for DefineLoginStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DEFINE LOGIN {} ON {}", self.name, self.base)?; + if let Some(ref v) = self.pass { + write!(f, " PASSWORD {}", v)? + } + if let Some(ref v) = self.hash { + write!(f, " PASSHASH {}", v)? + } + Ok(()) + } +} + fn login(i: &str) -> IResult<&str, DefineLoginStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -290,21 +289,11 @@ pub struct DefineTokenStatement { pub code: String, } -impl fmt::Display for DefineTokenStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "DEFINE TOKEN {} ON {} TYPE {} VALUE {}", - self.name, self.base, self.kind, self.code - ) - } -} - -impl dbs::Process for DefineTokenStatement { - fn process( +impl DefineTokenStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -319,6 +308,16 @@ impl dbs::Process for DefineTokenStatement { } } +impl fmt::Display for DefineTokenStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "DEFINE TOKEN {} ON {} TYPE {} VALUE {}", + self.name, self.base, self.kind, self.code + ) + } +} + fn token(i: &str) -> IResult<&str, DefineTokenStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -365,6 +364,21 @@ pub struct DefineScopeStatement { pub connect: Option, } +impl DefineScopeStatement { + pub async fn compute( + &self, + _ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + _doc: Option<&Value>, + ) -> Result { + // Allowed to run? + exe.check(opt, Level::Db)?; + // Continue + todo!() + } +} + impl fmt::Display for DefineScopeStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DEFINE SCOPE {}", self.name)?; @@ -384,21 +398,6 @@ impl fmt::Display for DefineScopeStatement { } } -impl dbs::Process for DefineScopeStatement { - fn process( - &self, - _ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - _doc: Option<&Value>, - ) -> Result { - // Allowed to run? - exe.check(opt, Level::Db)?; - // Continue - todo!() - } -} - fn scope(i: &str) -> IResult<&str, DefineScopeStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -488,6 +487,21 @@ pub struct DefineTableStatement { pub permissions: Permissions, } +impl DefineTableStatement { + pub async fn compute( + &self, + _ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + _doc: Option<&Value>, + ) -> Result { + // Allowed to run? + exe.check(opt, Level::Db)?; + // Continue + todo!() + } +} + impl fmt::Display for DefineTableStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DEFINE TABLE {}", self.name)?; @@ -508,21 +522,6 @@ impl fmt::Display for DefineTableStatement { } } -impl dbs::Process for DefineTableStatement { - fn process( - &self, - _ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - _doc: Option<&Value>, - ) -> Result { - // Allowed to run? - exe.check(opt, Level::Db)?; - // Continue - todo!() - } -} - fn table(i: &str) -> IResult<&str, DefineTableStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -619,21 +618,11 @@ pub struct DefineEventStatement { pub then: Values, } -impl fmt::Display for DefineEventStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "DEFINE EVENT {} ON {} WHEN {} THEN {}", - self.name, self.what, self.when, self.then - ) - } -} - -impl dbs::Process for DefineEventStatement { - fn process( +impl DefineEventStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -644,6 +633,16 @@ impl dbs::Process for DefineEventStatement { } } +impl fmt::Display for DefineEventStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "DEFINE EVENT {} ON {} WHEN {} THEN {}", + self.name, self.what, self.when, self.then + ) + } +} + fn event(i: &str) -> IResult<&str, DefineEventStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -693,6 +692,21 @@ pub struct DefineFieldStatement { pub permissions: Permissions, } +impl DefineFieldStatement { + pub async fn compute( + &self, + _ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + _doc: Option<&Value>, + ) -> Result { + // Allowed to run? + exe.check(opt, Level::Db)?; + // Continue + todo!() + } +} + impl fmt::Display for DefineFieldStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DEFINE FIELD {} ON {}", self.name, self.what)?; @@ -710,21 +724,6 @@ impl fmt::Display for DefineFieldStatement { } } -impl dbs::Process for DefineFieldStatement { - fn process( - &self, - _ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - _doc: Option<&Value>, - ) -> Result { - // Allowed to run? - exe.check(opt, Level::Db)?; - // Continue - todo!() - } -} - fn field(i: &str) -> IResult<&str, DefineFieldStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; @@ -832,21 +831,11 @@ pub struct DefineIndexStatement { pub uniq: bool, } -impl fmt::Display for DefineIndexStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DEFINE INDEX {} ON {} COLUMNS {}", self.name, self.what, self.cols)?; - if self.uniq == true { - write!(f, " UNIQUE")? - } - Ok(()) - } -} - -impl dbs::Process for DefineIndexStatement { - fn process( +impl DefineIndexStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -857,6 +846,16 @@ impl dbs::Process for DefineIndexStatement { } } +impl fmt::Display for DefineIndexStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DEFINE INDEX {} ON {} COLUMNS {}", self.name, self.what, self.cols)?; + if self.uniq == true { + write!(f, " UNIQUE")? + } + Ok(()) + } +} + fn index(i: &str) -> IResult<&str, DefineIndexStatement> { let (i, _) = tag_no_case("DEFINE")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/delete.rs b/src/sql/statements/delete.rs index dcf5fc6e..946ba7cd 100644 --- a/src/sql/statements/delete.rs +++ b/src/sql/statements/delete.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -29,27 +28,11 @@ pub struct DeleteStatement { pub timeout: Option, } -impl fmt::Display for DeleteStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DELETE {}", self.what)?; - if let Some(ref v) = self.cond { - write!(f, " {}", v)? - } - if let Some(ref v) = self.output { - write!(f, " {}", v)? - } - if let Some(ref v) = self.timeout { - write!(f, " {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for DeleteStatement { - fn process( +impl DeleteStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -63,7 +46,7 @@ impl dbs::Process for DeleteStatement { let opt = &opt.futures(false); // Loop over the delete targets for w in self.what.0.iter() { - match w.process(ctx, opt, exe, doc)? { + match w.compute(ctx, opt, exe, doc).await? { Value::Table(v) => { i.process_table(ctx, exe, v); } @@ -91,6 +74,22 @@ impl dbs::Process for DeleteStatement { } } +impl fmt::Display for DeleteStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DELETE {}", self.what)?; + if let Some(ref v) = self.cond { + write!(f, " {}", v)? + } + if let Some(ref v) = self.output { + write!(f, " {}", v)? + } + if let Some(ref v) = self.timeout { + write!(f, " {}", v)? + } + Ok(()) + } +} + pub fn delete(i: &str) -> IResult<&str, DeleteStatement> { let (i, _) = tag_no_case("DELETE")(i)?; let (i, _) = opt(tuple((shouldbespace, tag_no_case("FROM"))))(i)?; diff --git a/src/sql/statements/ifelse.rs b/src/sql/statements/ifelse.rs index 2bba42c7..b80e905d 100644 --- a/src/sql/statements/ifelse.rs +++ b/src/sql/statements/ifelse.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -19,6 +18,27 @@ pub struct IfelseStatement { pub close: Option, } +impl IfelseStatement { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + for (ref cond, ref then) in &self.exprs { + let v = cond.compute(ctx, opt, exe, doc).await?; + if v.is_truthy() { + return then.compute(ctx, opt, exe, doc).await; + } + } + match self.close { + Some(ref v) => v.compute(ctx, opt, exe, doc).await, + None => Ok(Value::None), + } + } +} + impl fmt::Display for IfelseStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -38,27 +58,6 @@ impl fmt::Display for IfelseStatement { } } -impl dbs::Process for IfelseStatement { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - for (ref cond, ref then) in &self.exprs { - let v = cond.process(ctx, opt, exe, doc)?; - if v.is_truthy() { - return then.process(ctx, opt, exe, doc); - } - } - match self.close { - Some(ref v) => v.process(ctx, opt, exe, doc), - None => Ok(Value::None), - } - } -} - pub fn ifelse(i: &str) -> IResult<&str, IfelseStatement> { let (i, exprs) = separated_list0(split, exprs)(i)?; let (i, close) = opt(close)(i)?; diff --git a/src/sql/statements/info.rs b/src/sql/statements/info.rs index 131ec697..a075652d 100644 --- a/src/sql/statements/info.rs +++ b/src/sql/statements/info.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Level; use crate::dbs::Options; @@ -21,22 +20,11 @@ pub enum InfoStatement { Table(String), } -impl fmt::Display for InfoStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - InfoStatement::Namespace => write!(f, "INFO FOR NAMESPACE"), - InfoStatement::Database => write!(f, "INFO FOR DATABASE"), - InfoStatement::Scope(ref s) => write!(f, "INFO FOR SCOPE {}", s), - InfoStatement::Table(ref t) => write!(f, "INFO FOR TABLE {}", t), - } - } -} - -impl dbs::Process for InfoStatement { - fn process( +impl InfoStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -52,6 +40,17 @@ impl dbs::Process for InfoStatement { } } +impl fmt::Display for InfoStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + InfoStatement::Namespace => write!(f, "INFO FOR NAMESPACE"), + InfoStatement::Database => write!(f, "INFO FOR DATABASE"), + InfoStatement::Scope(ref s) => write!(f, "INFO FOR SCOPE {}", s), + InfoStatement::Table(ref t) => write!(f, "INFO FOR TABLE {}", t), + } + } +} + pub fn info(i: &str) -> IResult<&str, InfoStatement> { let (i, _) = tag_no_case("INFO")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/insert.rs b/src/sql/statements/insert.rs index f1c9b000..7660517b 100644 --- a/src/sql/statements/insert.rs +++ b/src/sql/statements/insert.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -32,28 +31,11 @@ pub struct InsertStatement { pub timeout: Option, } -impl fmt::Display for InsertStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "INSERT")?; - if self.ignore { - write!(f, " IGNORE")? - } - write!(f, " INTO {} {}", self.into, self.data)?; - if let Some(ref v) = self.output { - write!(f, " {}", v)? - } - if let Some(ref v) = self.timeout { - write!(f, " {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for InsertStatement { - fn process( +impl InsertStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -71,7 +53,7 @@ impl dbs::Process for InsertStatement { Data::ValuesExpression(_) => { todo!() // TODO: loop over each } - Data::SingleExpression(v) => match v.process(ctx, opt, exe, doc)? { + Data::SingleExpression(v) => match v.compute(ctx, opt, exe, doc).await? { Value::Array(v) => { i.process_array(ctx, exe, v); } @@ -91,6 +73,23 @@ impl dbs::Process for InsertStatement { } } +impl fmt::Display for InsertStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "INSERT")?; + if self.ignore { + write!(f, " IGNORE")? + } + write!(f, " INTO {} {}", self.into, self.data)?; + if let Some(ref v) = self.output { + write!(f, " {}", v)? + } + if let Some(ref v) = self.timeout { + write!(f, " {}", v)? + } + Ok(()) + } +} + pub fn insert(i: &str) -> IResult<&str, InsertStatement> { let (i, _) = tag_no_case("INSERT")(i)?; let (i, ignore) = opt(preceded(shouldbespace, tag_no_case("IGNORE")))(i)?; diff --git a/src/sql/statements/kill.rs b/src/sql/statements/kill.rs index b2c9e77e..b426b4e0 100644 --- a/src/sql/statements/kill.rs +++ b/src/sql/statements/kill.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -16,17 +15,11 @@ pub struct KillStatement { pub id: Ident, } -impl fmt::Display for KillStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "KILL {}", self.id) - } -} - -impl dbs::Process for KillStatement { - fn process( +impl KillStatement { + pub async fn compute( &self, _ctx: &Runtime, - _opt: &Options, + _opt: &Options<'_>, _exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -34,6 +27,12 @@ impl dbs::Process for KillStatement { } } +impl fmt::Display for KillStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "KILL {}", self.id) + } +} + pub fn kill(i: &str) -> IResult<&str, KillStatement> { let (i, _) = tag_no_case("KILL")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/live.rs b/src/sql/statements/live.rs index 806c56c3..b99edcb0 100644 --- a/src/sql/statements/live.rs +++ b/src/sql/statements/live.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -26,6 +25,18 @@ pub struct LiveStatement { pub fetch: Option, } +impl LiveStatement { + pub async fn compute( + &self, + _ctx: &Runtime, + _opt: &Options<'_>, + _exe: &mut Executor, + _doc: Option<&Value>, + ) -> Result { + todo!() + } +} + impl fmt::Display for LiveStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "LIVE SELECT {} FROM {}", self.expr, self.what)?; @@ -39,18 +50,6 @@ impl fmt::Display for LiveStatement { } } -impl dbs::Process for LiveStatement { - fn process( - &self, - _ctx: &Runtime, - _opt: &Options, - _exe: &mut Executor, - _doc: Option<&Value>, - ) -> Result { - todo!() - } -} - pub fn live(i: &str) -> IResult<&str, LiveStatement> { let (i, _) = tag_no_case("LIVE SELECT")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/option.rs b/src/sql/statements/option.rs index 71b4c822..592bf910 100644 --- a/src/sql/statements/option.rs +++ b/src/sql/statements/option.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Level; use crate::dbs::Options; @@ -23,21 +22,11 @@ pub struct OptionStatement { pub what: bool, } -impl fmt::Display for OptionStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.what { - write!(f, "OPTION {}", self.name) - } else { - write!(f, "OPTION {} = FALSE", self.name) - } - } -} - -impl dbs::Process for OptionStatement { - fn process( +impl OptionStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -48,6 +37,16 @@ impl dbs::Process for OptionStatement { } } +impl fmt::Display for OptionStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.what { + write!(f, "OPTION {}", self.name) + } else { + write!(f, "OPTION {} = FALSE", self.name) + } + } +} + pub fn option(i: &str) -> IResult<&str, OptionStatement> { let (i, _) = tag_no_case("OPTION")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/output.rs b/src/sql/statements/output.rs index 99faf756..d5d9e787 100644 --- a/src/sql/statements/output.rs +++ b/src/sql/statements/output.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -15,24 +14,24 @@ pub struct OutputStatement { pub what: Value, } -impl fmt::Display for OutputStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RETURN {}", self.what) - } -} - -impl dbs::Process for OutputStatement { - fn process( +impl OutputStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { // Ensure futures are processed let opt = &opt.futures(true); // Process the output value - self.what.process(ctx, opt, exe, doc) + self.what.compute(ctx, opt, exe, doc).await + } +} + +impl fmt::Display for OutputStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RETURN {}", self.what) } } diff --git a/src/sql/statements/relate.rs b/src/sql/statements/relate.rs index 46ddc3bc..9db97626 100644 --- a/src/sql/statements/relate.rs +++ b/src/sql/statements/relate.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -35,30 +34,11 @@ pub struct RelateStatement { pub timeout: Option, } -impl fmt::Display for RelateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RELATE {} -> {} -> {}", self.from, self.kind, self.with)?; - if self.uniq { - write!(f, " UNIQUE")? - } - if let Some(ref v) = self.data { - write!(f, " {}", v)? - } - if let Some(ref v) = self.output { - write!(f, " {}", v)? - } - if let Some(ref v) = self.timeout { - write!(f, " {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for RelateStatement { - fn process( +impl RelateStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -70,7 +50,7 @@ impl dbs::Process for RelateStatement { let opt = &opt.futures(false); // Loop over the select targets for f in self.from.0.iter() { - match f.process(ctx, opt, exe, doc)? { + match f.compute(ctx, opt, exe, doc).await? { Value::Table(v) => { i.process_table(ctx, exe, v); } @@ -98,6 +78,25 @@ impl dbs::Process for RelateStatement { } } +impl fmt::Display for RelateStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RELATE {} -> {} -> {}", self.from, self.kind, self.with)?; + if self.uniq { + write!(f, " UNIQUE")? + } + if let Some(ref v) = self.data { + write!(f, " {}", v)? + } + if let Some(ref v) = self.output { + write!(f, " {}", v)? + } + if let Some(ref v) = self.timeout { + write!(f, " {}", v)? + } + Ok(()) + } +} + pub fn relate(i: &str) -> IResult<&str, RelateStatement> { let (i, _) = tag_no_case("RELATE")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/remove.rs b/src/sql/statements/remove.rs index a032d726..a3b097ae 100644 --- a/src/sql/statements/remove.rs +++ b/src/sql/statements/remove.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Level; use crate::dbs::Options; @@ -29,6 +28,28 @@ pub enum RemoveStatement { Index(RemoveIndexStatement), } +impl RemoveStatement { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + match self { + RemoveStatement::Namespace(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Database(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Login(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Token(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Scope(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Table(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Event(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Field(ref v) => v.compute(ctx, opt, exe, doc).await, + RemoveStatement::Index(ref v) => v.compute(ctx, opt, exe, doc).await, + } + } +} + impl fmt::Display for RemoveStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -45,28 +66,6 @@ impl fmt::Display for RemoveStatement { } } -impl dbs::Process for RemoveStatement { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - match self { - RemoveStatement::Namespace(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Database(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Login(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Token(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Scope(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Table(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Event(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Field(ref v) => v.process(ctx, opt, exe, doc), - RemoveStatement::Index(ref v) => v.process(ctx, opt, exe, doc), - } - } -} - pub fn remove(i: &str) -> IResult<&str, RemoveStatement> { alt(( map(namespace, |v| RemoveStatement::Namespace(v)), @@ -90,17 +89,11 @@ pub struct RemoveNamespaceStatement { pub name: String, } -impl fmt::Display for RemoveNamespaceStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE NAMESPACE {}", self.name) - } -} - -impl dbs::Process for RemoveNamespaceStatement { - fn process( +impl RemoveNamespaceStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -111,6 +104,12 @@ impl dbs::Process for RemoveNamespaceStatement { } } +impl fmt::Display for RemoveNamespaceStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE NAMESPACE {}", self.name) + } +} + fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -134,17 +133,11 @@ pub struct RemoveDatabaseStatement { pub name: String, } -impl fmt::Display for RemoveDatabaseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE DATABASE {}", self.name) - } -} - -impl dbs::Process for RemoveDatabaseStatement { - fn process( +impl RemoveDatabaseStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -155,6 +148,12 @@ impl dbs::Process for RemoveDatabaseStatement { } } +impl fmt::Display for RemoveDatabaseStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE DATABASE {}", self.name) + } +} + fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -179,17 +178,11 @@ pub struct RemoveLoginStatement { pub base: Base, } -impl fmt::Display for RemoveLoginStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE LOGIN {} ON {}", self.name, self.base) - } -} - -impl dbs::Process for RemoveLoginStatement { - fn process( +impl RemoveLoginStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -204,6 +197,12 @@ impl dbs::Process for RemoveLoginStatement { } } +impl fmt::Display for RemoveLoginStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE LOGIN {} ON {}", self.name, self.base) + } +} + fn login(i: &str) -> IResult<&str, RemoveLoginStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -233,17 +232,11 @@ pub struct RemoveTokenStatement { pub base: Base, } -impl fmt::Display for RemoveTokenStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base) - } -} - -impl dbs::Process for RemoveTokenStatement { - fn process( +impl RemoveTokenStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -258,6 +251,12 @@ impl dbs::Process for RemoveTokenStatement { } } +impl fmt::Display for RemoveTokenStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE TOKEN {} ON {}", self.name, self.base) + } +} + fn token(i: &str) -> IResult<&str, RemoveTokenStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -286,17 +285,11 @@ pub struct RemoveScopeStatement { pub name: String, } -impl fmt::Display for RemoveScopeStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE SCOPE {}", self.name) - } -} - -impl dbs::Process for RemoveScopeStatement { - fn process( +impl RemoveScopeStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -307,6 +300,12 @@ impl dbs::Process for RemoveScopeStatement { } } +impl fmt::Display for RemoveScopeStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE SCOPE {}", self.name) + } +} + fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -330,17 +329,11 @@ pub struct RemoveTableStatement { pub name: String, } -impl fmt::Display for RemoveTableStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE TABLE {}", self.name) - } -} - -impl dbs::Process for RemoveTableStatement { - fn process( +impl RemoveTableStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -351,6 +344,12 @@ impl dbs::Process for RemoveTableStatement { } } +impl fmt::Display for RemoveTableStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE TABLE {}", self.name) + } +} + fn table(i: &str) -> IResult<&str, RemoveTableStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -375,17 +374,11 @@ pub struct RemoveEventStatement { pub what: String, } -impl fmt::Display for RemoveEventStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE EVENT {} ON {}", self.name, self.what) - } -} - -impl dbs::Process for RemoveEventStatement { - fn process( +impl RemoveEventStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -396,6 +389,12 @@ impl dbs::Process for RemoveEventStatement { } } +impl fmt::Display for RemoveEventStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE EVENT {} ON {}", self.name, self.what) + } +} + fn event(i: &str) -> IResult<&str, RemoveEventStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -426,17 +425,11 @@ pub struct RemoveFieldStatement { pub what: String, } -impl fmt::Display for RemoveFieldStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE FIELD {} ON {}", self.name, self.what) - } -} - -impl dbs::Process for RemoveFieldStatement { - fn process( +impl RemoveFieldStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -447,6 +440,12 @@ impl dbs::Process for RemoveFieldStatement { } } +impl fmt::Display for RemoveFieldStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE FIELD {} ON {}", self.name, self.what) + } +} + fn field(i: &str) -> IResult<&str, RemoveFieldStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; @@ -477,17 +476,11 @@ pub struct RemoveIndexStatement { pub what: String, } -impl fmt::Display for RemoveIndexStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "REMOVE INDEX {} ON {}", self.name, self.what) - } -} - -impl dbs::Process for RemoveIndexStatement { - fn process( +impl RemoveIndexStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -498,6 +491,12 @@ impl dbs::Process for RemoveIndexStatement { } } +impl fmt::Display for RemoveIndexStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "REMOVE INDEX {} ON {}", self.name, self.what) + } +} + fn index(i: &str) -> IResult<&str, RemoveIndexStatement> { let (i, _) = tag_no_case("REMOVE")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/select.rs b/src/sql/statements/select.rs index d26ff2b1..8d740ff2 100644 --- a/src/sql/statements/select.rs +++ b/src/sql/statements/select.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -63,6 +62,58 @@ impl SelectStatement { } } +impl SelectStatement { + pub async fn compute( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + doc: Option<&Value>, + ) -> Result { + // Allowed to run? + exe.check(opt, Level::No)?; + // Create a new iterator + let mut i = Iterator::new(); + // Pass in statement config + i.expr = Some(&self.expr); + i.cond = self.cond.as_ref(); + i.split = self.split.as_ref(); + i.group = self.group.as_ref(); + i.order = self.order.as_ref(); + i.limit = self.limit.as_ref(); + i.start = self.start.as_ref(); + // Ensure futures are processed + let opt = &opt.futures(true); + // Specify the document version + let opt = &opt.version(self.version.as_ref()); + // Loop over the select targets + for w in self.what.0.iter() { + match w.compute(ctx, opt, exe, doc).await? { + Value::Table(v) => { + i.process_table(ctx, exe, v); + } + Value::Thing(v) => { + i.process_thing(ctx, exe, v); + } + Value::Model(v) => { + i.process_model(ctx, exe, v); + } + Value::Array(v) => { + i.process_array(ctx, exe, v); + } + Value::Object(v) => { + i.process_object(ctx, exe, v); + } + v => { + i.process_value(ctx, exe, v); + } + }; + } + // Output the results + i.output(ctx, exe) + } +} + impl fmt::Display for SelectStatement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "SELECT {} FROM {}", self.expr, self.what)?; @@ -97,58 +148,6 @@ impl fmt::Display for SelectStatement { } } -impl dbs::Process for SelectStatement { - fn process( - &self, - ctx: &Runtime, - opt: &Options, - exe: &mut Executor, - doc: Option<&Value>, - ) -> Result { - // Allowed to run? - exe.check(opt, Level::No)?; - // Create a new iterator - let mut i = Iterator::new(); - // Pass in statement config - i.expr = Some(&self.expr); - i.cond = self.cond.as_ref(); - i.split = self.split.as_ref(); - i.group = self.group.as_ref(); - i.order = self.order.as_ref(); - i.limit = self.limit.as_ref(); - i.start = self.start.as_ref(); - // Ensure futures are processed - let opt = &opt.futures(true); - // Specify the document version - let opt = &opt.version(self.version.as_ref()); - // Loop over the select targets - for w in self.what.0.iter() { - match w.process(ctx, opt, exe, doc)? { - Value::Table(v) => { - i.process_table(ctx, exe, v); - } - Value::Thing(v) => { - i.process_thing(ctx, exe, v); - } - Value::Model(v) => { - i.process_model(ctx, exe, v); - } - Value::Array(v) => { - i.process_array(ctx, exe, v); - } - Value::Object(v) => { - i.process_object(ctx, exe, v); - } - v => { - i.process_value(ctx, exe, v); - } - }; - } - // Output the results - i.output(ctx, exe) - } -} - pub fn select(i: &str) -> IResult<&str, SelectStatement> { let (i, _) = tag_no_case("SELECT")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/set.rs b/src/sql/statements/set.rs index 86e86595..e41c7060 100644 --- a/src/sql/statements/set.rs +++ b/src/sql/statements/set.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -20,21 +19,21 @@ pub struct SetStatement { pub what: Value, } -impl fmt::Display for SetStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "LET ${} = {}", self.name, self.what) - } -} - -impl dbs::Process for SetStatement { - fn process( +impl SetStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { - self.what.process(ctx, opt, exe, doc) + self.what.compute(ctx, opt, exe, doc).await + } +} + +impl fmt::Display for SetStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "LET ${} = {}", self.name, self.what) } } diff --git a/src/sql/statements/update.rs b/src/sql/statements/update.rs index 10f84fb0..0effb2a7 100644 --- a/src/sql/statements/update.rs +++ b/src/sql/statements/update.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Iterator; use crate::dbs::Level; @@ -31,30 +30,11 @@ pub struct UpdateStatement { pub timeout: Option, } -impl fmt::Display for UpdateStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UPDATE {}", self.what)?; - if let Some(ref v) = self.data { - write!(f, " {}", v)? - } - if let Some(ref v) = self.cond { - write!(f, " {}", v)? - } - if let Some(ref v) = self.output { - write!(f, " {}", v)? - } - if let Some(ref v) = self.timeout { - write!(f, " {}", v)? - } - Ok(()) - } -} - -impl dbs::Process for UpdateStatement { - fn process( +impl UpdateStatement { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { @@ -69,7 +49,7 @@ impl dbs::Process for UpdateStatement { let opt = &opt.futures(false); // Loop over the update targets for w in self.what.0.iter() { - match w.process(ctx, opt, exe, doc)? { + match w.compute(ctx, opt, exe, doc).await? { Value::Table(v) => { i.process_table(ctx, exe, v); } @@ -97,6 +77,25 @@ impl dbs::Process for UpdateStatement { } } +impl fmt::Display for UpdateStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UPDATE {}", self.what)?; + if let Some(ref v) = self.data { + write!(f, " {}", v)? + } + if let Some(ref v) = self.cond { + write!(f, " {}", v)? + } + if let Some(ref v) = self.output { + write!(f, " {}", v)? + } + if let Some(ref v) = self.timeout { + write!(f, " {}", v)? + } + Ok(()) + } +} + pub fn update(i: &str) -> IResult<&str, UpdateStatement> { let (i, _) = tag_no_case("UPDATE")(i)?; let (i, _) = shouldbespace(i)?; diff --git a/src/sql/statements/yuse.rs b/src/sql/statements/yuse.rs index 0d33c719..0b36229f 100644 --- a/src/sql/statements/yuse.rs +++ b/src/sql/statements/yuse.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Auth; use crate::dbs::Executor; use crate::dbs::Options; @@ -21,24 +20,11 @@ pub struct UseStatement { pub db: Option, } -impl fmt::Display for UseStatement { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "USE")?; - if let Some(ref ns) = self.ns { - write!(f, " NS {}", ns)?; - } - if let Some(ref db) = self.db { - write!(f, " DB {}", db)?; - } - Ok(()) - } -} - -impl dbs::Process for UseStatement { - fn process( +impl UseStatement { + pub async fn compute( &self, _ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, _doc: Option<&Value>, ) -> Result { @@ -73,6 +59,19 @@ impl dbs::Process for UseStatement { } } +impl fmt::Display for UseStatement { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "USE")?; + if let Some(ref ns) = self.ns { + write!(f, " NS {}", ns)?; + } + if let Some(ref db) = self.db { + write!(f, " DB {}", db)?; + } + Ok(()) + } +} + pub fn yuse(i: &str) -> IResult<&str, UseStatement> { alt((both, ns, db))(i) } diff --git a/src/sql/subquery.rs b/src/sql/subquery.rs index 8e4588d3..2256ae2c 100644 --- a/src/sql/subquery.rs +++ b/src/sql/subquery.rs @@ -1,5 +1,4 @@ use crate::ctx::Context; -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -39,32 +38,17 @@ impl PartialOrd for Subquery { } } -impl fmt::Display for Subquery { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Subquery::Value(v) => write!(f, "({})", v), - Subquery::Select(v) => write!(f, "({})", v), - Subquery::Create(v) => write!(f, "({})", v), - Subquery::Update(v) => write!(f, "({})", v), - Subquery::Delete(v) => write!(f, "({})", v), - Subquery::Relate(v) => write!(f, "({})", v), - Subquery::Insert(v) => write!(f, "({})", v), - Subquery::Ifelse(v) => write!(f, "{}", v), - } - } -} - -impl dbs::Process for Subquery { - fn process( +impl Subquery { + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, doc: Option<&Value>, ) -> Result { match self { - Subquery::Value(ref v) => v.process(ctx, opt, exe, doc), - Subquery::Ifelse(ref v) => v.process(ctx, opt, exe, doc), + Subquery::Value(ref v) => v.compute(ctx, opt, exe, doc).await, + Subquery::Ifelse(ref v) => v.compute(ctx, opt, exe, doc).await, Subquery::Select(ref v) => { // Duplicate options let opt = opt.dive()?; @@ -78,15 +62,17 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - let res = v.process(&ctx, &opt, exe, doc)?; + let res = v.compute(&ctx, &opt, exe, doc).await?; // Process result match v.limit() { 1 => match v.expr.single() { - Some(v) => res.first(&ctx, &opt, exe).get(&ctx, &opt, exe, &v).ok(), - None => res.first(&ctx, &opt, exe).ok(), + Some(v) => { + res.first(&ctx, &opt, exe).await.get(&ctx, &opt, exe, &v).await.ok() + } + None => res.first(&ctx, &opt, exe).await.ok(), }, _ => match v.expr.single() { - Some(v) => res.get(&ctx, &opt, exe, &v).ok(), + Some(v) => res.get(&ctx, &opt, exe, &v).await.ok(), None => res.ok(), }, } @@ -104,7 +90,7 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - match v.process(&ctx, &opt, exe, doc)? { + match v.compute(&ctx, &opt, exe, doc).await? { Value::Array(mut v) => match v.len() { 1 => Ok(v.value.remove(0)), _ => Ok(v.into()), @@ -125,7 +111,7 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - match v.process(&ctx, &opt, exe, doc)? { + match v.compute(&ctx, &opt, exe, doc).await? { Value::Array(mut v) => match v.len() { 1 => Ok(v.value.remove(0)), _ => Ok(v.into()), @@ -146,7 +132,7 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - match v.process(&ctx, &opt, exe, doc)? { + match v.compute(&ctx, &opt, exe, doc).await? { Value::Array(mut v) => match v.len() { 1 => Ok(v.value.remove(0)), _ => Ok(v.into()), @@ -167,7 +153,7 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - match v.process(&ctx, &opt, exe, doc)? { + match v.compute(&ctx, &opt, exe, doc).await? { Value::Array(mut v) => match v.len() { 1 => Ok(v.value.remove(0)), _ => Ok(v.into()), @@ -188,7 +174,7 @@ impl dbs::Process for Subquery { // Prepare context let ctx = ctx.freeze(); // Process subquery - match v.process(&ctx, &opt, exe, doc)? { + match v.compute(&ctx, &opt, exe, doc).await? { Value::Array(mut v) => match v.len() { 1 => Ok(v.value.remove(0)), _ => Ok(v.into()), @@ -200,6 +186,21 @@ impl dbs::Process for Subquery { } } +impl fmt::Display for Subquery { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Subquery::Value(v) => write!(f, "({})", v), + Subquery::Select(v) => write!(f, "({})", v), + Subquery::Create(v) => write!(f, "({})", v), + Subquery::Update(v) => write!(f, "({})", v), + Subquery::Delete(v) => write!(f, "({})", v), + Subquery::Relate(v) => write!(f, "({})", v), + Subquery::Insert(v) => write!(f, "({})", v), + Subquery::Ifelse(v) => write!(f, "{}", v), + } + } +} + pub fn subquery(i: &str) -> IResult<&str, Subquery> { alt((subquery_ifelse, subquery_others))(i) } diff --git a/src/sql/value/array.rs b/src/sql/value/array.rs index 4e2e0b00..56873814 100644 --- a/src/sql/value/array.rs +++ b/src/sql/value/array.rs @@ -6,8 +6,14 @@ use crate::sql::idiom::Idiom; use crate::sql::value::Value; impl Value { - pub fn array(&mut self, ctx: &Runtime, opt: &Options, exe: &mut Executor, path: &Idiom) { + pub async fn array( + &mut self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + path: &Idiom, + ) { let val = Value::from(Array::default()); - self.set(ctx, opt, exe, path, Value::from(val)) + self.set(ctx, opt, exe, path, Value::from(val)).await } } diff --git a/src/sql/value/decrement.rs b/src/sql/value/decrement.rs index f991ee06..dd6eb624 100644 --- a/src/sql/value/decrement.rs +++ b/src/sql/value/decrement.rs @@ -6,25 +6,37 @@ use crate::sql::number::Number; use crate::sql::value::Value; impl Value { - pub fn decrement( + pub async fn decrement( &mut self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, path: &Idiom, val: Value, ) { - match self.get(ctx, opt, exe, path) { + match self.get(ctx, opt, exe, path).await { Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, exe, path, Value::from(v - x)), + Value::Number(x) => { + self.set(ctx, opt, exe, path, Value::from(v - x)).await; + () + } _ => (), }, Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, exe, path, Value::from(v - x)), - x => self.set(ctx, opt, exe, path, Value::from(v - x)), + Value::Array(x) => { + self.set(ctx, opt, exe, path, Value::from(v - x)).await; + () + } + x => { + self.set(ctx, opt, exe, path, Value::from(v - x)).await; + () + } }, Value::None => match val { - Value::Number(x) => self.set(ctx, opt, exe, path, Value::from(Number::from(0) - x)), + Value::Number(x) => { + self.set(ctx, opt, exe, path, Value::from(Number::from(0) - x)).await; + () + } _ => (), }, _ => (), @@ -39,53 +51,53 @@ mod tests { use crate::dbs::test::mock; use crate::sql::test::Parse; - #[test] - fn dec_none() { + #[tokio::test] + async fn dec_none() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("other"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 100, other: -10 }"); - val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(10)); + val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn dec_number() { + #[tokio::test] + async fn dec_number() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 90 }"); - val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(10)); + val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn dec_array_number() { + #[tokio::test] + async fn dec_array_number() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(10)); + val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn dec_array_value() { + #[tokio::test] + async fn dec_array_value() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(200)); + val.decrement(&ctx, &opt, &mut exe, &idi, Value::from(200)).await; assert_eq!(res, val); } - #[test] - fn dec_array_array() { + #[tokio::test] + async fn dec_array_array() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [200] }"); - val.decrement(&ctx, &opt, &mut exe, &idi, Value::parse("[100, 300]")); + val.decrement(&ctx, &opt, &mut exe, &idi, Value::parse("[100, 300]")).await; assert_eq!(res, val); } } diff --git a/src/sql/value/del.rs b/src/sql/value/del.rs index 97a8177a..5c638295 100644 --- a/src/sql/value/del.rs +++ b/src/sql/value/del.rs @@ -1,13 +1,22 @@ use crate::dbs::Executor; use crate::dbs::Options; -use crate::dbs::Process; use crate::dbs::Runtime; +use crate::sql::array::Abolish; use crate::sql::idiom::Idiom; use crate::sql::part::Part; use crate::sql::value::Value; +use async_recursion::async_recursion; +use std::collections::HashMap; impl Value { - pub fn del(&mut self, ctx: &Runtime, opt: &Options, exe: &mut Executor, path: &Idiom) { + #[async_recursion] + pub async fn del( + &mut self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + path: &Idiom, + ) { match path.parts.first() { // Get the current path part Some(p) => match self { @@ -16,7 +25,7 @@ impl Value { Part::Field(p) => match path.parts.len() { 1 => v.remove(&p.name), _ => match v.value.get_mut(&p.name) { - Some(v) if v.is_some() => v.del(ctx, opt, exe, &path.next()), + Some(v) if v.is_some() => v.del(ctx, opt, exe, &path.next()).await, _ => (), }, }, @@ -26,7 +35,11 @@ impl Value { Value::Array(v) => match p { Part::All => match path.parts.len() { 1 => v.value.clear(), - _ => v.value.iter_mut().for_each(|v| v.del(ctx, opt, exe, &path.next())), + _ => { + for v in &mut v.value { + v.del(ctx, opt, exe, &path.next()).await + } + } }, Part::First => match path.parts.len() { 1 => { @@ -36,7 +49,7 @@ impl Value { } } _ => match v.value.first_mut() { - Some(v) => v.del(ctx, opt, exe, &path.next()), + Some(v) => v.del(ctx, opt, exe, &path.next()).await, None => (), }, }, @@ -48,7 +61,7 @@ impl Value { } } _ => match v.value.last_mut() { - Some(v) => v.del(ctx, opt, exe, &path.next()), + Some(v) => v.del(ctx, opt, exe, &path.next()).await, None => (), }, }, @@ -61,22 +74,32 @@ impl Value { } _ => match path.parts.len() { _ => match v.value.get_mut(i.to_usize()) { - Some(v) => v.del(ctx, opt, exe, &path.next()), + Some(v) => v.del(ctx, opt, exe, &path.next()).await, None => (), }, }, }, Part::Where(w) => match path.parts.len() { - 1 => v.value.retain(|v| match w.process(ctx, opt, exe, Some(v)) { - Ok(v) if v.is_truthy() => false, - _ => true, - }), - _ => v.value.iter_mut().for_each(|v| { - match w.process(ctx, opt, exe, Some(v)) { - Ok(mut v) if v.is_truthy() => v.del(ctx, opt, exe, &path.next()), - _ => (), + 1 => { + let mut m = HashMap::new(); + for (i, v) in v.value.iter().enumerate() { + match w.compute(ctx, opt, exe, Some(&v)).await { + Ok(o) if o.is_truthy() => m.insert(i, ()), + _ => None, + }; } - }), + v.value.abolish(|i| m.contains_key(&i)) + } + _ => { + for v in &mut v.value { + match w.compute(ctx, opt, exe, Some(&v)).await { + Ok(o) if o.is_truthy() => { + v.del(ctx, opt, exe, &path.next()).await + } + _ => (), + }; + } + } }, _ => (), }, @@ -96,85 +119,105 @@ mod tests { use crate::dbs::test::mock; use crate::sql::test::Parse; - #[test] - fn del_none() { + #[tokio::test] + async fn del_none() { let (ctx, opt, mut exe) = mock(); let idi = Idiom { parts: vec![], }; let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let res = Value::parse("{ test: { other: null, something: 123 } }"); - val.del(&ctx, &opt, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_reset() { + #[tokio::test] + async fn del_reset() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let res = Value::parse("{ }"); - val.del(&ctx, &opt, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_basic() { + #[tokio::test] + async fn del_basic() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_wrong() { + #[tokio::test] + async fn del_wrong() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_other() { + #[tokio::test] + async fn del_other() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_array() { + #[tokio::test] + async fn del_array() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_array_field() { + #[tokio::test] + async fn del_array_field() { let (ctx, opt, mut exe) = mock(); 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 }, { }] } }"); - val.del(&ctx, &opt, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn del_array_fields() { + #[tokio::test] + async fn del_array_fields() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something[*].age"); let mut val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); let res = Value::parse("{ test: { something: [{ }, { }] } }"); - val.del(&ctx, &opt, &mut exe, &idi); + val.del(&ctx, &opt, &mut exe, &idi).await; + assert_eq!(res, val); + } + + #[tokio::test] + async fn del_array_where_field() { + let (ctx, opt, mut exe) = mock(); + 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 }, { }] } }"); + val.del(&ctx, &opt, &mut exe, &idi).await; + assert_eq!(res, val); + } + + #[tokio::test] + async fn del_array_where_fields() { + let (ctx, opt, mut exe) = mock(); + 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 }] } }"); + val.del(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } } diff --git a/src/sql/value/first.rs b/src/sql/value/first.rs index ca10fff3..19eea0c3 100644 --- a/src/sql/value/first.rs +++ b/src/sql/value/first.rs @@ -6,7 +6,7 @@ use crate::sql::part::Part; use crate::sql::value::Value; impl Value { - pub fn first(&self, ctx: &Runtime, opt: &Options, exe: &mut Executor) -> Self { - self.get(ctx, opt, exe, &Idiom::from(vec![Part::First])) + pub async fn first(&self, ctx: &Runtime, opt: &Options<'_>, exe: &mut Executor) -> Self { + self.get(ctx, opt, exe, &Idiom::from(vec![Part::First])).await } } diff --git a/src/sql/value/get.rs b/src/sql/value/get.rs index 7a777006..8dba84c9 100644 --- a/src/sql/value/get.rs +++ b/src/sql/value/get.rs @@ -1,55 +1,66 @@ use crate::dbs::Executor; use crate::dbs::Options; -use crate::dbs::Process; use crate::dbs::Runtime; use crate::sql::field::{Field, Fields}; use crate::sql::idiom::Idiom; use crate::sql::part::Part; use crate::sql::statements::select::SelectStatement; use crate::sql::value::{Value, Values}; +use async_recursion::async_recursion; impl Value { - pub fn get(&self, ctx: &Runtime, opt: &Options, exe: &mut Executor, path: &Idiom) -> Self { + #[async_recursion] + pub async fn get( + &self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + path: &Idiom, + ) -> Self { match path.parts.first() { // Get the current path part Some(p) => match self { // Current path part is an object Value::Object(v) => match p { Part::Field(p) => match v.value.get(&p.name) { - Some(v) => v.get(ctx, opt, exe, &path.next()), + Some(v) => v.get(ctx, opt, exe, &path.next()).await, None => Value::None, }, _ => Value::None, }, // Current path part is an array Value::Array(v) => match p { - Part::All => v - .value - .iter() - .map(|v| v.get(ctx, opt, exe, &path.next())) - .collect::>() - .into(), + Part::All => { + let mut a = Vec::new(); + for v in &v.value { + a.push(v.get(ctx, opt, exe, &path.next()).await) + } + a.into() + } Part::First => match v.value.first() { - Some(v) => v.get(ctx, opt, exe, &path.next()), + Some(v) => v.get(ctx, opt, exe, &path.next()).await, None => Value::None, }, Part::Last => match v.value.last() { - Some(v) => v.get(ctx, opt, exe, &path.next()), + Some(v) => v.get(ctx, opt, exe, &path.next()).await, None => Value::None, }, Part::Index(i) => match v.value.get(i.to_usize()) { - Some(v) => v.get(ctx, opt, exe, &path.next()), + Some(v) => v.get(ctx, opt, exe, &path.next()).await, None => Value::None, }, - Part::Where(w) => v - .value - .iter() - .filter_map(|v| match w.process(ctx, opt, exe, Some(v)) { - Ok(v) if v.is_truthy() => Some(v.get(ctx, opt, exe, &path.next())), - _ => None, - }) - .collect::>() - .into(), + Part::Where(w) => { + let mut a = Vec::new(); + for v in &v.value { + match w.compute(ctx, opt, exe, Some(&v)).await { + Ok(x) if x.is_truthy() => { + a.push(v.get(ctx, opt, exe, &path.next()).await) + } + _ => (), + }; + } + a.into() + } _ => Value::None, }, // Current path part is a thing @@ -63,8 +74,8 @@ impl Value { what: Values(vec![Value::Thing(v.clone())]), ..SelectStatement::default() }; - match stm.process(ctx, opt, exe, None) { - Ok(v) => v.get(ctx, opt, exe, &path.next()), + match stm.compute(ctx, opt, exe, None).await { + Ok(v) => v.get(ctx, opt, exe, &path.next()).await, Err(_) => Value::None, } } @@ -86,32 +97,32 @@ mod tests { use crate::sql::test::Parse; use crate::sql::thing::Thing; - #[test] - fn get_none() { + #[tokio::test] + async fn get_none() { let (ctx, opt, mut exe) = mock(); let idi = Idiom { parts: vec![], }; let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, val); } - #[test] - fn get_basic() { + #[tokio::test] + async fn get_basic() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something"); let val = Value::parse("{ test: { other: null, something: 123 } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, Value::from(123)); } - #[test] - fn get_thing() { + #[tokio::test] + async fn get_thing() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.other"); let val = Value::parse("{ test: { other: test:tobie, something: 123 } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!( res, Value::from(Thing { @@ -121,21 +132,21 @@ mod tests { ); } - #[test] - fn get_array() { + #[tokio::test] + async fn get_array() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something[1]"); let val = Value::parse("{ test: { something: [123, 456, 789] } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, Value::from(456)); } - #[test] - fn get_array_thing() { + #[tokio::test] + async fn get_array_thing() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something[1]"); let val = Value::parse("{ test: { something: [test:tobie, test:jaime] } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!( res, Value::from(Thing { @@ -145,21 +156,44 @@ mod tests { ); } - #[test] - fn get_array_field() { + #[tokio::test] + async fn get_array_field() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something[1].age"); let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, Value::from(36)); } - #[test] - fn get_array_fields() { + #[tokio::test] + async fn get_array_fields() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test.something[*].age"); let val = Value::parse("{ test: { something: [{ age: 34 }, { age: 36 }] } }"); - let res = val.get(&ctx, &opt, &mut exe, &idi); + let res = val.get(&ctx, &opt, &mut exe, &idi).await; assert_eq!(res, Value::from(vec![34, 36])); } + + #[tokio::test] + async fn get_array_where_field() { + let (ctx, opt, mut exe) = mock(); + 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, &mut exe, &idi).await; + assert_eq!(res, Value::from(vec![36])); + } + + #[tokio::test] + async fn get_array_where_fields() { + let (ctx, opt, mut exe) = mock(); + 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, &mut exe, &idi).await; + assert_eq!( + res, + Value::from(vec![Value::from(map! { + "age".to_string() => Value::from(36), + })]) + ); + } } diff --git a/src/sql/value/increment.rs b/src/sql/value/increment.rs index b522f559..af2851b5 100644 --- a/src/sql/value/increment.rs +++ b/src/sql/value/increment.rs @@ -6,27 +6,45 @@ use crate::sql::number::Number; use crate::sql::value::Value; impl Value { - pub fn increment( + pub async fn increment( &mut self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, path: &Idiom, val: Value, ) { - match self.get(ctx, opt, exe, path) { + match self.get(ctx, opt, exe, path).await { Value::Number(v) => match val { - Value::Number(x) => self.set(ctx, opt, exe, path, Value::from(v + x)), + Value::Number(x) => { + self.set(ctx, opt, exe, path, Value::from(v + x)).await; + () + } _ => (), }, Value::Array(v) => match val { - Value::Array(x) => self.set(ctx, opt, exe, path, Value::from(v + x)), - x => self.set(ctx, opt, exe, path, Value::from(v + x)), + Value::Array(x) => { + self.set(ctx, opt, exe, path, Value::from(v + x)).await; + () + } + x => { + self.set(ctx, opt, exe, path, Value::from(v + x)).await; + () + } }, Value::None => match val { - Value::Number(x) => self.set(ctx, opt, exe, path, Value::from(Number::from(0) + x)), - Value::Array(x) => self.set(ctx, opt, exe, path, Value::from(x)), - x => self.set(ctx, opt, exe, path, Value::from(vec![x])), + Value::Number(x) => { + self.set(ctx, opt, exe, path, Value::from(Number::from(0) + x)).await; + () + } + Value::Array(x) => { + self.set(ctx, opt, exe, path, Value::from(x)).await; + () + } + x => { + self.set(ctx, opt, exe, path, Value::from(vec![x])).await; + () + } }, _ => (), } @@ -40,53 +58,53 @@ mod tests { use crate::dbs::test::mock; use crate::sql::test::Parse; - #[test] - fn inc_none() { + #[tokio::test] + async fn inc_none() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("other"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 100, other: +10 }"); - val.increment(&ctx, &opt, &mut exe, &idi, Value::from(10)); + val.increment(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn inc_number() { + #[tokio::test] + async fn inc_number() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: 100 }"); let res = Value::parse("{ test: 110 }"); - val.increment(&ctx, &opt, &mut exe, &idi, Value::from(10)); + val.increment(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn inc_array_number() { + #[tokio::test] + async fn inc_array_number() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(10)); + val.increment(&ctx, &opt, &mut exe, &idi, Value::from(10)).await; assert_eq!(res, val); } - #[test] - fn inc_array_value() { + #[tokio::test] + async fn inc_array_value() { let (ctx, opt, mut exe) = mock(); let idi = Idiom::parse("test"); let mut val = Value::parse("{ test: [100, 200, 300] }"); let res = Value::parse("{ test: [100, 200, 300] }"); - val.increment(&ctx, &opt, &mut exe, &idi, Value::from(200)); + val.increment(&ctx, &opt, &mut exe, &idi, Value::from(200)).await; assert_eq!(res, val); } - #[test] - fn inc_array_array() { + #[tokio::test] + async fn inc_array_array() { let (ctx, opt, mut exe) = mock(); 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.increment(&ctx, &opt, &mut exe, &idi, Value::parse("[100, 300, 400, 500]")); + val.increment(&ctx, &opt, &mut exe, &idi, Value::parse("[100, 300, 400, 500]")).await; assert_eq!(res, val); } } diff --git a/src/sql/value/last.rs b/src/sql/value/last.rs index 428bf558..c3de90af 100644 --- a/src/sql/value/last.rs +++ b/src/sql/value/last.rs @@ -6,7 +6,7 @@ use crate::sql::part::Part; use crate::sql::value::Value; impl Value { - pub fn last(&self, ctx: &Runtime, opt: &Options, exe: &mut Executor) -> Self { - self.get(ctx, opt, exe, &Idiom::from(vec![Part::Last])) + pub async fn last(&self, ctx: &Runtime, opt: &Options<'_>, exe: &mut Executor) -> Self { + self.get(ctx, opt, exe, &Idiom::from(vec![Part::Last])).await } } diff --git a/src/sql/value/object.rs b/src/sql/value/object.rs index d3496c70..c4cca4c3 100644 --- a/src/sql/value/object.rs +++ b/src/sql/value/object.rs @@ -6,8 +6,14 @@ use crate::sql::object::Object; use crate::sql::value::Value; impl Value { - pub fn object(&mut self, ctx: &Runtime, opt: &Options, exe: &mut Executor, path: &Idiom) { + pub async fn object( + &mut self, + ctx: &Runtime, + opt: &Options<'_>, + exe: &mut Executor, + path: &Idiom, + ) { let val = Value::from(Object::default()); - self.set(ctx, opt, exe, path, val) + self.set(ctx, opt, exe, path, val).await } } diff --git a/src/sql/value/set.rs b/src/sql/value/set.rs index 59494dc3..e1b95388 100644 --- a/src/sql/value/set.rs +++ b/src/sql/value/set.rs @@ -1,17 +1,18 @@ use crate::dbs::Executor; use crate::dbs::Options; -use crate::dbs::Process; use crate::dbs::Runtime; use crate::sql::idiom::Idiom; use crate::sql::object::Object; use crate::sql::part::Part; use crate::sql::value::Value; +use async_recursion::async_recursion; impl Value { - pub fn set( + #[async_recursion] + pub async fn set( &mut self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, path: &Idiom, val: Value, @@ -22,10 +23,10 @@ impl Value { // Current path part is an object Value::Object(v) => match p { Part::Field(p) => match v.value.get_mut(&p.name) { - Some(v) if v.is_some() => v.set(ctx, opt, exe, &path.next(), val), + Some(v) if v.is_some() => v.set(ctx, opt, exe, &path.next(), val).await, _ => { let mut obj = Value::from(Object::default()); - obj.set(ctx, opt, exe, &path.next(), val); + obj.set(ctx, opt, exe, &path.next(), val).await; v.insert(&p.name, obj) } }, @@ -33,29 +34,32 @@ impl Value { }, // Current path part is an array Value::Array(v) => match p { - Part::All => v - .value - .iter_mut() - .for_each(|v| v.set(ctx, opt, exe, &path.next(), val.clone())), + Part::All => { + for v in &mut v.value { + v.set(ctx, opt, exe, &path.next(), val.clone()).await + } + } Part::First => match v.value.first_mut() { - Some(v) => v.set(ctx, opt, exe, &path.next(), val), + Some(v) => v.set(ctx, opt, exe, &path.next(), val).await, None => (), }, Part::Last => match v.value.last_mut() { - Some(v) => v.set(ctx, opt, exe, &path.next(), val), + Some(v) => v.set(ctx, opt, exe, &path.next(), val).await, None => (), }, Part::Index(i) => match v.value.get_mut(i.to_usize()) { - Some(v) => v.set(ctx, opt, exe, &path.next(), val), + Some(v) => v.set(ctx, opt, exe, &path.next(), val).await, None => (), }, Part::Where(w) => { - v.value.iter_mut().for_each(|v| match w.process(ctx, opt, exe, Some(v)) { - Ok(mut v) if v.is_truthy() => { - v.set(ctx, opt, exe, &path.next(), val.clone()) - } - _ => (), - }) + for v in &mut v.value { + match w.compute(ctx, opt, exe, Some(&v)).await { + Ok(x) if x.is_truthy() => { + v.set(ctx, opt, exe, &path.next(), val.clone()).await + } + _ => (), + }; + } } _ => (), }, @@ -75,85 +79,105 @@ mod tests { use crate::dbs::test::mock; use crate::sql::test::Parse; - #[test] - fn set_none() { + #[tokio::test] + async fn set_none() { let (ctx, opt, mut exe) = mock(); let idi = Idiom { parts: vec![], }; let mut val = Value::parse("{ test: { other: null, something: 123 } }"); let res = Value::parse("999"); - val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_reset() { + #[tokio::test] + async fn set_reset() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_basic() { + #[tokio::test] + async fn set_basic() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_wrong() { + #[tokio::test] + async fn set_wrong() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_other() { + #[tokio::test] + async fn set_other() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_array() { + #[tokio::test] + async fn set_array() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(999)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(999)).await; assert_eq!(res, val); } - #[test] - fn set_array_field() { + #[tokio::test] + async fn set_array_field() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(21)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(21)).await; assert_eq!(res, val); } - #[test] - fn set_array_fields() { + #[tokio::test] + async fn set_array_fields() { let (ctx, opt, mut exe) = mock(); 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, &mut exe, &idi, Value::from(21)); + val.set(&ctx, &opt, &mut exe, &idi, Value::from(21)).await; + assert_eq!(res, val); + } + + #[tokio::test] + async fn set_array_where_field() { + let (ctx, opt, mut exe) = mock(); + 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, &mut exe, &idi, Value::from(21)).await; + assert_eq!(res, val); + } + + #[tokio::test] + async fn set_array_where_fields() { + let (ctx, opt, mut exe) = mock(); + 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, &mut exe, &idi, Value::from(21)).await; assert_eq!(res, val); } } diff --git a/src/sql/value/value.rs b/src/sql/value/value.rs index 6f491e9c..22de1f9d 100644 --- a/src/sql/value/value.rs +++ b/src/sql/value/value.rs @@ -1,4 +1,3 @@ -use crate::dbs; use crate::dbs::Executor; use crate::dbs::Options; use crate::dbs::Runtime; @@ -21,6 +20,7 @@ use crate::sql::strand::{strand, Strand}; use crate::sql::subquery::{subquery, Subquery}; use crate::sql::table::{table, Table}; use crate::sql::thing::{thing, Thing}; +use async_recursion::async_recursion; use chrono::{DateTime, Utc}; use dec::Decimal; use fuzzy_matcher::skim::SkimMatcherV2; @@ -762,13 +762,14 @@ impl fmt::Display for Value { } } -impl dbs::Process for Value { - fn process( +impl Value { + #[async_recursion] + pub async fn compute( &self, ctx: &Runtime, - opt: &Options, + opt: &Options<'_>, exe: &mut Executor, - doc: Option<&Value>, + doc: Option<&'async_recursion Value>, ) -> Result { match self { Value::None => Ok(Value::None), @@ -776,13 +777,13 @@ impl dbs::Process for Value { Value::Null => Ok(Value::Null), Value::True => Ok(Value::True), Value::False => Ok(Value::False), - Value::Param(v) => v.process(ctx, opt, exe, doc), - Value::Idiom(v) => v.process(ctx, opt, exe, doc), - Value::Array(v) => v.process(ctx, opt, exe, doc), - Value::Object(v) => v.process(ctx, opt, exe, doc), - Value::Function(v) => v.process(ctx, opt, exe, doc), - Value::Subquery(v) => v.process(ctx, opt, exe, doc), - Value::Expression(v) => v.process(ctx, opt, exe, doc), + Value::Param(v) => v.compute(ctx, opt, exe, doc).await, + Value::Idiom(v) => v.compute(ctx, opt, exe, doc).await, + Value::Array(v) => v.compute(ctx, opt, exe, doc).await, + Value::Object(v) => v.compute(ctx, opt, exe, doc).await, + Value::Function(v) => v.compute(ctx, opt, exe, doc).await, + Value::Subquery(v) => v.compute(ctx, opt, exe, doc).await, + Value::Expression(v) => v.compute(ctx, opt, exe, doc).await, _ => Ok(self.to_owned()), } }