#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum UnOper {
Not,
}
impl UnOper {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Not => "NOT",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BinOper {
And,
Or,
Equal,
NotEqual,
SmallerThan,
SmallerThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
Like,
NotLike,
ILike,
NotILike,
SimilarTo,
NotSimilarTo,
Matches,
NotMatches,
In,
NotIn,
Between,
NotBetween,
Is,
IsNot,
Add,
Sub,
Mul,
Div,
Mod,
BitAnd,
BitOr,
LShift,
RShift,
PgOperator(PgBinOper),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PgBinOper {
Contains,
Contained,
Overlap,
Concatenate,
JsonContainsKey,
JsonContainsAnyKey,
JsonContainsAllKeys,
JsonGetByIndex,
JsonGetAsText,
JsonGetPath,
JsonGetPathAsText,
}
impl BinOper {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::And => "AND",
Self::Or => "OR",
Self::Equal => "=",
Self::NotEqual => "<>",
Self::SmallerThan => "<",
Self::SmallerThanOrEqual => "<=",
Self::GreaterThan => ">",
Self::GreaterThanOrEqual => ">=",
Self::Like => "LIKE",
Self::NotLike => "NOT LIKE",
Self::ILike => "ILIKE",
Self::NotILike => "NOT ILIKE",
Self::SimilarTo => "SIMILAR TO",
Self::NotSimilarTo => "NOT SIMILAR TO",
Self::Matches => "~",
Self::NotMatches => "!~",
Self::In => "IN",
Self::NotIn => "NOT IN",
Self::Between => "BETWEEN",
Self::NotBetween => "NOT BETWEEN",
Self::Is => "IS",
Self::IsNot => "IS NOT",
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Mod => "%",
Self::BitAnd => "&",
Self::BitOr => "|",
Self::LShift => "<<",
Self::RShift => ">>",
Self::PgOperator(pg_op) => pg_op.as_str(),
}
}
#[must_use]
pub fn precedence(&self) -> u8 {
match self {
Self::Or => 1,
Self::And => 2,
Self::Is | Self::IsNot => 3,
Self::Between | Self::NotBetween | Self::In | Self::NotIn => 4,
Self::Like
| Self::NotLike
| Self::ILike
| Self::NotILike
| Self::SimilarTo
| Self::NotSimilarTo
| Self::Matches
| Self::NotMatches => 5,
Self::Equal
| Self::NotEqual
| Self::SmallerThan
| Self::SmallerThanOrEqual
| Self::GreaterThan
| Self::GreaterThanOrEqual => 6,
Self::BitOr => 7,
Self::BitAnd => 8,
Self::LShift | Self::RShift => 9,
Self::Add | Self::Sub => 10,
Self::Mul | Self::Div | Self::Mod => 11,
Self::PgOperator(_) => 6, }
}
#[must_use]
pub fn is_left_associative(&self) -> bool {
true
}
}
impl PgBinOper {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Contains => "@>",
Self::Contained => "<@",
Self::Overlap => "&&",
Self::Concatenate => "||",
Self::JsonContainsKey => "?",
Self::JsonContainsAnyKey => "?|",
Self::JsonContainsAllKeys => "?&",
Self::JsonGetByIndex => "->",
Self::JsonGetAsText => "->>",
Self::JsonGetPath => "#>",
Self::JsonGetPathAsText => "#>>",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LogicalChainOper {
And,
Or,
}
impl LogicalChainOper {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::And => "AND",
Self::Or => "OR",
}
}
}
impl From<LogicalChainOper> for BinOper {
fn from(op: LogicalChainOper) -> Self {
match op {
LogicalChainOper::And => BinOper::And,
LogicalChainOper::Or => BinOper::Or,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SubQueryOper {
Exists,
Any,
Some,
All,
}
impl SubQueryOper {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Exists => "EXISTS",
Self::Any => "ANY",
Self::Some => "SOME",
Self::All => "ALL",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
fn test_un_oper_as_str() {
assert_eq!(UnOper::Not.as_str(), "NOT");
}
#[rstest]
#[case(BinOper::And, "AND")]
#[case(BinOper::Or, "OR")]
#[case(BinOper::Equal, "=")]
#[case(BinOper::NotEqual, "<>")]
#[case(BinOper::SmallerThan, "<")]
#[case(BinOper::GreaterThan, ">")]
#[case(BinOper::Like, "LIKE")]
#[case(BinOper::In, "IN")]
#[case(BinOper::Between, "BETWEEN")]
fn test_bin_oper_as_str(#[case] op: BinOper, #[case] expected: &str) {
assert_eq!(op.as_str(), expected);
}
#[rstest]
fn test_bin_oper_precedence() {
assert!(BinOper::Mul.precedence() > BinOper::Add.precedence());
assert!(BinOper::And.precedence() > BinOper::Or.precedence());
assert!(BinOper::Equal.precedence() > BinOper::And.precedence());
}
#[rstest]
fn test_logical_chain_oper() {
assert_eq!(LogicalChainOper::And.as_str(), "AND");
assert_eq!(LogicalChainOper::Or.as_str(), "OR");
}
#[rstest]
fn test_subquery_oper() {
assert_eq!(SubQueryOper::Exists.as_str(), "EXISTS");
assert_eq!(SubQueryOper::Any.as_str(), "ANY");
assert_eq!(SubQueryOper::All.as_str(), "ALL");
}
#[rstest]
fn test_pg_bin_oper() {
assert_eq!(PgBinOper::Contains.as_str(), "@>");
assert_eq!(PgBinOper::Contained.as_str(), "<@");
assert_eq!(PgBinOper::JsonGetAsText.as_str(), "->>");
}
}