1use crate::{
2 BinaryOp, BinaryOpType, ColumnRef, Context, DynQuery, Expression, Operand, Order, Ordered,
3 SqlWriter, UnaryOp, Value,
4};
5
6pub trait ExpressionVisitor {
7 fn visit_column(
8 &mut self,
9 _writer: &dyn SqlWriter,
10 _context: &mut Context,
11 _out: &mut DynQuery,
12 _value: &ColumnRef,
13 ) -> bool {
14 false
15 }
16 fn visit_operand(
17 &mut self,
18 _writer: &dyn SqlWriter,
19 _context: &mut Context,
20 _out: &mut DynQuery,
21 _value: &Operand,
22 ) -> bool {
23 false
24 }
25 fn visit_unary_op(
26 &mut self,
27 _writer: &dyn SqlWriter,
28 _context: &mut Context,
29 _out: &mut DynQuery,
30 _value: &UnaryOp<&dyn Expression>,
31 ) -> bool {
32 false
33 }
34 fn visit_binary_op(
35 &mut self,
36 _writer: &dyn SqlWriter,
37 _context: &mut Context,
38 _out: &mut DynQuery,
39 _value: &BinaryOp<&dyn Expression, &dyn Expression>,
40 ) -> bool {
41 false
42 }
43 fn visit_ordered(
44 &mut self,
45 _writer: &dyn SqlWriter,
46 _context: &mut Context,
47 _out: &mut DynQuery,
48 _value: &Ordered<&dyn Expression>,
49 ) -> bool {
50 false
51 }
52}
53
54#[derive(Default, Debug, Copy, Clone)]
55pub struct IsTrue;
56impl ExpressionVisitor for IsTrue {
57 fn visit_operand(
58 &mut self,
59 _writer: &dyn SqlWriter,
60 _context: &mut Context,
61 _out: &mut DynQuery,
62 value: &Operand,
63 ) -> bool {
64 match value {
65 Operand::LitBool(true)
66 | Operand::Variable(Value::Boolean(Some(true), ..))
67 | Operand::Value(Value::Boolean(Some(true), ..)) => true,
68 _ => false,
69 }
70 }
71}
72
73#[derive(Default, Debug, Copy, Clone)]
74pub struct IsFalse;
75impl ExpressionVisitor for IsFalse {
76 fn visit_operand(
77 &mut self,
78 _writer: &dyn SqlWriter,
79 _context: &mut Context,
80 _out: &mut DynQuery,
81 value: &Operand,
82 ) -> bool {
83 match value {
84 Operand::LitBool(false)
85 | Operand::Variable(Value::Boolean(Some(false), ..))
86 | Operand::Value(Value::Boolean(Some(false), ..)) => true,
87 _ => false,
88 }
89 }
90}
91
92#[derive(Default, Debug)]
93pub struct IsConstant;
94impl ExpressionVisitor for IsConstant {
95 fn visit_operand(
96 &mut self,
97 writer: &dyn SqlWriter,
98 context: &mut Context,
99 out: &mut DynQuery,
100 value: &Operand,
101 ) -> bool {
102 match value {
103 Operand::Null
104 | Operand::LitBool(..)
105 | Operand::LitInt(..)
106 | Operand::LitFloat(..)
107 | Operand::LitStr(..)
108 | Operand::Type(..)
109 | Operand::Variable(..)
110 | Operand::Value(..) => true,
111 Operand::LitList(operands) | Operand::LitTuple(operands) => operands
112 .iter()
113 .all(|v| v.accept_visitor(&mut IsConstant, writer, context, out)),
114 _ => false,
115 }
116 }
117 fn visit_binary_op(
118 &mut self,
119 writer: &dyn SqlWriter,
120 context: &mut Context,
121 out: &mut DynQuery,
122 value: &BinaryOp<&dyn Expression, &dyn Expression>,
123 ) -> bool {
124 if value.op == BinaryOpType::Alias {
125 value.lhs.accept_visitor(self, writer, context, out)
126 } else {
127 false
128 }
129 }
130}
131
132#[derive(Default, Debug)]
133pub struct IsAggregateFunction;
134impl ExpressionVisitor for IsAggregateFunction {
135 fn visit_operand(
136 &mut self,
137 _writer: &dyn SqlWriter,
138 _context: &mut Context,
139 _out: &mut DynQuery,
140 value: &Operand,
141 ) -> bool {
142 match value {
143 Operand::Call(function, ..) => match function {
144 s if s.eq_ignore_ascii_case("avg") => true,
145 s if s.eq_ignore_ascii_case("count") => true,
146 s if s.eq_ignore_ascii_case("max") => true,
147 s if s.eq_ignore_ascii_case("min") => true,
148 s if s.eq_ignore_ascii_case("sum") => true,
149 _ => false,
150 },
151 _ => false,
152 }
153 }
154 fn visit_binary_op(
155 &mut self,
156 writer: &dyn SqlWriter,
157 context: &mut Context,
158 out: &mut DynQuery,
159 value: &BinaryOp<&dyn Expression, &dyn Expression>,
160 ) -> bool {
161 if value.op == BinaryOpType::Alias {
162 value.lhs.accept_visitor(self, writer, context, out)
163 } else {
164 false
165 }
166 }
167}
168
169#[derive(Default, Debug)]
170pub struct IsAsterisk;
171impl ExpressionVisitor for IsAsterisk {
172 fn visit_operand(
173 &mut self,
174 _writer: &dyn SqlWriter,
175 _context: &mut Context,
176 _out: &mut DynQuery,
177 value: &Operand,
178 ) -> bool {
179 matches!(value, Operand::Asterisk)
180 }
181}
182
183#[derive(Default, Debug)]
184pub struct IsQuestionMark;
185impl ExpressionVisitor for IsQuestionMark {
186 fn visit_operand(
187 &mut self,
188 _writer: &dyn SqlWriter,
189 _context: &mut Context,
190 _out: &mut DynQuery,
191 value: &Operand,
192 ) -> bool {
193 matches!(value, Operand::QuestionMark)
194 }
195}
196
197#[derive(Default, Debug)]
198pub struct IsAlias {
199 pub name: String,
200}
201impl ExpressionVisitor for IsAlias {
202 fn visit_binary_op(
203 &mut self,
204 _writer: &dyn SqlWriter,
205 context: &mut Context,
206 _out: &mut DynQuery,
207 value: &BinaryOp<&dyn Expression, &dyn Expression>,
208 ) -> bool {
209 if value.op != BinaryOpType::Alias {
210 return false;
211 }
212 self.name = value.rhs.as_identifier(context);
213 true
214 }
215}
216
217#[derive(Default, Debug, Copy, Clone)]
218pub struct FindOrder {
219 pub order: Order,
220}
221impl ExpressionVisitor for FindOrder {
222 fn visit_column(
223 &mut self,
224 _writer: &dyn SqlWriter,
225 _context: &mut Context,
226 _out: &mut DynQuery,
227 _value: &ColumnRef,
228 ) -> bool {
229 true
230 }
231 fn visit_operand(
232 &mut self,
233 _writer: &dyn SqlWriter,
234 _context: &mut Context,
235 _out: &mut DynQuery,
236 _value: &Operand,
237 ) -> bool {
238 true
239 }
240 fn visit_unary_op(
241 &mut self,
242 _writer: &dyn SqlWriter,
243 _context: &mut Context,
244 _out: &mut DynQuery,
245 _value: &UnaryOp<&dyn Expression>,
246 ) -> bool {
247 true
248 }
249 fn visit_binary_op(
250 &mut self,
251 _writer: &dyn SqlWriter,
252 _context: &mut Context,
253 _out: &mut DynQuery,
254 _value: &BinaryOp<&dyn Expression, &dyn Expression>,
255 ) -> bool {
256 true
257 }
258 fn visit_ordered(
259 &mut self,
260 _writer: &dyn SqlWriter,
261 _context: &mut Context,
262 _out: &mut DynQuery,
263 value: &Ordered<&dyn Expression>,
264 ) -> bool {
265 self.order = value.order;
266 true
267 }
268}