Skip to main content

tank_core/expression/
visitor.rs

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}