Feature - unary operators (#2139)
This commit is contained in:
parent
64adb2e913
commit
41e119a5f5
16 changed files with 499 additions and 131 deletions
|
@ -321,7 +321,7 @@ impl<'a> Document<'a> {
|
||||||
Operator::Equal,
|
Operator::Equal,
|
||||||
Value::Subquery(Box::new(Subquery::Ifelse(IfelseStatement {
|
Value::Subquery(Box::new(Subquery::Ifelse(IfelseStatement {
|
||||||
exprs: vec![(
|
exprs: vec![(
|
||||||
Value::Expression(Box::new(Expression {
|
Value::Expression(Box::new(Expression::Binary {
|
||||||
l: Value::Idiom(key.clone()),
|
l: Value::Idiom(key.clone()),
|
||||||
o: Operator::MoreThan,
|
o: Operator::MoreThan,
|
||||||
r: val.clone(),
|
r: val.clone(),
|
||||||
|
@ -341,7 +341,7 @@ impl<'a> Document<'a> {
|
||||||
Operator::Equal,
|
Operator::Equal,
|
||||||
Value::Subquery(Box::new(Subquery::Ifelse(IfelseStatement {
|
Value::Subquery(Box::new(Subquery::Ifelse(IfelseStatement {
|
||||||
exprs: vec![(
|
exprs: vec![(
|
||||||
Value::Expression(Box::new(Expression {
|
Value::Expression(Box::new(Expression::Binary {
|
||||||
l: Value::Idiom(key.clone()),
|
l: Value::Idiom(key.clone()),
|
||||||
o: Operator::LessThan,
|
o: Operator::LessThan,
|
||||||
r: val.clone(),
|
r: val.clone(),
|
||||||
|
@ -363,13 +363,13 @@ impl<'a> Document<'a> {
|
||||||
ops.push((
|
ops.push((
|
||||||
key.clone(),
|
key.clone(),
|
||||||
Operator::Equal,
|
Operator::Equal,
|
||||||
Value::Expression(Box::new(Expression {
|
Value::Expression(Box::new(Expression::Binary {
|
||||||
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
||||||
Expression {
|
Expression::Binary {
|
||||||
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
||||||
Expression {
|
Expression::Binary {
|
||||||
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(
|
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(
|
||||||
Box::new(Expression {
|
Box::new(Expression::Binary {
|
||||||
l: Value::Idiom(key),
|
l: Value::Idiom(key),
|
||||||
o: Operator::Nco,
|
o: Operator::Nco,
|
||||||
r: Value::Number(Number::Int(0)),
|
r: Value::Number(Number::Int(0)),
|
||||||
|
@ -377,7 +377,7 @@ impl<'a> Document<'a> {
|
||||||
)))),
|
)))),
|
||||||
o: Operator::Mul,
|
o: Operator::Mul,
|
||||||
r: Value::Subquery(Box::new(Subquery::Value(Value::Expression(
|
r: Value::Subquery(Box::new(Subquery::Value(Value::Expression(
|
||||||
Box::new(Expression {
|
Box::new(Expression::Binary {
|
||||||
l: Value::Idiom(key_c.clone()),
|
l: Value::Idiom(key_c.clone()),
|
||||||
o: Operator::Nco,
|
o: Operator::Nco,
|
||||||
r: Value::Number(Number::Int(0)),
|
r: Value::Number(Number::Int(0)),
|
||||||
|
@ -395,9 +395,9 @@ impl<'a> Document<'a> {
|
||||||
))))),
|
))))),
|
||||||
o: Operator::Div,
|
o: Operator::Div,
|
||||||
r: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
r: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
||||||
Expression {
|
Expression::Binary {
|
||||||
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
l: Value::Subquery(Box::new(Subquery::Value(Value::Expression(Box::new(
|
||||||
Expression {
|
Expression::Binary {
|
||||||
l: Value::Idiom(key_c.clone()),
|
l: Value::Idiom(key_c.clone()),
|
||||||
o: Operator::Nco,
|
o: Operator::Nco,
|
||||||
r: Value::Number(Number::Int(0)),
|
r: Value::Number(Number::Int(0)),
|
||||||
|
|
|
@ -430,6 +430,10 @@ pub enum Error {
|
||||||
#[error("Cannot raise the value '{0}' with '{1}'")]
|
#[error("Cannot raise the value '{0}' with '{1}'")]
|
||||||
TryPow(String, String),
|
TryPow(String, String),
|
||||||
|
|
||||||
|
/// Cannot perform negation
|
||||||
|
#[error("Cannot negate the value '{0}'")]
|
||||||
|
TryNeg(String),
|
||||||
|
|
||||||
/// It's is not possible to convert between the two types
|
/// It's is not possible to convert between the two types
|
||||||
#[error("Cannot convert from '{0}' to '{1}'")]
|
#[error("Cannot convert from '{0}' to '{1}'")]
|
||||||
TryFrom(String, &'static str),
|
TryFrom(String, &'static str),
|
||||||
|
|
|
@ -3,11 +3,20 @@ use crate::err::Error;
|
||||||
use crate::sql::value::TryAdd;
|
use crate::sql::value::TryAdd;
|
||||||
use crate::sql::value::TryDiv;
|
use crate::sql::value::TryDiv;
|
||||||
use crate::sql::value::TryMul;
|
use crate::sql::value::TryMul;
|
||||||
|
use crate::sql::value::TryNeg;
|
||||||
use crate::sql::value::TryPow;
|
use crate::sql::value::TryPow;
|
||||||
use crate::sql::value::TrySub;
|
use crate::sql::value::TrySub;
|
||||||
use crate::sql::value::Value;
|
use crate::sql::value::Value;
|
||||||
use crate::sql::Expression;
|
use crate::sql::Expression;
|
||||||
|
|
||||||
|
pub fn neg(a: Value) -> Result<Value, Error> {
|
||||||
|
a.try_neg()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not(a: Value) -> Result<Value, Error> {
|
||||||
|
super::not::not((a,))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn or(a: Value, b: Value) -> Result<Value, Error> {
|
pub fn or(a: Value, b: Value) -> Result<Value, Error> {
|
||||||
Ok(match a.is_truthy() {
|
Ok(match a.is_truthy() {
|
||||||
true => a,
|
true => a,
|
||||||
|
|
|
@ -87,27 +87,42 @@ impl<'a> TreeBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn eval_expression(&mut self, e: &Expression) -> Result<Node, Error> {
|
async fn eval_expression(&mut self, e: &Expression) -> Result<Node, Error> {
|
||||||
let left = self.eval_value(&e.l).await?;
|
match e {
|
||||||
let right = self.eval_value(&e.r).await?;
|
Expression::Unary {
|
||||||
let mut index_option = None;
|
..
|
||||||
if let Some(ix) = left.is_indexed_field() {
|
} => {
|
||||||
if let Some(io) = IndexOption::found(ix, &e.o, &right, e) {
|
return Err(Error::FeatureNotYetImplemented {
|
||||||
index_option = Some(io.clone());
|
feature: "unary expressions in index",
|
||||||
self.add_index(e, io);
|
});
|
||||||
|
}
|
||||||
|
Expression::Binary {
|
||||||
|
l,
|
||||||
|
o,
|
||||||
|
r,
|
||||||
|
} => {
|
||||||
|
let left = self.eval_value(l).await?;
|
||||||
|
let right = self.eval_value(r).await?;
|
||||||
|
let mut index_option = None;
|
||||||
|
if let Some(ix) = left.is_indexed_field() {
|
||||||
|
if let Some(io) = IndexOption::found(ix, o, &right, e) {
|
||||||
|
index_option = Some(io.clone());
|
||||||
|
self.add_index(e, io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ix) = right.is_indexed_field() {
|
||||||
|
if let Some(io) = IndexOption::found(ix, o, &left, e) {
|
||||||
|
index_option = Some(io.clone());
|
||||||
|
self.add_index(e, io);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Node::Expression {
|
||||||
|
index_option,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(right),
|
||||||
|
operator: o.to_owned(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ix) = right.is_indexed_field() {
|
|
||||||
if let Some(io) = IndexOption::found(ix, &e.o, &left, e) {
|
|
||||||
index_option = Some(io.clone());
|
|
||||||
self.add_index(e, io);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Node::Expression {
|
|
||||||
index_option,
|
|
||||||
left: Box::new(left),
|
|
||||||
right: Box::new(right),
|
|
||||||
operator: e.o.to_owned(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_index(&mut self, e: &Expression, io: IndexOption) {
|
fn add_index(&mut self, e: &Expression, io: IndexOption) {
|
||||||
|
|
|
@ -13,6 +13,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Cast";
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||||
#[serde(rename = "$surrealdb::private::sql::Cast")]
|
#[serde(rename = "$surrealdb::private::sql::Cast")]
|
||||||
pub struct Cast(pub Kind, pub Value);
|
pub struct Cast(pub Kind, pub Value);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::sql::comment::comment;
|
use crate::sql::comment::comment;
|
||||||
use crate::sql::comment::{mightbespace, shouldbespace};
|
use crate::sql::comment::{mightbespace, shouldbespace};
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::operator::{assigner, operator};
|
use crate::sql::operator::{assigner, binary};
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::bytes::complete::tag_no_case;
|
use nom::bytes::complete::tag_no_case;
|
||||||
|
@ -15,7 +15,7 @@ use nom::sequence::preceded;
|
||||||
pub fn number(i: &str) -> IResult<&str, ()> {
|
pub fn number(i: &str) -> IResult<&str, ()> {
|
||||||
peek(alt((
|
peek(alt((
|
||||||
map(multispace1, |_| ()),
|
map(multispace1, |_| ()),
|
||||||
map(operator, |_| ()),
|
map(binary, |_| ()),
|
||||||
map(assigner, |_| ()),
|
map(assigner, |_| ()),
|
||||||
map(comment, |_| ()),
|
map(comment, |_| ()),
|
||||||
map(char(')'), |_| ()),
|
map(char(')'), |_| ()),
|
||||||
|
@ -33,7 +33,7 @@ pub fn number(i: &str) -> IResult<&str, ()> {
|
||||||
pub fn ident(i: &str) -> IResult<&str, ()> {
|
pub fn ident(i: &str) -> IResult<&str, ()> {
|
||||||
peek(alt((
|
peek(alt((
|
||||||
map(multispace1, |_| ()),
|
map(multispace1, |_| ()),
|
||||||
map(operator, |_| ()),
|
map(binary, |_| ()),
|
||||||
map(assigner, |_| ()),
|
map(assigner, |_| ()),
|
||||||
map(comment, |_| ()),
|
map(comment, |_| ()),
|
||||||
map(char(')'), |_| ()),
|
map(char(')'), |_| ()),
|
||||||
|
@ -51,7 +51,7 @@ pub fn ident(i: &str) -> IResult<&str, ()> {
|
||||||
pub fn duration(i: &str) -> IResult<&str, ()> {
|
pub fn duration(i: &str) -> IResult<&str, ()> {
|
||||||
peek(alt((
|
peek(alt((
|
||||||
map(multispace1, |_| ()),
|
map(multispace1, |_| ()),
|
||||||
map(operator, |_| ()),
|
map(binary, |_| ()),
|
||||||
map(assigner, |_| ()),
|
map(assigner, |_| ()),
|
||||||
map(comment, |_| ()),
|
map(comment, |_| ()),
|
||||||
map(char(')'), |_| ()),
|
map(char(')'), |_| ()),
|
||||||
|
|
|
@ -2,8 +2,9 @@ use crate::ctx::Context;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::fnc;
|
use crate::fnc;
|
||||||
|
use crate::sql::comment::mightbespace;
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::operator::{operator, Operator};
|
use crate::sql::operator::{self, Operator};
|
||||||
use crate::sql::value::{single, value, Value};
|
use crate::sql::value::{single, value, Value};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -11,17 +12,24 @@ use std::str;
|
||||||
|
|
||||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Expression";
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Expression";
|
||||||
|
|
||||||
|
/// Binary expressions.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
#[serde(rename = "$surrealdb::private::sql::Expression")]
|
#[serde(rename = "$surrealdb::private::sql::Expression")]
|
||||||
pub struct Expression {
|
pub enum Expression {
|
||||||
pub l: Value,
|
Unary {
|
||||||
pub o: Operator,
|
o: Operator,
|
||||||
pub r: Value,
|
v: Value,
|
||||||
|
},
|
||||||
|
Binary {
|
||||||
|
l: Value,
|
||||||
|
o: Operator,
|
||||||
|
r: Value,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Expression {
|
impl Default for Expression {
|
||||||
fn default() -> Expression {
|
fn default() -> Expression {
|
||||||
Expression {
|
Expression::Binary {
|
||||||
l: Value::Null,
|
l: Value::Null,
|
||||||
o: Operator::default(),
|
o: Operator::default(),
|
||||||
r: Value::Null,
|
r: Value::Null,
|
||||||
|
@ -30,9 +38,9 @@ impl Default for Expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
/// Create a new expression
|
/// Create a new binary expression
|
||||||
pub(crate) fn new(l: Value, o: Operator, r: Value) -> Self {
|
pub(crate) fn new(l: Value, o: Operator, r: Value) -> Self {
|
||||||
Self {
|
Self::Binary {
|
||||||
l,
|
l,
|
||||||
o,
|
o,
|
||||||
r,
|
r,
|
||||||
|
@ -40,29 +48,67 @@ impl Expression {
|
||||||
}
|
}
|
||||||
/// Augment an existing expression
|
/// Augment an existing expression
|
||||||
fn augment(mut self, l: Value, o: Operator) -> Self {
|
fn augment(mut self, l: Value, o: Operator) -> Self {
|
||||||
if o.precedence() >= self.o.precedence() {
|
match &mut self {
|
||||||
match self.l {
|
Self::Binary {
|
||||||
|
l: left,
|
||||||
|
o: op,
|
||||||
|
..
|
||||||
|
} if o.precedence() >= op.precedence() => match left {
|
||||||
Value::Expression(x) => {
|
Value::Expression(x) => {
|
||||||
self.l = x.augment(l, o).into();
|
*x.as_mut() = std::mem::take(x).augment(l, o);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.l = Self::new(l, o, self.l).into();
|
*left = Self::new(l, o, std::mem::take(left)).into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
e => {
|
||||||
|
let r = Value::from(std::mem::take(e));
|
||||||
|
Self::new(l, o, r)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let r = Value::from(self);
|
|
||||||
Self::new(l, o, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
|
pub(crate) fn writeable(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Unary {
|
||||||
|
v,
|
||||||
|
..
|
||||||
|
} => v.writeable(),
|
||||||
|
Self::Binary {
|
||||||
|
l,
|
||||||
|
r,
|
||||||
|
..
|
||||||
|
} => l.writeable() || r.writeable(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Process this type returning a computed simple Value
|
/// Process this type returning a computed simple Value
|
||||||
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
pub(crate) async fn compute(&self, ctx: &Context<'_>, opt: &Options) -> Result<Value, Error> {
|
||||||
let l = self.l.compute(ctx, opt).await?;
|
let (l, o, r) = match self {
|
||||||
match self.o {
|
Self::Unary {
|
||||||
|
o,
|
||||||
|
v,
|
||||||
|
} => {
|
||||||
|
let operand = v.compute(ctx, opt).await?;
|
||||||
|
return match o {
|
||||||
|
Operator::Neg => fnc::operate::neg(operand),
|
||||||
|
Operator::Not => fnc::operate::not(operand),
|
||||||
|
op => unreachable!("{op:?} is not a unary op"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Self::Binary {
|
||||||
|
l,
|
||||||
|
o,
|
||||||
|
r,
|
||||||
|
} => (l, o, r),
|
||||||
|
};
|
||||||
|
|
||||||
|
let l = l.compute(ctx, opt).await?;
|
||||||
|
match o {
|
||||||
Operator::Or => {
|
Operator::Or => {
|
||||||
if let true = l.is_truthy() {
|
if let true = l.is_truthy() {
|
||||||
return Ok(l);
|
return Ok(l);
|
||||||
|
@ -85,8 +131,8 @@ impl Expression {
|
||||||
}
|
}
|
||||||
_ => {} // Continue
|
_ => {} // Continue
|
||||||
}
|
}
|
||||||
let r = self.r.compute(ctx, opt).await?;
|
let r = r.compute(ctx, opt).await?;
|
||||||
match self.o {
|
match o {
|
||||||
Operator::Or => fnc::operate::or(l, r),
|
Operator::Or => fnc::operate::or(l, r),
|
||||||
Operator::And => fnc::operate::and(l, r),
|
Operator::And => fnc::operate::and(l, r),
|
||||||
Operator::Tco => fnc::operate::tco(l, r),
|
Operator::Tco => fnc::operate::tco(l, r),
|
||||||
|
@ -129,13 +175,36 @@ impl Expression {
|
||||||
|
|
||||||
impl fmt::Display for Expression {
|
impl fmt::Display for Expression {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {} {}", self.l, self.o, self.r)
|
match self {
|
||||||
|
Self::Unary {
|
||||||
|
o,
|
||||||
|
v,
|
||||||
|
} => write!(f, "{o}{v}"),
|
||||||
|
Self::Binary {
|
||||||
|
l,
|
||||||
|
o,
|
||||||
|
r,
|
||||||
|
} => write!(f, "{l} {o} {r}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expression(i: &str) -> IResult<&str, Expression> {
|
pub fn unary(i: &str) -> IResult<&str, Expression> {
|
||||||
|
let (i, o) = operator::unary(i)?;
|
||||||
|
let (i, _) = mightbespace(i)?;
|
||||||
|
let (i, v) = single(i)?;
|
||||||
|
Ok((
|
||||||
|
i,
|
||||||
|
Expression::Unary {
|
||||||
|
o,
|
||||||
|
v,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary(i: &str) -> IResult<&str, Expression> {
|
||||||
let (i, l) = single(i)?;
|
let (i, l) = single(i)?;
|
||||||
let (i, o) = operator(i)?;
|
let (i, o) = operator::binary(i)?;
|
||||||
let (i, r) = value(i)?;
|
let (i, r) = value(i)?;
|
||||||
let v = match r {
|
let v = match r {
|
||||||
Value::Expression(r) => r.augment(l, o),
|
Value::Expression(r) => r.augment(l, o),
|
||||||
|
@ -152,7 +221,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_statement() {
|
fn expression_statement() {
|
||||||
let sql = "true AND false";
|
let sql = "true AND false";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("true AND false", format!("{}", out));
|
assert_eq!("true AND false", format!("{}", out));
|
||||||
|
@ -161,7 +230,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_left_opened() {
|
fn expression_left_opened() {
|
||||||
let sql = "3 * 3 * 3 = 27";
|
let sql = "3 * 3 * 3 = 27";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("3 * 3 * 3 = 27", format!("{}", out));
|
assert_eq!("3 * 3 * 3 = 27", format!("{}", out));
|
||||||
|
@ -170,7 +239,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_left_closed() {
|
fn expression_left_closed() {
|
||||||
let sql = "(3 * 3 * 3) = 27";
|
let sql = "(3 * 3 * 3) = 27";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("(3 * 3 * 3) = 27", format!("{}", out));
|
assert_eq!("(3 * 3 * 3) = 27", format!("{}", out));
|
||||||
|
@ -179,7 +248,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_right_opened() {
|
fn expression_right_opened() {
|
||||||
let sql = "27 = 3 * 3 * 3";
|
let sql = "27 = 3 * 3 * 3";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("27 = 3 * 3 * 3", format!("{}", out));
|
assert_eq!("27 = 3 * 3 * 3", format!("{}", out));
|
||||||
|
@ -188,7 +257,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_right_closed() {
|
fn expression_right_closed() {
|
||||||
let sql = "27 = (3 * 3 * 3)";
|
let sql = "27 = (3 * 3 * 3)";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("27 = (3 * 3 * 3)", format!("{}", out));
|
assert_eq!("27 = (3 * 3 * 3)", format!("{}", out));
|
||||||
|
@ -197,7 +266,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_both_opened() {
|
fn expression_both_opened() {
|
||||||
let sql = "3 * 3 * 3 = 3 * 3 * 3";
|
let sql = "3 * 3 * 3 = 3 * 3 * 3";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("3 * 3 * 3 = 3 * 3 * 3", format!("{}", out));
|
assert_eq!("3 * 3 * 3 = 3 * 3 * 3", format!("{}", out));
|
||||||
|
@ -206,9 +275,27 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression_both_closed() {
|
fn expression_both_closed() {
|
||||||
let sql = "(3 * 3 * 3) = (3 * 3 * 3)";
|
let sql = "(3 * 3 * 3) = (3 * 3 * 3)";
|
||||||
let res = expression(sql);
|
let res = binary(sql);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
let out = res.unwrap().1;
|
let out = res.unwrap().1;
|
||||||
assert_eq!("(3 * 3 * 3) = (3 * 3 * 3)", format!("{}", out));
|
assert_eq!("(3 * 3 * 3) = (3 * 3 * 3)", format!("{}", out));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expression_unary() {
|
||||||
|
let sql = "-a";
|
||||||
|
let res = unary(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(sql, format!("{}", out));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn expression_with_unary() {
|
||||||
|
let sql = "-(5) + 5";
|
||||||
|
let res = binary(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(sql, format!("{}", out));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::fmt::{self, Display, Formatter};
|
||||||
use std::hash;
|
use std::hash;
|
||||||
use std::iter::Product;
|
use std::iter::Product;
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
use std::ops;
|
use std::ops::{self, Neg};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Number";
|
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Number";
|
||||||
|
@ -572,6 +572,18 @@ impl<'a, 'b> ops::Div<&'b Number> for &'a Number {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Neg for Number {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Self::Int(n) => Number::Int(-n),
|
||||||
|
Self::Float(n) => Number::Float(-n),
|
||||||
|
Self::Decimal(n) => Number::Decimal(-n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
|
|
||||||
impl Sum<Self> for Number {
|
impl Sum<Self> for Number {
|
||||||
|
|
|
@ -11,8 +11,12 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
/// Binary operators.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
|
//
|
||||||
|
Neg, // -
|
||||||
|
Not, // !
|
||||||
//
|
//
|
||||||
Or, // ||
|
Or, // ||
|
||||||
And, // &&
|
And, // &&
|
||||||
|
@ -70,14 +74,14 @@ impl Operator {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn precedence(&self) -> u8 {
|
pub fn precedence(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Operator::Or => 1,
|
Self::Or => 1,
|
||||||
Operator::And => 2,
|
Self::And => 2,
|
||||||
Operator::Tco => 3,
|
Self::Tco => 3,
|
||||||
Operator::Nco => 4,
|
Self::Nco => 4,
|
||||||
Operator::Sub => 6,
|
Self::Sub => 6,
|
||||||
Operator::Add => 7,
|
Self::Add => 7,
|
||||||
Operator::Mul => 8,
|
Self::Mul => 8,
|
||||||
Operator::Div => 9,
|
Self::Div => 9,
|
||||||
_ => 5,
|
_ => 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +90,8 @@ impl Operator {
|
||||||
impl fmt::Display for Operator {
|
impl fmt::Display for Operator {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Neg => f.write_str("-"),
|
||||||
|
Self::Not => f.write_str("!"),
|
||||||
Self::Or => f.write_str("OR"),
|
Self::Or => f.write_str("OR"),
|
||||||
Self::And => f.write_str("AND"),
|
Self::And => f.write_str("AND"),
|
||||||
Self::Tco => f.write_str("?:"),
|
Self::Tco => f.write_str("?:"),
|
||||||
|
@ -143,11 +149,23 @@ pub fn assigner(i: &str) -> IResult<&str, Operator> {
|
||||||
))(i)
|
))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operator(i: &str) -> IResult<&str, Operator> {
|
pub fn unary(i: &str) -> IResult<&str, Operator> {
|
||||||
alt((symbols, phrases))(i)
|
unary_symbols(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symbols(i: &str) -> IResult<&str, Operator> {
|
pub fn unary_symbols(i: &str) -> IResult<&str, Operator> {
|
||||||
|
let (i, _) = mightbespace(i)?;
|
||||||
|
let (i, v) =
|
||||||
|
alt((alt((map(tag("-"), |_| Operator::Neg), map(tag("!"), |_| Operator::Not))),))(i)?;
|
||||||
|
let (i, _) = mightbespace(i)?;
|
||||||
|
Ok((i, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary(i: &str) -> IResult<&str, Operator> {
|
||||||
|
alt((binary_symbols, binary_phrases))(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binary_symbols(i: &str) -> IResult<&str, Operator> {
|
||||||
let (i, _) = mightbespace(i)?;
|
let (i, _) = mightbespace(i)?;
|
||||||
let (i, v) = alt((
|
let (i, v) = alt((
|
||||||
alt((
|
alt((
|
||||||
|
@ -203,7 +221,7 @@ pub fn symbols(i: &str) -> IResult<&str, Operator> {
|
||||||
Ok((i, v))
|
Ok((i, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn phrases(i: &str) -> IResult<&str, Operator> {
|
pub fn binary_phrases(i: &str) -> IResult<&str, Operator> {
|
||||||
let (i, _) = shouldbespace(i)?;
|
let (i, _) = shouldbespace(i)?;
|
||||||
let (i, v) = alt((
|
let (i, v) = alt((
|
||||||
alt((
|
alt((
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::sql::array::{array, Array};
|
use crate::sql::array::{array, Array};
|
||||||
use crate::sql::expression::{expression, Expression};
|
use crate::sql::expression::{binary, Expression};
|
||||||
use crate::sql::idiom::{idiom, Idiom};
|
use crate::sql::idiom::{idiom, Idiom};
|
||||||
use crate::sql::param::{param, Param};
|
use crate::sql::param::{param, Param};
|
||||||
use crate::sql::script::{script, Script};
|
use crate::sql::script::{script, Script};
|
||||||
|
@ -48,6 +48,6 @@ impl Parse<Self> for Thing {
|
||||||
|
|
||||||
impl Parse<Self> for Expression {
|
impl Parse<Self> for Expression {
|
||||||
fn parse(val: &str) -> Self {
|
fn parse(val: &str) -> Self {
|
||||||
expression(val).unwrap().1
|
binary(val).unwrap().1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,29 +19,104 @@ impl ser::Serializer for Serializer {
|
||||||
type SerializeTupleStruct = Impossible<Expression, Error>;
|
type SerializeTupleStruct = Impossible<Expression, Error>;
|
||||||
type SerializeTupleVariant = Impossible<Expression, Error>;
|
type SerializeTupleVariant = Impossible<Expression, Error>;
|
||||||
type SerializeMap = Impossible<Expression, Error>;
|
type SerializeMap = Impossible<Expression, Error>;
|
||||||
type SerializeStruct = SerializeExpression;
|
type SerializeStruct = Impossible<Expression, Error>;
|
||||||
type SerializeStructVariant = Impossible<Expression, Error>;
|
type SerializeStructVariant = SerializeExpression;
|
||||||
|
|
||||||
const EXPECTED: &'static str = "a struct `Expression`";
|
const EXPECTED: &'static str = "an enum `Expression`";
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_struct(
|
fn serialize_struct_variant(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
name: &'static str,
|
||||||
|
_variant_index: u32,
|
||||||
|
variant: &'static str,
|
||||||
_len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeStruct, Error> {
|
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||||
Ok(SerializeExpression::default())
|
debug_assert_eq!(name, crate::sql::expression::TOKEN);
|
||||||
|
match variant {
|
||||||
|
"Unary" => Ok(SerializeExpression::Unary(Default::default())),
|
||||||
|
"Binary" => Ok(SerializeExpression::Binary(Default::default())),
|
||||||
|
_ => Err(Error::custom(format!("unexpected `Expression::{name}`"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) enum SerializeExpression {
|
||||||
|
Unary(SerializeUnary),
|
||||||
|
Binary(SerializeBinary),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeStructVariant for SerializeExpression {
|
||||||
|
type Ok = Expression;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Unary(unary) => unary.serialize_field(key, value),
|
||||||
|
Self::Binary(binary) => binary.serialize_field(key, value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Self::Ok, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Unary(unary) => unary.end(),
|
||||||
|
Self::Binary(binary) => binary.end(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(super) struct SerializeExpression {
|
pub(super) struct SerializeUnary {
|
||||||
|
o: Option<Operator>,
|
||||||
|
v: Option<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeStructVariant for SerializeUnary {
|
||||||
|
type Ok = Expression;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
match key {
|
||||||
|
"o" => {
|
||||||
|
self.o = Some(value.serialize(ser::operator::Serializer.wrap())?);
|
||||||
|
}
|
||||||
|
"v" => {
|
||||||
|
self.v = Some(value.serialize(ser::value::Serializer.wrap())?);
|
||||||
|
}
|
||||||
|
key => {
|
||||||
|
return Err(Error::custom(format!(
|
||||||
|
"unexpected field `Expression::Unary{{{key}}}`"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Self::Ok, Error> {
|
||||||
|
match (self.o, self.v) {
|
||||||
|
(Some(o), Some(v)) => Ok(Expression::Unary {
|
||||||
|
o,
|
||||||
|
v,
|
||||||
|
}),
|
||||||
|
_ => Err(Error::custom("`Expression::Unary` missing required field(s)")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct SerializeBinary {
|
||||||
l: Option<Value>,
|
l: Option<Value>,
|
||||||
o: Option<Operator>,
|
o: Option<Operator>,
|
||||||
r: Option<Value>,
|
r: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serde::ser::SerializeStruct for SerializeExpression {
|
impl serde::ser::SerializeStructVariant for SerializeBinary {
|
||||||
type Ok = Expression;
|
type Ok = Expression;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
@ -60,7 +135,9 @@ impl serde::ser::SerializeStruct for SerializeExpression {
|
||||||
self.r = Some(value.serialize(ser::value::Serializer.wrap())?);
|
self.r = Some(value.serialize(ser::value::Serializer.wrap())?);
|
||||||
}
|
}
|
||||||
key => {
|
key => {
|
||||||
return Err(Error::custom(format!("unexpected field `Expression::{key}`")));
|
return Err(Error::custom(format!(
|
||||||
|
"unexpected field `Expression::Binary{{{key}}}`"
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -68,12 +145,12 @@ impl serde::ser::SerializeStruct for SerializeExpression {
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Error> {
|
fn end(self) -> Result<Self::Ok, Error> {
|
||||||
match (self.l, self.o, self.r) {
|
match (self.l, self.o, self.r) {
|
||||||
(Some(l), Some(o), Some(r)) => Ok(Expression {
|
(Some(l), Some(o), Some(r)) => Ok(Expression::Binary {
|
||||||
l,
|
l,
|
||||||
o,
|
o,
|
||||||
r,
|
r,
|
||||||
}),
|
}),
|
||||||
_ => Err(Error::custom("`Expression` missing required field(s)")),
|
_ => Err(Error::custom("`Expression::Binary` missing required field(s)")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,9 +167,19 @@ mod tests {
|
||||||
assert_eq!(expression, serialized);
|
assert_eq!(expression, serialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unary() {
|
||||||
|
let expression = Expression::Unary {
|
||||||
|
o: Operator::Not,
|
||||||
|
v: "Bar".into(),
|
||||||
|
};
|
||||||
|
let serialized = expression.serialize(Serializer.wrap()).unwrap();
|
||||||
|
assert_eq!(expression, serialized);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn foo_equals_bar() {
|
fn foo_equals_bar() {
|
||||||
let expression = Expression {
|
let expression = Expression::Binary {
|
||||||
l: "foo".into(),
|
l: "foo".into(),
|
||||||
o: Operator::Equal,
|
o: Operator::Equal,
|
||||||
r: "Bar".into(),
|
r: "Bar".into(),
|
||||||
|
|
|
@ -28,6 +28,8 @@ impl ser::Serializer for Serializer {
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
) -> Result<Self::Ok, Error> {
|
) -> Result<Self::Ok, Error> {
|
||||||
match variant {
|
match variant {
|
||||||
|
"Neg" => Ok(Operator::Neg),
|
||||||
|
"Not" => Ok(Operator::Not),
|
||||||
"Or" => Ok(Operator::Or),
|
"Or" => Ok(Operator::Or),
|
||||||
"And" => Ok(Operator::And),
|
"And" => Ok(Operator::And),
|
||||||
"Tco" => Ok(Operator::Tco),
|
"Tco" => Ok(Operator::Tco),
|
||||||
|
|
|
@ -20,6 +20,7 @@ use crate::sql::Table;
|
||||||
use crate::sql::Uuid;
|
use crate::sql::Uuid;
|
||||||
use map::SerializeValueMap;
|
use map::SerializeValueMap;
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
use ser::cast::SerializeCast;
|
||||||
use ser::edges::SerializeEdges;
|
use ser::edges::SerializeEdges;
|
||||||
use ser::expression::SerializeExpression;
|
use ser::expression::SerializeExpression;
|
||||||
use ser::function::SerializeFunction;
|
use ser::function::SerializeFunction;
|
||||||
|
@ -60,7 +61,7 @@ impl ser::Serializer for Serializer {
|
||||||
|
|
||||||
type SerializeSeq = SerializeArray;
|
type SerializeSeq = SerializeArray;
|
||||||
type SerializeTuple = SerializeArray;
|
type SerializeTuple = SerializeArray;
|
||||||
type SerializeTupleStruct = SerializeArray;
|
type SerializeTupleStruct = SerializeTupleStruct;
|
||||||
type SerializeTupleVariant = SerializeTupleVariant;
|
type SerializeTupleVariant = SerializeTupleVariant;
|
||||||
type SerializeMap = SerializeMap;
|
type SerializeMap = SerializeMap;
|
||||||
type SerializeStruct = SerializeStruct;
|
type SerializeStruct = SerializeStruct;
|
||||||
|
@ -299,10 +300,13 @@ impl ser::Serializer for Serializer {
|
||||||
|
|
||||||
fn serialize_tuple_struct(
|
fn serialize_tuple_struct(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
name: &'static str,
|
||||||
len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeTupleStruct, Error> {
|
) -> Result<Self::SerializeTupleStruct, Error> {
|
||||||
self.serialize_seq(Some(len))
|
match name {
|
||||||
|
sql::cast::TOKEN => Ok(SerializeTupleStruct::Cast(Default::default())),
|
||||||
|
_ => Ok(SerializeTupleStruct::Array(Default::default())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple_variant(
|
fn serialize_tuple_variant(
|
||||||
|
@ -347,7 +351,6 @@ impl ser::Serializer for Serializer {
|
||||||
) -> Result<Self::SerializeStruct, Error> {
|
) -> Result<Self::SerializeStruct, Error> {
|
||||||
Ok(match name {
|
Ok(match name {
|
||||||
sql::thing::TOKEN => SerializeStruct::Thing(Default::default()),
|
sql::thing::TOKEN => SerializeStruct::Thing(Default::default()),
|
||||||
sql::expression::TOKEN => SerializeStruct::Expression(Default::default()),
|
|
||||||
sql::edges::TOKEN => SerializeStruct::Edges(Default::default()),
|
sql::edges::TOKEN => SerializeStruct::Edges(Default::default()),
|
||||||
sql::range::TOKEN => SerializeStruct::Range(Default::default()),
|
sql::range::TOKEN => SerializeStruct::Range(Default::default()),
|
||||||
_ => SerializeStruct::Unknown(Default::default()),
|
_ => SerializeStruct::Unknown(Default::default()),
|
||||||
|
@ -356,18 +359,27 @@ impl ser::Serializer for Serializer {
|
||||||
|
|
||||||
fn serialize_struct_variant(
|
fn serialize_struct_variant(
|
||||||
self,
|
self,
|
||||||
_name: &'static str,
|
name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
variant: &'static str,
|
variant: &'static str,
|
||||||
_len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, Error> {
|
) -> Result<Self::SerializeStructVariant, Error> {
|
||||||
Ok(SerializeStructVariant {
|
Ok(if name == sql::expression::TOKEN {
|
||||||
name: String::from(variant),
|
SerializeStructVariant::Expression(match variant {
|
||||||
map: Object::default(),
|
"Unary" => SerializeExpression::Unary(Default::default()),
|
||||||
|
"Binary" => SerializeExpression::Binary(Default::default()),
|
||||||
|
_ => return Err(Error::custom(format!("unexpected `Expression::{name}`"))),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
SerializeStructVariant::Object {
|
||||||
|
name: String::from(variant),
|
||||||
|
map: Object::default(),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub(super) struct SerializeArray(vec::SerializeValueVec);
|
pub(super) struct SerializeArray(vec::SerializeValueVec);
|
||||||
|
|
||||||
impl serde::ser::SerializeSeq for SerializeArray {
|
impl serde::ser::SerializeSeq for SerializeArray {
|
||||||
|
@ -452,6 +464,33 @@ pub(super) enum SerializeTupleVariant {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) enum SerializeTupleStruct {
|
||||||
|
Cast(SerializeCast),
|
||||||
|
Array(SerializeArray),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::ser::SerializeTupleStruct for SerializeTupleStruct {
|
||||||
|
type Ok = Value;
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: ?Sized + Serialize,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Cast(cast) => cast.serialize_field(value),
|
||||||
|
Self::Array(array) => array.serialize_field(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Value, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Cast(cast) => Ok(Value::Cast(Box::new(cast.end()?))),
|
||||||
|
Self::Array(array) => Ok(serde::ser::SerializeTupleStruct::end(array)?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||||
type Ok = Value;
|
type Ok = Value;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
@ -461,9 +500,9 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||||
T: ?Sized + Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
SerializeTupleVariant::Model(model) => model.serialize_field(value),
|
Self::Model(model) => model.serialize_field(value),
|
||||||
SerializeTupleVariant::Function(function) => function.serialize_field(value),
|
Self::Function(function) => function.serialize_field(value),
|
||||||
SerializeTupleVariant::Unknown {
|
Self::Unknown {
|
||||||
ref mut fields,
|
ref mut fields,
|
||||||
..
|
..
|
||||||
} => fields.serialize_element(value),
|
} => fields.serialize_element(value),
|
||||||
|
@ -472,11 +511,9 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||||
|
|
||||||
fn end(self) -> Result<Value, Error> {
|
fn end(self) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
SerializeTupleVariant::Model(model) => Ok(Value::Model(model.end()?)),
|
Self::Model(model) => Ok(Value::Model(model.end()?)),
|
||||||
SerializeTupleVariant::Function(function) => {
|
Self::Function(function) => Ok(Value::Function(Box::new(function.end()?))),
|
||||||
Ok(Value::Function(Box::new(function.end()?)))
|
Self::Unknown {
|
||||||
}
|
|
||||||
SerializeTupleVariant::Unknown {
|
|
||||||
variant,
|
variant,
|
||||||
fields,
|
fields,
|
||||||
} => Ok(map! {
|
} => Ok(map! {
|
||||||
|
@ -489,7 +526,6 @@ impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
|
||||||
|
|
||||||
pub(super) enum SerializeStruct {
|
pub(super) enum SerializeStruct {
|
||||||
Thing(SerializeThing),
|
Thing(SerializeThing),
|
||||||
Expression(SerializeExpression),
|
|
||||||
Edges(SerializeEdges),
|
Edges(SerializeEdges),
|
||||||
Range(SerializeRange),
|
Range(SerializeRange),
|
||||||
Unknown(SerializeValueMap),
|
Unknown(SerializeValueMap),
|
||||||
|
@ -504,28 +540,29 @@ impl serde::ser::SerializeStruct for SerializeStruct {
|
||||||
T: ?Sized + Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
SerializeStruct::Thing(thing) => thing.serialize_field(key, value),
|
Self::Thing(thing) => thing.serialize_field(key, value),
|
||||||
SerializeStruct::Expression(expr) => expr.serialize_field(key, value),
|
Self::Edges(edges) => edges.serialize_field(key, value),
|
||||||
SerializeStruct::Edges(edges) => edges.serialize_field(key, value),
|
Self::Range(range) => range.serialize_field(key, value),
|
||||||
SerializeStruct::Range(range) => range.serialize_field(key, value),
|
Self::Unknown(map) => map.serialize_entry(key, value),
|
||||||
SerializeStruct::Unknown(map) => map.serialize_entry(key, value),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Value, Error> {
|
fn end(self) -> Result<Value, Error> {
|
||||||
match self {
|
match self {
|
||||||
SerializeStruct::Thing(thing) => Ok(Value::Thing(thing.end()?)),
|
Self::Thing(thing) => Ok(Value::Thing(thing.end()?)),
|
||||||
SerializeStruct::Expression(expr) => Ok(Value::Expression(Box::new(expr.end()?))),
|
Self::Edges(edges) => Ok(Value::Edges(Box::new(edges.end()?))),
|
||||||
SerializeStruct::Edges(edges) => Ok(Value::Edges(Box::new(edges.end()?))),
|
Self::Range(range) => Ok(Value::Range(Box::new(range.end()?))),
|
||||||
SerializeStruct::Range(range) => Ok(Value::Range(Box::new(range.end()?))),
|
Self::Unknown(map) => Ok(Value::Object(Object(map.end()?))),
|
||||||
SerializeStruct::Unknown(map) => Ok(Value::Object(Object(map.end()?))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct SerializeStructVariant {
|
pub(super) enum SerializeStructVariant {
|
||||||
name: String,
|
Expression(SerializeExpression),
|
||||||
map: Object,
|
Object {
|
||||||
|
name: String,
|
||||||
|
map: Object,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
||||||
|
@ -536,16 +573,32 @@ impl serde::ser::SerializeStructVariant for SerializeStructVariant {
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: ?Sized + Serialize,
|
||||||
{
|
{
|
||||||
self.map.0.insert(String::from(key), value.serialize(Serializer.wrap())?);
|
match self {
|
||||||
Ok(())
|
Self::Expression(expression) => expression.serialize_field(key, value),
|
||||||
|
Self::Object {
|
||||||
|
map,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
map.0.insert(String::from(key), value.serialize(Serializer.wrap())?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Value, Error> {
|
fn end(self) -> Result<Value, Error> {
|
||||||
let mut object = Object::default();
|
match self {
|
||||||
|
Self::Expression(expression) => Ok(Value::from(expression.end()?)),
|
||||||
|
Self::Object {
|
||||||
|
name,
|
||||||
|
map,
|
||||||
|
} => {
|
||||||
|
let mut object = Object::default();
|
||||||
|
|
||||||
object.insert(self.name, Value::Object(self.map));
|
object.insert(name, Value::Object(map));
|
||||||
|
|
||||||
Ok(Value::Object(object))
|
Ok(Value::Object(object))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,7 +878,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expression() {
|
fn expression() {
|
||||||
let expression = Box::new(Expression {
|
let expression = Box::new(Expression::Binary {
|
||||||
l: "foo".into(),
|
l: "foo".into(),
|
||||||
o: Operator::Equal,
|
o: Operator::Equal,
|
||||||
r: "Bar".into(),
|
r: "Bar".into(),
|
||||||
|
|
|
@ -38,6 +38,7 @@ impl ser::Serializer for Serializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct SerializeValueVec(pub Vec<Value>);
|
pub struct SerializeValueVec(pub Vec<Value>);
|
||||||
|
|
||||||
impl serde::ser::SerializeSeq for SerializeValueVec {
|
impl serde::ser::SerializeSeq for SerializeValueVec {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::sql::datetime::{datetime, Datetime};
|
||||||
use crate::sql::duration::{duration, Duration};
|
use crate::sql::duration::{duration, Duration};
|
||||||
use crate::sql::edges::{edges, Edges};
|
use crate::sql::edges::{edges, Edges};
|
||||||
use crate::sql::error::IResult;
|
use crate::sql::error::IResult;
|
||||||
use crate::sql::expression::{expression, Expression};
|
use crate::sql::expression::{binary, unary, Expression};
|
||||||
use crate::sql::fmt::{Fmt, Pretty};
|
use crate::sql::fmt::{Fmt, Pretty};
|
||||||
use crate::sql::function::{self, function, Function};
|
use crate::sql::function::{self, function, Function};
|
||||||
use crate::sql::future::{future, Future};
|
use crate::sql::future::{future, Future};
|
||||||
|
@ -58,6 +58,7 @@ use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Display, Formatter, Write};
|
use std::fmt::{self, Display, Formatter, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::ops::Neg;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
static MATCHER: Lazy<SkimMatcherV2> = Lazy::new(|| SkimMatcherV2::default().ignore_case());
|
static MATCHER: Lazy<SkimMatcherV2> = Lazy::new(|| SkimMatcherV2::default().ignore_case());
|
||||||
|
@ -2477,7 +2478,7 @@ impl Value {
|
||||||
Value::Object(v) => v.iter().any(|(_, v)| v.writeable()),
|
Value::Object(v) => v.iter().any(|(_, v)| v.writeable()),
|
||||||
Value::Function(v) => v.is_custom() || v.args().iter().any(Value::writeable),
|
Value::Function(v) => v.is_custom() || v.args().iter().any(Value::writeable),
|
||||||
Value::Subquery(v) => v.writeable(),
|
Value::Subquery(v) => v.writeable(),
|
||||||
Value::Expression(v) => v.l.writeable() || v.r.writeable(),
|
Value::Expression(v) => v.writeable(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2658,9 +2659,24 @@ impl TryPow for Value {
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
|
|
||||||
/// Parse any `Value` including binary expressions
|
pub(crate) trait TryNeg<Rhs = Self> {
|
||||||
|
type Output;
|
||||||
|
fn try_neg(self) -> Result<Self::Output, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryNeg for Value {
|
||||||
|
type Output = Self;
|
||||||
|
fn try_neg(self) -> Result<Self, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Number(n) if !matches!(n, Number::Int(i64::MIN)) => Ok(Self::Number(n.neg())),
|
||||||
|
v => Err(Error::TryNeg(v.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse any `Value` including expressions
|
||||||
pub fn value(i: &str) -> IResult<&str, Value> {
|
pub fn value(i: &str) -> IResult<&str, Value> {
|
||||||
alt((map(expression, Value::from), single))(i)
|
alt((map(binary, Value::from), single))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse any `Value` excluding binary expressions
|
/// Parse any `Value` excluding binary expressions
|
||||||
|
@ -2684,8 +2700,11 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
||||||
map(future, Value::from),
|
map(future, Value::from),
|
||||||
map(unique, Value::from),
|
map(unique, Value::from),
|
||||||
map(number, Value::from),
|
map(number, Value::from),
|
||||||
|
map(unary, Value::from),
|
||||||
map(object, Value::from),
|
map(object, Value::from),
|
||||||
map(array, Value::from),
|
map(array, Value::from),
|
||||||
|
)),
|
||||||
|
alt((
|
||||||
map(block, Value::from),
|
map(block, Value::from),
|
||||||
map(param, Value::from),
|
map(param, Value::from),
|
||||||
map(regex, Value::from),
|
map(regex, Value::from),
|
||||||
|
@ -2702,7 +2721,8 @@ pub fn single(i: &str) -> IResult<&str, Value> {
|
||||||
pub fn select(i: &str) -> IResult<&str, Value> {
|
pub fn select(i: &str) -> IResult<&str, Value> {
|
||||||
alt((
|
alt((
|
||||||
alt((
|
alt((
|
||||||
map(expression, Value::from),
|
map(unary, Value::from),
|
||||||
|
map(binary, Value::from),
|
||||||
map(tag_no_case("NONE"), |_| Value::None),
|
map(tag_no_case("NONE"), |_| Value::None),
|
||||||
map(tag_no_case("NULL"), |_| Value::Null),
|
map(tag_no_case("NULL"), |_| Value::Null),
|
||||||
map(tag_no_case("true"), |_| Value::Bool(true)),
|
map(tag_no_case("true"), |_| Value::Bool(true)),
|
||||||
|
|
|
@ -65,6 +65,64 @@ async fn select_field_value() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn select_expression_value() -> Result<(), Error> {
|
||||||
|
let sql = "
|
||||||
|
CREATE thing:a SET number = 5, boolean = true;
|
||||||
|
CREATE thing:b SET number = -5, boolean = false;
|
||||||
|
SELECT VALUE -number FROM thing;
|
||||||
|
SELECT VALUE !boolean FROM thing;
|
||||||
|
";
|
||||||
|
let dbs = Datastore::new("memory").await?;
|
||||||
|
let ses = Session::for_kv().with_ns("test").with_db("test");
|
||||||
|
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
|
||||||
|
assert_eq!(res.len(), 4);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
boolean: true,
|
||||||
|
id: thing:a,
|
||||||
|
number: 5
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
boolean: false,
|
||||||
|
id: thing:b,
|
||||||
|
number: -5
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
-5,
|
||||||
|
5,
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn select_writeable_subqueries() -> Result<(), Error> {
|
async fn select_writeable_subqueries() -> Result<(), Error> {
|
||||||
let sql = "
|
let sql = "
|
||||||
|
|
Loading…
Reference in a new issue