2023-06-21 18:31:15 +00:00
|
|
|
|
use crate::idx::ft::MatchRef;
|
2022-01-13 17:36:41 +00:00
|
|
|
|
use crate::sql::comment::mightbespace;
|
|
|
|
|
use crate::sql::comment::shouldbespace;
|
2022-01-16 20:31:50 +00:00
|
|
|
|
use crate::sql::error::IResult;
|
2020-06-29 15:36:01 +00:00
|
|
|
|
use nom::branch::alt;
|
|
|
|
|
use nom::bytes::complete::tag;
|
|
|
|
|
use nom::bytes::complete::tag_no_case;
|
2022-03-16 23:52:25 +00:00
|
|
|
|
use nom::character::complete::char;
|
2023-09-12 20:26:03 +00:00
|
|
|
|
use nom::character::complete::u32 as uint32;
|
2023-05-29 11:46:41 +00:00
|
|
|
|
use nom::character::complete::u8 as uint8;
|
2023-08-29 10:50:00 +00:00
|
|
|
|
use nom::combinator::cut;
|
|
|
|
|
use nom::combinator::opt;
|
|
|
|
|
use nom::combinator::value;
|
2023-08-17 18:03:46 +00:00
|
|
|
|
use revision::revisioned;
|
2020-06-29 15:36:01 +00:00
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::fmt;
|
2023-05-29 11:46:41 +00:00
|
|
|
|
use std::fmt::Write;
|
2020-06-29 15:36:01 +00:00
|
|
|
|
|
2023-06-20 23:31:23 +00:00
|
|
|
|
/// Binary operators.
|
2022-10-27 12:23:24 +00:00
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
2023-08-17 18:03:46 +00:00
|
|
|
|
#[revisioned(revision = 1)]
|
2020-06-29 15:36:01 +00:00
|
|
|
|
pub enum Operator {
|
2023-06-20 23:31:23 +00:00
|
|
|
|
//
|
|
|
|
|
Neg, // -
|
|
|
|
|
Not, // !
|
2022-12-02 21:48:10 +00:00
|
|
|
|
//
|
2020-06-29 15:36:01 +00:00
|
|
|
|
Or, // ||
|
2021-03-29 15:43:37 +00:00
|
|
|
|
And, // &&
|
2022-12-02 21:48:10 +00:00
|
|
|
|
Tco, // ?: Ternary conditional operator
|
|
|
|
|
Nco, // ?? Null coalescing operator
|
2020-06-29 15:36:01 +00:00
|
|
|
|
//
|
|
|
|
|
Add, // +
|
|
|
|
|
Sub, // -
|
|
|
|
|
Mul, // *
|
|
|
|
|
Div, // /
|
2022-12-18 14:56:07 +00:00
|
|
|
|
Pow, // **
|
2020-06-29 15:36:01 +00:00
|
|
|
|
Inc, // +=
|
|
|
|
|
Dec, // -=
|
2023-03-25 23:17:33 +00:00
|
|
|
|
Ext, // +?=
|
2020-06-29 15:36:01 +00:00
|
|
|
|
//
|
|
|
|
|
Equal, // =
|
2022-12-02 21:48:10 +00:00
|
|
|
|
Exact, // ==
|
2020-06-29 15:36:01 +00:00
|
|
|
|
NotEqual, // !=
|
|
|
|
|
AllEqual, // *=
|
|
|
|
|
AnyEqual, // ?=
|
|
|
|
|
//
|
2023-06-21 18:31:15 +00:00
|
|
|
|
Like, // ~
|
|
|
|
|
NotLike, // !~
|
|
|
|
|
AllLike, // *~
|
|
|
|
|
AnyLike, // ?~
|
|
|
|
|
Matches(Option<MatchRef>), // @{ref}@
|
2020-06-29 15:36:01 +00:00
|
|
|
|
//
|
|
|
|
|
LessThan, // <
|
|
|
|
|
LessThanOrEqual, // <=
|
|
|
|
|
MoreThan, // >
|
|
|
|
|
MoreThanOrEqual, // >=
|
|
|
|
|
//
|
|
|
|
|
Contain, // ∋
|
|
|
|
|
NotContain, // ∌
|
|
|
|
|
ContainAll, // ⊇
|
2022-01-13 17:36:41 +00:00
|
|
|
|
ContainAny, // ⊃
|
2020-06-29 15:36:01 +00:00
|
|
|
|
ContainNone, // ⊅
|
|
|
|
|
Inside, // ∈
|
|
|
|
|
NotInside, // ∉
|
|
|
|
|
AllInside, // ⊆
|
2022-01-13 17:36:41 +00:00
|
|
|
|
AnyInside, // ⊂
|
2020-06-29 15:36:01 +00:00
|
|
|
|
NoneInside, // ⊄
|
2022-11-03 10:59:01 +00:00
|
|
|
|
//
|
|
|
|
|
Outside,
|
|
|
|
|
Intersects,
|
2023-09-12 20:26:03 +00:00
|
|
|
|
//
|
|
|
|
|
Knn(u32), // <{k}>
|
2020-06-29 15:36:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Operator {
|
2022-10-04 21:51:18 +00:00
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::Equal
|
2020-06-29 15:36:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-13 00:18:23 +00:00
|
|
|
|
impl Operator {
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn precedence(&self) -> u8 {
|
|
|
|
|
match self {
|
2023-06-20 23:31:23 +00:00
|
|
|
|
Self::Or => 1,
|
|
|
|
|
Self::And => 2,
|
|
|
|
|
Self::Tco => 3,
|
|
|
|
|
Self::Nco => 4,
|
|
|
|
|
Self::Sub => 6,
|
|
|
|
|
Self::Add => 7,
|
|
|
|
|
Self::Mul => 8,
|
|
|
|
|
Self::Div => 9,
|
2022-12-02 21:48:10 +00:00
|
|
|
|
_ => 5,
|
2022-03-13 00:18:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-29 15:36:01 +00:00
|
|
|
|
impl fmt::Display for Operator {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2023-05-29 11:46:41 +00:00
|
|
|
|
match self {
|
2023-06-20 23:31:23 +00:00
|
|
|
|
Self::Neg => f.write_str("-"),
|
|
|
|
|
Self::Not => f.write_str("!"),
|
2023-05-29 11:46:41 +00:00
|
|
|
|
Self::Or => f.write_str("OR"),
|
|
|
|
|
Self::And => f.write_str("AND"),
|
|
|
|
|
Self::Tco => f.write_str("?:"),
|
|
|
|
|
Self::Nco => f.write_str("??"),
|
|
|
|
|
Self::Add => f.write_str("+"),
|
|
|
|
|
Self::Sub => f.write_char('-'),
|
|
|
|
|
Self::Mul => f.write_char('*'),
|
|
|
|
|
Self::Div => f.write_char('/'),
|
|
|
|
|
Self::Pow => f.write_str("**"),
|
|
|
|
|
Self::Inc => f.write_str("+="),
|
|
|
|
|
Self::Dec => f.write_str("-="),
|
|
|
|
|
Self::Ext => f.write_str("+?="),
|
|
|
|
|
Self::Equal => f.write_char('='),
|
|
|
|
|
Self::Exact => f.write_str("=="),
|
|
|
|
|
Self::NotEqual => f.write_str("!="),
|
|
|
|
|
Self::AllEqual => f.write_str("*="),
|
|
|
|
|
Self::AnyEqual => f.write_str("?="),
|
|
|
|
|
Self::Like => f.write_char('~'),
|
|
|
|
|
Self::NotLike => f.write_str("!~"),
|
|
|
|
|
Self::AllLike => f.write_str("*~"),
|
|
|
|
|
Self::AnyLike => f.write_str("?~"),
|
|
|
|
|
Self::LessThan => f.write_char('<'),
|
|
|
|
|
Self::LessThanOrEqual => f.write_str("<="),
|
|
|
|
|
Self::MoreThan => f.write_char('>'),
|
|
|
|
|
Self::MoreThanOrEqual => f.write_str(">="),
|
|
|
|
|
Self::Contain => f.write_str("CONTAINS"),
|
|
|
|
|
Self::NotContain => f.write_str("CONTAINSNOT"),
|
|
|
|
|
Self::ContainAll => f.write_str("CONTAINSALL"),
|
|
|
|
|
Self::ContainAny => f.write_str("CONTAINSANY"),
|
|
|
|
|
Self::ContainNone => f.write_str("CONTAINSNONE"),
|
|
|
|
|
Self::Inside => f.write_str("INSIDE"),
|
|
|
|
|
Self::NotInside => f.write_str("NOTINSIDE"),
|
|
|
|
|
Self::AllInside => f.write_str("ALLINSIDE"),
|
|
|
|
|
Self::AnyInside => f.write_str("ANYINSIDE"),
|
|
|
|
|
Self::NoneInside => f.write_str("NONEINSIDE"),
|
|
|
|
|
Self::Outside => f.write_str("OUTSIDE"),
|
|
|
|
|
Self::Intersects => f.write_str("INTERSECTS"),
|
|
|
|
|
Self::Matches(reference) => {
|
|
|
|
|
if let Some(r) = reference {
|
|
|
|
|
write!(f, "@{}@", r)
|
|
|
|
|
} else {
|
|
|
|
|
f.write_str("@@")
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-12 20:26:03 +00:00
|
|
|
|
Self::Knn(k) => write!(f, "<{}>", k),
|
2023-05-29 11:46:41 +00:00
|
|
|
|
}
|
2020-06-29 15:36:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn assigner(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Equal, char('=')),
|
|
|
|
|
value(Operator::Inc, tag("+=")),
|
|
|
|
|
value(Operator::Dec, tag("-=")),
|
|
|
|
|
value(Operator::Ext, tag("+?=")),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
))(i)
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 23:31:23 +00:00
|
|
|
|
pub fn unary(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
unary_symbols(i)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn unary_symbols(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
let (i, _) = mightbespace(i)?;
|
2023-08-29 10:50:00 +00:00
|
|
|
|
let (i, v) = alt((value(Operator::Neg, tag("-")), value(Operator::Not, tag("!"))))(i)?;
|
2023-06-20 23:31:23 +00:00
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
|
Ok((i, v))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn binary(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
alt((binary_symbols, binary_phrases))(i)
|
2022-01-13 17:36:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 23:31:23 +00:00
|
|
|
|
pub fn binary_symbols(i: &str) -> IResult<&str, Operator> {
|
2022-01-13 17:36:41 +00:00
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
|
let (i, v) = alt((
|
2022-12-02 21:48:10 +00:00
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Or, tag("||")),
|
|
|
|
|
value(Operator::And, tag("&&")),
|
|
|
|
|
value(Operator::Tco, tag("?:")),
|
|
|
|
|
value(Operator::Nco, tag("??")),
|
2022-12-02 21:48:10 +00:00
|
|
|
|
)),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Exact, tag("==")),
|
|
|
|
|
value(Operator::NotEqual, tag("!=")),
|
|
|
|
|
value(Operator::AllEqual, tag("*=")),
|
|
|
|
|
value(Operator::AnyEqual, tag("?=")),
|
|
|
|
|
value(Operator::Equal, char('=')),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::NotLike, tag("!~")),
|
|
|
|
|
value(Operator::AllLike, tag("*~")),
|
|
|
|
|
value(Operator::AnyLike, tag("?~")),
|
|
|
|
|
value(Operator::Like, char('~')),
|
2023-05-29 11:46:41 +00:00
|
|
|
|
matches,
|
2023-09-12 20:26:03 +00:00
|
|
|
|
knn,
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::LessThanOrEqual, tag("<=")),
|
|
|
|
|
value(Operator::LessThan, char('<')),
|
|
|
|
|
value(Operator::MoreThanOrEqual, tag(">=")),
|
|
|
|
|
value(Operator::MoreThan, char('>')),
|
2023-09-12 20:26:03 +00:00
|
|
|
|
knn,
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
2021-05-22 18:18:02 +00:00
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Pow, tag("**")),
|
|
|
|
|
value(Operator::Add, char('+')),
|
|
|
|
|
value(Operator::Sub, char('-')),
|
|
|
|
|
value(Operator::Mul, char('*')),
|
|
|
|
|
value(Operator::Mul, char('×')),
|
|
|
|
|
value(Operator::Mul, char('∙')),
|
|
|
|
|
value(Operator::Div, char('/')),
|
|
|
|
|
value(Operator::Div, char('÷')),
|
2021-05-22 18:18:02 +00:00
|
|
|
|
)),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Contain, char('∋')),
|
|
|
|
|
value(Operator::NotContain, char('∌')),
|
|
|
|
|
value(Operator::Inside, char('∈')),
|
|
|
|
|
value(Operator::NotInside, char('∉')),
|
|
|
|
|
value(Operator::ContainAll, char('⊇')),
|
|
|
|
|
value(Operator::ContainAny, char('⊃')),
|
|
|
|
|
value(Operator::ContainNone, char('⊅')),
|
|
|
|
|
value(Operator::AllInside, char('⊆')),
|
|
|
|
|
value(Operator::AnyInside, char('⊂')),
|
|
|
|
|
value(Operator::NoneInside, char('⊄')),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
2022-01-13 17:36:41 +00:00
|
|
|
|
))(i)?;
|
|
|
|
|
let (i, _) = mightbespace(i)?;
|
|
|
|
|
Ok((i, v))
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 23:31:23 +00:00
|
|
|
|
pub fn binary_phrases(i: &str) -> IResult<&str, Operator> {
|
2022-01-13 17:36:41 +00:00
|
|
|
|
let (i, _) = shouldbespace(i)?;
|
|
|
|
|
let (i, v) = alt((
|
2020-06-29 15:36:01 +00:00
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::Or, tag_no_case("OR")),
|
|
|
|
|
value(Operator::And, tag_no_case("AND")),
|
|
|
|
|
value(Operator::NotEqual, tag_no_case("IS NOT")),
|
|
|
|
|
value(Operator::Equal, tag_no_case("IS")),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
|
|
|
|
alt((
|
2023-08-29 10:50:00 +00:00
|
|
|
|
value(Operator::ContainAll, tag_no_case("CONTAINSALL")),
|
|
|
|
|
value(Operator::ContainAny, tag_no_case("CONTAINSANY")),
|
|
|
|
|
value(Operator::ContainNone, tag_no_case("CONTAINSNONE")),
|
|
|
|
|
value(Operator::NotContain, tag_no_case("CONTAINSNOT")),
|
|
|
|
|
value(Operator::Contain, tag_no_case("CONTAINS")),
|
|
|
|
|
value(Operator::AllInside, tag_no_case("ALLINSIDE")),
|
|
|
|
|
value(Operator::AnyInside, tag_no_case("ANYINSIDE")),
|
|
|
|
|
value(Operator::NoneInside, tag_no_case("NONEINSIDE")),
|
|
|
|
|
value(Operator::NotInside, tag_no_case("NOTINSIDE")),
|
|
|
|
|
value(Operator::Inside, tag_no_case("INSIDE")),
|
|
|
|
|
value(Operator::Outside, tag_no_case("OUTSIDE")),
|
|
|
|
|
value(Operator::Intersects, tag_no_case("INTERSECTS")),
|
|
|
|
|
value(Operator::NotInside, tag_no_case("NOT IN")),
|
|
|
|
|
value(Operator::Inside, tag_no_case("IN")),
|
2020-06-29 15:36:01 +00:00
|
|
|
|
)),
|
2022-01-13 17:36:41 +00:00
|
|
|
|
))(i)?;
|
|
|
|
|
let (i, _) = shouldbespace(i)?;
|
|
|
|
|
Ok((i, v))
|
2020-06-29 15:36:01 +00:00
|
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
|
|
|
|
|
|
pub fn matches(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
let (i, _) = char('@')(i)?;
|
2023-08-29 10:50:00 +00:00
|
|
|
|
cut(|i| {
|
|
|
|
|
let (i, reference) = opt(uint8)(i)?;
|
|
|
|
|
let (i, _) = char('@')(i)?;
|
|
|
|
|
Ok((i, Operator::Matches(reference)))
|
|
|
|
|
})(i)
|
2023-05-29 11:46:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-12 20:26:03 +00:00
|
|
|
|
pub fn knn(i: &str) -> IResult<&str, Operator> {
|
|
|
|
|
let (i, _) = char('<')(i)?;
|
|
|
|
|
let (i, k) = uint32(i)?;
|
|
|
|
|
let (i, _) = char('>')(i)?;
|
|
|
|
|
Ok((i, Operator::Knn(k)))
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-29 11:46:41 +00:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn matches_without_reference() {
|
|
|
|
|
let res = matches("@@");
|
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
|
assert_eq!("@@", format!("{}", out));
|
|
|
|
|
assert_eq!(out, Operator::Matches(None));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn matches_with_reference() {
|
|
|
|
|
let res = matches("@12@");
|
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
|
assert_eq!("@12@", format!("{}", out));
|
|
|
|
|
assert_eq!(out, Operator::Matches(Some(12u8)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn matches_with_invalid_reference() {
|
|
|
|
|
let res = matches("@256@");
|
2023-08-29 10:50:00 +00:00
|
|
|
|
res.unwrap_err();
|
2023-05-29 11:46:41 +00:00
|
|
|
|
}
|
2023-09-12 20:26:03 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_knn() {
|
|
|
|
|
let res = knn("<5>");
|
|
|
|
|
assert!(res.is_ok());
|
|
|
|
|
let out = res.unwrap().1;
|
|
|
|
|
assert_eq!("<5>", format!("{}", out));
|
|
|
|
|
assert_eq!(out, Operator::Knn(5));
|
|
|
|
|
}
|
2023-05-29 11:46:41 +00:00
|
|
|
|
}
|