use crate::{ColumnName, ParamName, PgType, TableName};
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Param(ParamName),
Column(ColumnRef),
String(String),
Int(i64),
Bool(bool),
Null,
Now,
Default,
BinOp {
left: Box<Expr>,
op: BinOp,
right: Box<Expr>,
},
IsNull { expr: Box<Expr>, negated: bool },
Like { expr: Box<Expr>, pattern: Box<Expr> },
ILike { expr: Box<Expr>, pattern: Box<Expr> },
Any { expr: Box<Expr>, array: Box<Expr> },
JsonGet { expr: Box<Expr>, key: Box<Expr> },
JsonGetText { expr: Box<Expr>, key: Box<Expr> },
Contains { expr: Box<Expr>, value: Box<Expr> },
KeyExists { expr: Box<Expr>, key: Box<Expr> },
Cast { expr: Box<Expr>, pg_type: PgType },
Excluded(ColumnName),
FnCall { name: String, args: Vec<Expr> },
Count { table: TableName },
Raw(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ColumnRef {
pub table: Option<TableName>,
pub column: ColumnName,
}
impl ColumnRef {
pub fn new(column: ColumnName) -> Self {
Self {
table: None,
column,
}
}
pub fn qualified(table: TableName, column: ColumnName) -> Self {
Self {
table: Some(table),
column,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
And,
Or,
}
impl BinOp {
pub fn as_str(self) -> &'static str {
match self {
BinOp::Eq => "=",
BinOp::Ne => "<>",
BinOp::Lt => "<",
BinOp::Le => "<=",
BinOp::Gt => ">",
BinOp::Ge => ">=",
BinOp::And => "AND",
BinOp::Or => "OR",
}
}
}
impl Expr {
pub fn param(name: ParamName) -> Self {
Expr::Param(name)
}
pub fn column(name: ColumnName) -> Self {
Expr::Column(ColumnRef::new(name))
}
pub fn qualified_column(table: TableName, column: ColumnName) -> Self {
Expr::Column(ColumnRef::qualified(table, column))
}
pub fn string(s: impl Into<String>) -> Self {
Expr::String(s.into())
}
pub fn int(n: i64) -> Self {
Expr::Int(n)
}
pub fn bool(b: bool) -> Self {
Expr::Bool(b)
}
pub fn eq(self, other: Expr) -> Self {
Expr::BinOp {
left: Box::new(self),
op: BinOp::Eq,
right: Box::new(other),
}
}
pub fn and(self, other: Expr) -> Self {
Expr::BinOp {
left: Box::new(self),
op: BinOp::And,
right: Box::new(other),
}
}
pub fn or(self, other: Expr) -> Self {
Expr::BinOp {
left: Box::new(self),
op: BinOp::Or,
right: Box::new(other),
}
}
pub fn is_null(self) -> Self {
Expr::IsNull {
expr: Box::new(self),
negated: false,
}
}
pub fn is_not_null(self) -> Self {
Expr::IsNull {
expr: Box::new(self),
negated: true,
}
}
pub fn like(self, pattern: Expr) -> Self {
Expr::Like {
expr: Box::new(self),
pattern: Box::new(pattern),
}
}
pub fn ilike(self, pattern: Expr) -> Self {
Expr::ILike {
expr: Box::new(self),
pattern: Box::new(pattern),
}
}
pub fn any(self, array: Expr) -> Self {
Expr::Any {
expr: Box::new(self),
array: Box::new(array),
}
}
pub fn json_get(self, key: Expr) -> Self {
Expr::JsonGet {
expr: Box::new(self),
key: Box::new(key),
}
}
pub fn json_get_text(self, key: Expr) -> Self {
Expr::JsonGetText {
expr: Box::new(self),
key: Box::new(key),
}
}
pub fn contains(self, value: Expr) -> Self {
Expr::Contains {
expr: Box::new(self),
value: Box::new(value),
}
}
pub fn key_exists(self, key: Expr) -> Self {
Expr::KeyExists {
expr: Box::new(self),
key: Box::new(key),
}
}
pub fn cast(self, pg_type: PgType) -> Self {
Expr::Cast {
expr: Box::new(self),
pg_type,
}
}
pub fn excluded(column: ColumnName) -> Self {
Expr::Excluded(column)
}
}