From 4c1ceac6eb5ddbc382d7fa7f6d306a467df3a186 Mon Sep 17 00:00:00 2001 From: Finn Bear Date: Mon, 23 Oct 2023 06:37:21 -0700 Subject: [PATCH] Feature #2720 - add remainder aka modulo operator. (#2868) --- lib/src/err/mod.rs | 4 ++++ lib/src/fnc/operate.rs | 12 +++++------- lib/src/sql/expression.rs | 1 + lib/src/sql/number.rs | 5 +++-- lib/src/sql/operator.rs | 5 +++++ lib/src/sql/value/value.rs | 17 +++++++++++++++++ 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/src/err/mod.rs b/lib/src/err/mod.rs index 9f88b9e1..cd2e25a7 100644 --- a/lib/src/err/mod.rs +++ b/lib/src/err/mod.rs @@ -547,6 +547,10 @@ pub enum Error { #[error("Cannot perform division with '{0}' and '{1}'")] TryDiv(String, String), + /// Cannot perform remainder + #[error("Cannot perform remainder with '{0}' and '{1}'")] + TryRem(String, String), + /// Cannot perform power #[error("Cannot raise the value '{0}' with '{1}'")] TryPow(String, String), diff --git a/lib/src/fnc/operate.rs b/lib/src/fnc/operate.rs index 9d4cfc73..9f6e719c 100644 --- a/lib/src/fnc/operate.rs +++ b/lib/src/fnc/operate.rs @@ -3,13 +3,7 @@ use crate::dbs::Transaction; use crate::doc::CursorDoc; use crate::err::Error; use crate::idx::planner::executor::QueryExecutor; -use crate::sql::value::TryAdd; -use crate::sql::value::TryDiv; -use crate::sql::value::TryMul; -use crate::sql::value::TryNeg; -use crate::sql::value::TryPow; -use crate::sql::value::TrySub; -use crate::sql::value::Value; +use crate::sql::value::{TryAdd, TryDiv, TryMul, TryNeg, TryPow, TryRem, TrySub, Value}; use crate::sql::{Expression, Thing}; pub fn neg(a: Value) -> Result { @@ -64,6 +58,10 @@ pub fn div(a: Value, b: Value) -> Result { a.try_div(b) } +pub fn rem(a: Value, b: Value) -> Result { + a.try_rem(b) +} + pub fn pow(a: Value, b: Value) -> Result { a.try_pow(b) } diff --git a/lib/src/sql/expression.rs b/lib/src/sql/expression.rs index f302adfd..45faae2a 100644 --- a/lib/src/sql/expression.rs +++ b/lib/src/sql/expression.rs @@ -164,6 +164,7 @@ impl Expression { Operator::Sub => fnc::operate::sub(l, r), Operator::Mul => fnc::operate::mul(l, r), Operator::Div => fnc::operate::div(l, r), + Operator::Rem => fnc::operate::rem(l, r), Operator::Pow => fnc::operate::pow(l, r), Operator::Equal => fnc::operate::equal(&l, &r), Operator::Exact => fnc::operate::exact(&l, &r), diff --git a/lib/src/sql/number.rs b/lib/src/sql/number.rs index 3f30eda5..5d645178 100644 --- a/lib/src/sql/number.rs +++ b/lib/src/sql/number.rs @@ -1,4 +1,4 @@ -use super::value::{TryAdd, TryDiv, TryMul, TryNeg, TryPow, TrySub}; +use super::value::{TryAdd, TryDiv, TryMul, TryNeg, TryPow, TryRem, TrySub}; use crate::err::Error; use crate::sql::ending::number as ending; use crate::sql::error::{IResult, ParseError}; @@ -17,7 +17,7 @@ use std::fmt::{self, Display, Formatter}; use std::hash; use std::iter::Product; use std::iter::Sum; -use std::ops::{self, Add, Div, Mul, Neg, Sub}; +use std::ops::{self, Add, Div, Mul, Neg, Rem, Sub}; use std::str::FromStr; pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Number"; @@ -504,6 +504,7 @@ impl_simple_try_op!(TryAdd, try_add, add, checked_add); impl_simple_try_op!(TrySub, try_sub, sub, checked_sub); impl_simple_try_op!(TryMul, try_mul, mul, checked_mul); impl_simple_try_op!(TryDiv, try_div, div, checked_div); +impl_simple_try_op!(TryRem, try_rem, rem, checked_rem); impl TryPow for Number { type Output = Self; diff --git a/lib/src/sql/operator.rs b/lib/src/sql/operator.rs index f7a43d48..aaa5300a 100644 --- a/lib/src/sql/operator.rs +++ b/lib/src/sql/operator.rs @@ -70,6 +70,8 @@ pub enum Operator { Intersects, // Knn(u32), // <{k}> + // + Rem, // % } impl Default for Operator { @@ -90,6 +92,7 @@ impl Operator { Self::Add => 7, Self::Mul => 8, Self::Div => 9, + Self::Rem => 10, _ => 5, } } @@ -108,6 +111,7 @@ impl fmt::Display for Operator { Self::Sub => f.write_char('-'), Self::Mul => f.write_char('*'), Self::Div => f.write_char('/'), + Self::Rem => f.write_char('%'), Self::Pow => f.write_str("**"), Self::Inc => f.write_str("+="), Self::Dec => f.write_str("-="), @@ -213,6 +217,7 @@ pub fn binary_symbols(i: &str) -> IResult<&str, Operator> { value(Operator::Mul, char('∙')), value(Operator::Div, char('/')), value(Operator::Div, char('÷')), + value(Operator::Rem, char('%')), )), alt(( value(Operator::Contain, char('∋')), diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index 5795eb52..bd3006ca 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -2694,6 +2694,23 @@ impl TryDiv for Value { // ------------------------------ +pub(crate) trait TryRem { + type Output; + fn try_rem(self, v: Self) -> Result; +} + +impl TryRem for Value { + type Output = Self; + fn try_rem(self, other: Self) -> Result { + Ok(match (self, other) { + (Self::Number(v), Self::Number(w)) => Self::Number(v.try_rem(w)?), + (v, w) => return Err(Error::TryRem(v.to_raw_string(), w.to_raw_string())), + }) + } +} + +// ------------------------------ + pub(crate) trait TryPow { type Output; fn try_pow(self, v: Self) -> Result;