1mod call_arguments;
10mod context;
11mod evaluator;
12mod subquery;
13mod traversal;
14
15use uqa_core::Value;
16use uqa_sql::ast::{BinaryOp, FrameMode, FunctionBinding, InternalColumnRef, NullsOrder};
17
18pub type SubqueryId = usize;
20
21#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
22pub enum ScalarExpr {
23 Star,
24 QualifiedStar(String),
25 Default,
26 Column(String),
27 Position(usize),
29 InternalColumn(InternalColumnRef),
31 QualifiedColumn {
32 qualifier: String,
33 column: String,
34 },
35 Literal(Value),
36 Param(usize),
37 Func {
38 name: String,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 binding: Option<FunctionBinding>,
41 args: Vec<Self>,
42 distinct: bool,
43 order_by: Vec<ScalarOrder>,
44 filter: Option<Box<Self>>,
45 },
46 Array(Vec<Self>),
47 Row(Vec<Self>),
48 Binary {
49 op: BinaryOp,
50 lhs: Box<Self>,
51 rhs: Box<Self>,
52 },
53 UnaryMinus(Box<Self>),
54 Not(Box<Self>),
55 And(Vec<Self>),
56 Or(Vec<Self>),
57 IsNull {
58 expr: Box<Self>,
59 negated: bool,
60 },
61 Between {
62 expr: Box<Self>,
63 low: Box<Self>,
64 high: Box<Self>,
65 },
66 InList {
67 expr: Box<Self>,
68 list: Vec<Self>,
69 negated: bool,
70 },
71 WindowCall {
72 name: String,
73 args: Vec<Self>,
74 spec: ScalarWindowSpec,
75 },
76 Case {
77 base: Option<Box<Self>>,
78 when: Vec<(Self, Self)>,
79 else_branch: Option<Box<Self>>,
80 },
81 Cast {
82 expr: Box<Self>,
83 ty: String,
84 },
85 ScalarSubquery(SubqueryId),
86 Exists {
87 subquery: SubqueryId,
88 negated: bool,
89 },
90 InSubquery {
91 expr: Box<Self>,
92 subquery: SubqueryId,
93 negated: bool,
94 },
95}
96
97#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
98pub struct ScalarOrder {
99 pub expr: ScalarExpr,
100 pub descending: bool,
101 pub nulls: Option<NullsOrder>,
102}
103
104#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
105pub struct ScalarWindowSpec {
106 pub partition_by: Vec<ScalarExpr>,
107 pub order_by: Vec<ScalarOrder>,
108 pub frame: Option<ScalarWindowFrame>,
109}
110
111#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
112pub struct ScalarWindowFrame {
113 pub mode: FrameMode,
114 pub start: ScalarFrameBound,
115 pub end: ScalarFrameBound,
116}
117
118#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
119pub enum ScalarFrameBound {
120 UnboundedPreceding,
121 UnboundedFollowing,
122 CurrentRow,
123 Preceding(Box<ScalarExpr>),
124 Following(Box<ScalarExpr>),
125}
126
127impl ScalarExpr {
128 #[must_use]
129 pub fn qualified_column(qualifier: impl Into<String>, column: impl Into<String>) -> Self {
130 Self::QualifiedColumn {
131 qualifier: qualifier.into(),
132 column: column.into(),
133 }
134 }
135}
136
137pub use call_arguments::{
138 eval_call_arguments, scalar_call_argument, scalar_call_arguments,
139 validate_scalar_call_arguments, ScalarCallArgument,
140};
141pub use context::ScalarEvalContext;
142pub use evaluator::eval_scalar;
143pub(crate) use evaluator::scalar_integer_binary_width;
144pub use subquery::{ScalarSubqueryRunner, SubqueryResult};
145
146#[cfg(test)]
147mod tests;