use crate::{Meta, OrderItem, Param};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BoolOp {
Eq,
Ne,
Gt,
Gte,
Lt,
Lte,
IsDistinctFrom,
IsNotDistinctFrom,
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BooleanTest {
True,
False,
Unknown,
}
impl BooleanTest {
#[inline]
pub const fn as_sql(self) -> &'static str {
match self {
Self::True => "TRUE",
Self::False => "FALSE",
Self::Unknown => "UNKNOWN",
}
}
}
impl BoolOp {
#[inline]
pub const fn as_sql(self) -> &'static str {
match self {
Self::Eq => "=",
Self::Ne => "<>",
Self::Gt => ">",
Self::Gte => ">=",
Self::Lt => "<",
Self::Lte => "<=",
Self::IsDistinctFrom => "IS DISTINCT FROM",
Self::IsNotDistinctFrom => "IS NOT DISTINCT FROM",
}
}
#[inline]
pub const fn as_name(self) -> &'static str {
match self {
Self::Eq => "eq",
Self::Ne => "ne",
Self::Gt => "gt",
Self::Gte => "gte",
Self::Lt => "lt",
Self::Lte => "lte",
Self::IsDistinctFrom => "is_distinct_from",
Self::IsNotDistinctFrom => "is_not_distinct_from",
}
}
#[inline]
pub const fn requires_ordering(self) -> bool {
matches!(self, Self::Gt | Self::Gte | Self::Lt | Self::Lte)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ValueOp {
Add,
Sub,
Mul,
Div,
Custom(&'static str),
}
impl ValueOp {
#[inline]
pub const fn as_sql(self) -> &'static str {
match self {
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Custom(op) => op,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WindowFunction {
RowNumber,
Rank,
DenseRank,
Lag,
Lead,
FirstValue,
LastValue,
NthValue,
Ntile,
PercentRank,
CumeDist,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum WindowFrameKind {
Rows,
Range,
Groups,
}
#[derive(Clone, Debug)]
#[must_use]
pub enum FrameBound {
#[non_exhaustive]
UnboundedPreceding,
#[non_exhaustive]
Preceding(Box<ValueExpr>),
#[non_exhaustive]
CurrentRow,
#[non_exhaustive]
Following(Box<ValueExpr>),
#[non_exhaustive]
UnboundedFollowing,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FrameExclude {
CurrentRow,
Group,
Ties,
NoOthers,
}
#[derive(Clone, Debug)]
#[must_use]
#[non_exhaustive]
pub struct WindowFrame {
pub(crate) kind: WindowFrameKind,
pub(crate) start: FrameBound,
pub(crate) end: Option<FrameBound>,
pub(crate) exclude: Option<FrameExclude>,
}
#[derive(Clone, Debug, Default)]
#[must_use]
#[non_exhaustive]
pub struct WindowSpec {
pub(crate) partition_by: Vec<ValueExpr>,
pub(crate) order_by: Vec<OrderItem>,
pub(crate) frame: Option<Box<WindowFrame>>,
}
#[derive(Clone, Debug)]
#[must_use]
pub struct WindowFunctionBuilder {
pub(super) function: WindowFunction,
pub(super) args: Vec<ValueExpr>,
}
#[derive(Clone, Debug)]
#[must_use]
pub struct OffsetWindowFunctionBuilder {
pub(super) function: WindowFunction,
pub(super) value: ValueExpr,
pub(super) offset: Option<ValueExpr>,
pub(super) default: Option<ValueExpr>,
}
#[derive(Clone, Debug, Default)]
#[must_use]
pub struct CaseBuilder {
pub(super) branches: Vec<(BoolExpr, ValueExpr)>,
}
#[derive(Clone, Debug)]
#[must_use]
#[non_exhaustive]
pub enum BoolExpr {
#[non_exhaustive]
Constant(bool),
#[non_exhaustive]
Compare {
left: ValueExpr,
op: BoolOp,
right: ValueExpr,
},
#[non_exhaustive]
IsNull {
expr: ValueExpr,
negated: bool,
},
#[non_exhaustive]
IsBoolean {
expr: ValueExpr,
test: BooleanTest,
negated: bool,
},
#[non_exhaustive]
InList {
expr: ValueExpr,
values: Vec<ValueExpr>,
negated: bool,
},
#[non_exhaustive]
InSubquery {
expr: ValueExpr,
query: Box<crate::Stmt>,
negated: bool,
},
#[non_exhaustive]
Between {
expr: ValueExpr,
low: ValueExpr,
high: ValueExpr,
negated: bool,
},
#[non_exhaustive]
Like {
expr: ValueExpr,
pattern: ValueExpr,
case_insensitive: bool,
negated: bool,
escape: bool,
},
#[non_exhaustive]
SimilarTo {
expr: ValueExpr,
pattern: ValueExpr,
negated: bool,
},
#[non_exhaustive]
Regex {
expr: ValueExpr,
pattern: ValueExpr,
case_insensitive: bool,
negated: bool,
},
#[non_exhaustive]
Infix {
left: ValueExpr,
op: &'static str,
right: ValueExpr,
negated: bool,
checked: bool,
},
#[non_exhaustive]
Any {
value: ValueExpr,
array: ValueExpr,
negated: bool,
},
#[non_exhaustive]
ArrayIsEmpty {
expr: ValueExpr,
negated: bool,
},
#[non_exhaustive]
And(Vec<BoolExpr>),
#[non_exhaustive]
Or(Vec<BoolExpr>),
#[non_exhaustive]
Not(Box<BoolExpr>),
#[non_exhaustive]
Exists(Box<crate::Stmt>),
#[non_exhaustive]
Raw {
sql: String,
params: Vec<Param>,
},
}
#[derive(Clone, Debug)]
#[must_use]
#[non_exhaustive]
pub enum ValueExpr {
#[non_exhaustive]
Field {
meta: Meta,
qualifier: Option<String>,
},
#[non_exhaustive]
Excluded(Meta),
#[non_exhaustive]
Param(Param),
#[non_exhaustive]
Null,
#[non_exhaustive]
SqlLiteral(&'static str),
#[non_exhaustive]
Keyword(&'static str),
#[non_exhaustive]
Function {
name: &'static str,
args: Vec<ValueExpr>,
},
#[non_exhaustive]
Aggregate {
name: &'static str,
args: Vec<ValueExpr>,
distinct: bool,
order_by: Vec<OrderItem>,
filter: Option<Box<BoolExpr>>,
over: Option<Box<WindowSpec>>,
},
#[non_exhaustive]
OrderedSetAggregate {
name: &'static str,
args: Vec<ValueExpr>,
within_group: Vec<OrderItem>,
filter: Option<Box<BoolExpr>>,
},
#[non_exhaustive]
Case {
branches: Vec<(BoolExpr, ValueExpr)>,
else_: Option<Box<ValueExpr>>,
},
#[non_exhaustive]
Cast {
expr: Box<ValueExpr>,
pg: &'static str,
},
#[non_exhaustive]
Binary {
left: Box<ValueExpr>,
op: ValueOp,
right: Box<ValueExpr>,
},
#[non_exhaustive]
Subscript {
expr: Box<ValueExpr>,
index: Box<ValueExpr>,
},
#[non_exhaustive]
Slice {
expr: Box<ValueExpr>,
start: Option<Box<ValueExpr>>,
end: Option<Box<ValueExpr>>,
},
#[non_exhaustive]
Array(Vec<ValueExpr>),
#[non_exhaustive]
Row(Vec<ValueExpr>),
#[non_exhaustive]
Extract {
field: &'static str,
expr: Box<ValueExpr>,
},
#[non_exhaustive]
Window {
function: WindowFunction,
args: Vec<ValueExpr>,
spec: WindowSpec,
},
#[non_exhaustive]
Raw {
sql: String,
params: Vec<Param>,
},
#[non_exhaustive]
Subquery(Box<crate::Stmt>),
#[non_exhaustive]
InvalidAggregateModifier {
expr: Box<ValueExpr>,
modifier: &'static str,
},
}
impl BoolExpr {
#[inline]
pub(crate) fn compare(left: ValueExpr, op: BoolOp, right: ValueExpr) -> Self {
Self::Compare { left, op, right }
}
#[inline]
pub(crate) fn is_null_expr(expr: ValueExpr, negated: bool) -> Self {
Self::IsNull { expr, negated }
}
#[inline]
pub(crate) fn is_boolean(expr: ValueExpr, test: BooleanTest, negated: bool) -> Self {
Self::IsBoolean {
expr,
test,
negated,
}
}
#[inline]
pub(crate) fn in_list(expr: ValueExpr, values: Vec<ValueExpr>, negated: bool) -> Self {
Self::InList {
expr,
values,
negated,
}
}
#[inline]
pub(crate) fn in_subquery(expr: ValueExpr, query: Box<crate::Stmt>, negated: bool) -> Self {
Self::InSubquery {
expr,
query,
negated,
}
}
#[inline]
pub(crate) fn between(expr: ValueExpr, low: ValueExpr, high: ValueExpr, negated: bool) -> Self {
Self::Between {
expr,
low,
high,
negated,
}
}
#[inline]
pub(crate) fn like(
expr: ValueExpr,
pattern: ValueExpr,
case_insensitive: bool,
negated: bool,
escape: bool,
) -> Self {
Self::Like {
expr,
pattern,
case_insensitive,
negated,
escape,
}
}
#[inline]
pub(crate) fn similar_to(expr: ValueExpr, pattern: ValueExpr, negated: bool) -> Self {
Self::SimilarTo {
expr,
pattern,
negated,
}
}
#[inline]
pub(crate) fn regex(
expr: ValueExpr,
pattern: ValueExpr,
case_insensitive: bool,
negated: bool,
) -> Self {
Self::Regex {
expr,
pattern,
case_insensitive,
negated,
}
}
#[inline]
pub(crate) fn infix(
left: ValueExpr,
op: &'static str,
right: ValueExpr,
negated: bool,
) -> Self {
Self::Infix {
left,
op,
right,
negated,
checked: true,
}
}
#[inline]
pub(crate) fn any(value: ValueExpr, array: ValueExpr, negated: bool) -> Self {
Self::Any {
value,
array,
negated,
}
}
#[inline]
pub(crate) fn array_is_empty(expr: ValueExpr, negated: bool) -> Self {
Self::ArrayIsEmpty { expr, negated }
}
#[inline]
pub(crate) fn raw(sql: impl Into<String>, params: impl Into<Vec<Param>>) -> Self {
Self::Raw {
sql: sql.into(),
params: params.into(),
}
}
}
impl ValueExpr {
#[inline]
pub(crate) fn field(meta: Meta, qualifier: Option<String>) -> Self {
Self::Field { meta, qualifier }
}
#[inline]
pub(crate) fn function(name: &'static str, args: Vec<ValueExpr>) -> Self {
Self::Function { name, args }
}
#[inline]
pub(crate) fn aggregate(
name: &'static str,
args: Vec<ValueExpr>,
distinct: bool,
order_by: Vec<OrderItem>,
filter: Option<Box<BoolExpr>>,
over: Option<Box<WindowSpec>>,
) -> Self {
Self::Aggregate {
name,
args,
distinct,
order_by,
filter,
over,
}
}
#[inline]
pub(crate) fn ordered_set_aggregate(
name: &'static str,
args: Vec<ValueExpr>,
within_group: Vec<OrderItem>,
filter: Option<Box<BoolExpr>>,
) -> Self {
Self::OrderedSetAggregate {
name,
args,
within_group,
filter,
}
}
#[inline]
pub(crate) fn case(
branches: Vec<(BoolExpr, ValueExpr)>,
else_: Option<Box<ValueExpr>>,
) -> Self {
Self::Case { branches, else_ }
}
#[inline]
pub(crate) fn cast_expr(expr: ValueExpr, pg: &'static str) -> Self {
Self::Cast {
expr: Box::new(expr),
pg,
}
}
#[inline]
pub(crate) fn binary(left: ValueExpr, op: ValueOp, right: ValueExpr) -> Self {
Self::Binary {
left: Box::new(left),
op,
right: Box::new(right),
}
}
#[inline]
pub(crate) fn subscript(expr: ValueExpr, index: ValueExpr) -> Self {
Self::Subscript {
expr: Box::new(expr),
index: Box::new(index),
}
}
#[inline]
pub(crate) fn slice(expr: ValueExpr, start: Option<ValueExpr>, end: Option<ValueExpr>) -> Self {
Self::Slice {
expr: Box::new(expr),
start: start.map(Box::new),
end: end.map(Box::new),
}
}
#[inline]
pub(crate) fn extract(field: &'static str, expr: ValueExpr) -> Self {
Self::Extract {
field,
expr: Box::new(expr),
}
}
#[inline]
pub(crate) fn window(function: WindowFunction, args: Vec<ValueExpr>, spec: WindowSpec) -> Self {
Self::Window {
function,
args,
spec,
}
}
#[inline]
pub(crate) fn raw(sql: impl Into<String>, params: impl Into<Vec<Param>>) -> Self {
Self::Raw {
sql: sql.into(),
params: params.into(),
}
}
#[inline]
pub(crate) fn invalid_aggregate_modifier(expr: ValueExpr, modifier: &'static str) -> Self {
Self::InvalidAggregateModifier {
expr: Box::new(expr),
modifier,
}
}
}