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}
118
119#[derive(Default, Debug)]
120pub struct IsAggregateFunction;
121impl ExpressionVisitor for IsAggregateFunction {
122 fn visit_operand(
123 &mut self,
124 _writer: &dyn SqlWriter,
125 _context: &mut Context,
126 _out: &mut DynQuery,
127 value: &Operand,
128 ) -> bool {
129 match value {
130 Operand::Call(function, ..) => match function {
131 s if s.eq_ignore_ascii_case("abs") => true,
132 s if s.eq_ignore_ascii_case("avg") => true,
133 s if s.eq_ignore_ascii_case("count") => true,
134 s if s.eq_ignore_ascii_case("max") => true,
135 s if s.eq_ignore_ascii_case("min") => true,
136 s if s.eq_ignore_ascii_case("sum") => true,
137 _ => false,
138 },
139 _ => false,
140 }
141 }
142 fn visit_binary_op(
143 &mut self,
144 writer: &dyn SqlWriter,
145 context: &mut Context,
146 out: &mut DynQuery,
147 value: &BinaryOp<&dyn Expression, &dyn Expression>,
148 ) -> bool {
149 if value.op == BinaryOpType::Alias {
150 value.lhs.accept_visitor(self, writer, context, out)
151 } else {
152 false
153 }
154 }
155}
156
157#[derive(Default, Debug)]
158pub struct IsAsterisk;
159impl ExpressionVisitor for IsAsterisk {
160 fn visit_operand(
161 &mut self,
162 _writer: &dyn SqlWriter,
163 _context: &mut Context,
164 _out: &mut DynQuery,
165 value: &Operand,
166 ) -> bool {
167 matches!(value, Operand::Asterisk)
168 }
169}
170
171#[derive(Default, Debug)]
172pub struct IsQuestionMark;
173impl ExpressionVisitor for IsQuestionMark {
174 fn visit_operand(
175 &mut self,
176 _writer: &dyn SqlWriter,
177 _context: &mut Context,
178 _out: &mut DynQuery,
179 value: &Operand,
180 ) -> bool {
181 matches!(value, Operand::QuestionMark)
182 }
183}
184
185#[derive(Default, Debug)]
186pub struct IsAlias {
187 pub name: String,
188}
189impl ExpressionVisitor for IsAlias {
190 fn visit_binary_op(
191 &mut self,
192 _writer: &dyn SqlWriter,
193 context: &mut Context,
194 _out: &mut DynQuery,
195 value: &BinaryOp<&dyn Expression, &dyn Expression>,
196 ) -> bool {
197 if value.op != BinaryOpType::Alias {
198 return false;
199 }
200 self.name = value.rhs.as_identifier(context);
201 true
202 }
203}
204
205#[derive(Default, Debug, Copy, Clone)]
206pub struct FindOrder {
207 pub order: Order,
208}
209impl ExpressionVisitor for FindOrder {
210 fn visit_column(
211 &mut self,
212 _writer: &dyn SqlWriter,
213 _context: &mut Context,
214 _out: &mut DynQuery,
215 _value: &ColumnRef,
216 ) -> bool {
217 true
218 }
219 fn visit_operand(
220 &mut self,
221 _writer: &dyn SqlWriter,
222 _context: &mut Context,
223 _out: &mut DynQuery,
224 _value: &Operand,
225 ) -> bool {
226 true
227 }
228 fn visit_unary_op(
229 &mut self,
230 _writer: &dyn SqlWriter,
231 _context: &mut Context,
232 _out: &mut DynQuery,
233 _value: &UnaryOp<&dyn Expression>,
234 ) -> bool {
235 true
236 }
237 fn visit_binary_op(
238 &mut self,
239 _writer: &dyn SqlWriter,
240 _context: &mut Context,
241 _out: &mut DynQuery,
242 _value: &BinaryOp<&dyn Expression, &dyn Expression>,
243 ) -> bool {
244 true
245 }
246 fn visit_ordered(
247 &mut self,
248 _writer: &dyn SqlWriter,
249 _context: &mut Context,
250 _out: &mut DynQuery,
251 value: &Ordered<&dyn Expression>,
252 ) -> bool {
253 self.order = value.order;
254 true
255 }
256}