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}
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}