use std::fmt;
use rust_decimal::Decimal;
use crate::quantity::Unit;
use crate::temporal::{Date, DateTime, Time};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Literal {
Boolean(bool),
String(String),
Integer(i64),
Decimal(Decimal),
Date(Date),
DateTime(DateTime),
Time(Time),
Quantity(Decimal, Unit),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeSpecifier {
pub namespace: Option<String>,
pub name: String,
}
impl fmt::Display for TypeSpecifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.namespace {
Some(namespace) => write!(f, "{namespace}.{}", self.name),
None => f.write_str(&self.name),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Multiply,
Divide,
Div,
Mod,
Add,
Subtract,
Concatenate,
Union,
Less,
LessOrEqual,
Greater,
GreaterOrEqual,
Equal,
Equivalent,
NotEqual,
NotEquivalent,
In,
Contains,
And,
Or,
Xor,
Implies,
}
impl fmt::Display for BinaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Multiply => "*",
Self::Divide => "/",
Self::Div => "div",
Self::Mod => "mod",
Self::Add => "+",
Self::Subtract => "-",
Self::Concatenate => "&",
Self::Union => "|",
Self::Less => "<",
Self::LessOrEqual => "<=",
Self::Greater => ">",
Self::GreaterOrEqual => ">=",
Self::Equal => "=",
Self::Equivalent => "~",
Self::NotEqual => "!=",
Self::NotEquivalent => "!~",
Self::In => "in",
Self::Contains => "contains",
Self::And => "and",
Self::Or => "or",
Self::Xor => "xor",
Self::Implies => "implies",
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr {
Literal(Literal),
Empty,
External(String),
This,
Index,
Total,
Member {
input: Option<Box<Expr>>,
name: String,
},
Call {
input: Option<Box<Expr>>,
name: String,
args: Vec<Expr>,
},
Invocation {
input: Box<Expr>,
variable: Box<Expr>,
},
SortKey {
key: Box<Expr>,
descending: bool,
},
Indexer {
input: Box<Expr>,
index: Box<Expr>,
},
Negate(Box<Expr>),
Plus(Box<Expr>),
Binary {
op: BinaryOp,
left: Box<Expr>,
right: Box<Expr>,
},
Is {
operand: Box<Expr>,
type_specifier: TypeSpecifier,
},
As {
operand: Box<Expr>,
type_specifier: TypeSpecifier,
},
}
impl Expr {
#[must_use]
pub fn as_type_specifier(&self) -> Option<TypeSpecifier> {
match self {
Self::Member { input: None, name } => Some(TypeSpecifier {
namespace: None,
name: name.clone(),
}),
Self::Member {
input: Some(input),
name,
} => match input.as_ref() {
Self::Member {
input: None,
name: namespace,
} => Some(TypeSpecifier {
namespace: Some(namespace.clone()),
name: name.clone(),
}),
_ => None,
},
_ => None,
}
}
}