filter_expr/
expr.rs

1use async_trait::async_trait;
2
3use crate::Error;
4
5/// The expression.
6///
7/// It is an AST of the filter expression.
8#[derive(Debug, Clone, PartialEq)]
9pub enum Expr {
10    Field(String),
11    Str(String),
12    I64(i64),
13    F64(f64),
14    Bool(bool),
15    Null,
16    Array(Vec<Expr>),
17
18    FuncCall(String, Vec<Expr>),
19    MethodCall(String, Box<Expr>, Vec<Expr>),
20
21    Gt(Box<Expr>, Box<Expr>),
22    Lt(Box<Expr>, Box<Expr>),
23    Ge(Box<Expr>, Box<Expr>),
24    Le(Box<Expr>, Box<Expr>),
25    Eq(Box<Expr>, Box<Expr>),
26    Ne(Box<Expr>, Box<Expr>),
27    In(Box<Expr>, Box<Expr>),
28
29    And(Vec<Expr>),
30    Or(Vec<Expr>),
31    Not(Box<Expr>),
32}
33
34#[allow(unused)]
35impl Expr {
36    pub(crate) fn field_<T: Into<String>>(field: T) -> Self {
37        Self::Field(field.into())
38    }
39
40    pub(crate) fn str_<T: Into<String>>(value: T) -> Self {
41        Self::Str(value.into())
42    }
43
44    pub(crate) fn i64_<T: Into<i64>>(value: T) -> Self {
45        Self::I64(value.into())
46    }
47
48    pub(crate) fn f64_<T: Into<f64>>(value: T) -> Self {
49        Self::F64(value.into())
50    }
51
52    pub(crate) fn bool_<T: Into<bool>>(value: T) -> Self {
53        Self::Bool(value.into())
54    }
55
56    pub(crate) fn null_() -> Self {
57        Self::Null
58    }
59
60    pub(crate) fn array_<T: Into<Vec<Expr>>>(value: T) -> Self {
61        Self::Array(value.into())
62    }
63
64    pub(crate) fn func_call_(func: impl Into<String>, args: Vec<Expr>) -> Self {
65        Self::FuncCall(func.into(), args)
66    }
67
68    pub(crate) fn method_call_(obj: Expr, method: impl Into<String>, args: Vec<Expr>) -> Self {
69        Self::MethodCall(method.into(), Box::new(obj), args)
70    }
71
72    pub(crate) fn gt_(left: Expr, right: Expr) -> Self {
73        Self::Gt(Box::new(left), Box::new(right))
74    }
75
76    pub(crate) fn lt_(left: Expr, right: Expr) -> Self {
77        Self::Lt(Box::new(left), Box::new(right))
78    }
79
80    pub(crate) fn ge_(left: Expr, right: Expr) -> Self {
81        Self::Ge(Box::new(left), Box::new(right))
82    }
83
84    pub(crate) fn le_(left: Expr, right: Expr) -> Self {
85        Self::Le(Box::new(left), Box::new(right))
86    }
87
88    pub(crate) fn eq_(left: Expr, right: Expr) -> Self {
89        Self::Eq(Box::new(left), Box::new(right))
90    }
91
92    pub(crate) fn ne_(left: Expr, right: Expr) -> Self {
93        Self::Ne(Box::new(left), Box::new(right))
94    }
95
96    pub(crate) fn in_(left: Expr, right: Expr) -> Self {
97        Self::In(Box::new(left), Box::new(right))
98    }
99
100    pub(crate) fn and_<T: Into<Vec<Expr>>>(value: T) -> Self {
101        Self::And(value.into())
102    }
103
104    pub(crate) fn or_<T: Into<Vec<Expr>>>(value: T) -> Self {
105        Self::Or(value.into())
106    }
107
108    pub(crate) fn not_(self) -> Self {
109        Self::Not(Box::new(self))
110    }
111}
112
113/// A trait for transforming AST expressions.
114///
115/// This trait allows you to recursively transform expressions by visiting
116/// all sub-expressions. The `transform` method is called recursively on all
117/// sub-expressions, allowing you to transform the AST in a composable way.
118///
119/// # Example
120///
121/// ```rust
122/// use filter_expr::{Expr, Transform};
123/// use async_trait::async_trait;
124///
125/// struct MyTransformer;
126///
127/// #[async_trait]
128/// impl Transform for MyTransformer {
129///     async fn transform(&mut self, expr: Expr) -> Result<Expr, filter_expr::Error> {
130///         // Transform the expression before recursing
131///         Ok(match expr {
132///             Expr::Field(name) if name == "old_name" => {
133///                 Expr::Field("new_name".to_string())
134///             }
135///             other => other,
136///         })
137///     }
138/// }
139/// ```
140#[async_trait]
141pub trait Transform {
142    /// Transform an expression by recursively transforming all sub-expressions.
143    async fn transform(&mut self, expr: Expr) -> Result<Expr, Error>
144    where
145        Self: Sized;
146}
147
148impl Expr {
149    /// Recursively transform an expression using the provided transformer.
150    ///
151    /// ```rust
152    /// use filter_expr::{Expr, Transform};
153    /// use async_trait::async_trait;
154    ///
155    /// struct MyTransformer;
156    ///
157    /// #[async_trait]
158    /// impl Transform for MyTransformer {
159    ///     async fn transform(&mut self, expr: Expr) -> Result<Expr, filter_expr::Error> {
160    ///         // Transform the expression before recursing
161    ///         Ok(match expr {
162    ///             Expr::Field(name) if name == "old_name" => {
163    ///                 Expr::Field("new_name".to_string())
164    ///             }
165    ///             other => other,
166    ///         })
167    ///     }
168    /// }
169    ///
170    /// # #[tokio::main]
171    /// # async fn main() {
172    /// let expr = Expr::Field("old_name".to_string());
173    /// let mut transformer = MyTransformer;
174    /// let result = expr.transform(&mut transformer).await.unwrap();
175    /// assert_eq!(result, Expr::Field("new_name".to_string()));
176    /// # }
177    /// ```
178    pub async fn transform<F: Transform>(self, transformer: &mut F) -> Result<Expr, Error> {
179        let this = transformer.transform(self).await?;
180
181        Ok(match this {
182            Expr::Field(name) => Expr::Field(name),
183            Expr::Str(value) => Expr::Str(value),
184            Expr::I64(value) => Expr::I64(value),
185            Expr::F64(value) => Expr::F64(value),
186            Expr::Bool(value) => Expr::Bool(value),
187            Expr::Null => Expr::Null,
188            Expr::Array(value) => Expr::Array(value),
189
190            Expr::FuncCall(func, args) => {
191                let mut transformed_args = Vec::new();
192                for arg in args {
193                    transformed_args.push(transformer.transform(arg).await?);
194                }
195                Expr::FuncCall(func, transformed_args)
196            }
197            Expr::MethodCall(method, obj, args) => {
198                let obj = Box::new(transformer.transform(*obj).await?);
199                let mut transformed_args = Vec::new();
200                for arg in args {
201                    transformed_args.push(transformer.transform(arg).await?);
202                }
203                Expr::MethodCall(method, obj, transformed_args)
204            }
205
206            Expr::Gt(left, right) => {
207                let left = Box::new(transformer.transform(*left).await?);
208                let right = Box::new(transformer.transform(*right).await?);
209                Expr::Gt(left, right)
210            }
211            Expr::Lt(left, right) => {
212                let left = Box::new(transformer.transform(*left).await?);
213                let right = Box::new(transformer.transform(*right).await?);
214                Expr::Lt(left, right)
215            }
216            Expr::Ge(left, right) => {
217                let left = Box::new(transformer.transform(*left).await?);
218                let right = Box::new(transformer.transform(*right).await?);
219                Expr::Ge(left, right)
220            }
221            Expr::Le(left, right) => {
222                let left = Box::new(transformer.transform(*left).await?);
223                let right = Box::new(transformer.transform(*right).await?);
224                Expr::Le(left, right)
225            }
226            Expr::Eq(left, right) => {
227                let left = Box::new(transformer.transform(*left).await?);
228                let right = Box::new(transformer.transform(*right).await?);
229                Expr::Eq(left, right)
230            }
231            Expr::Ne(left, right) => {
232                let left = Box::new(transformer.transform(*left).await?);
233                let right = Box::new(transformer.transform(*right).await?);
234                Expr::Ne(left, right)
235            }
236            Expr::In(left, right) => {
237                let left = Box::new(transformer.transform(*left).await?);
238                let right = Box::new(transformer.transform(*right).await?);
239                Expr::In(left, right)
240            }
241            Expr::And(exprs) => {
242                let mut transformed_exprs = Vec::new();
243                for e in exprs {
244                    transformed_exprs.push(transformer.transform(e).await?);
245                }
246                Expr::And(transformed_exprs)
247            }
248            Expr::Or(exprs) => {
249                let mut transformed_exprs = Vec::new();
250                for e in exprs {
251                    transformed_exprs.push(transformer.transform(e).await?);
252                }
253                Expr::Or(transformed_exprs)
254            }
255            Expr::Not(expr) => {
256                let expr = Box::new(transformer.transform(*expr).await?);
257                Expr::Not(expr)
258            }
259        })
260    }
261}
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266
267    #[tokio::test]
268    async fn test_transform_expr_to_rename_field() {
269        mod rename_field {
270            use super::*;
271
272            pub struct RenameFieldTransformer {
273                pub old_name: String,
274                pub new_name: String,
275            }
276
277            #[async_trait::async_trait]
278            impl Transform for RenameFieldTransformer {
279                async fn transform(&mut self, expr: Expr) -> Result<Expr, Error> {
280                    Ok(match expr {
281                        Expr::Field(name) if name == self.old_name => {
282                            Expr::Field(self.new_name.clone())
283                        }
284                        _ => expr,
285                    })
286                }
287            }
288        }
289
290        let expr = Expr::eq_(
291            Expr::field_("old_name"),
292            Expr::str_("value"),
293        );
294
295        let mut transformer = rename_field::RenameFieldTransformer {
296            old_name: "old_name".to_string(),
297            new_name: "new_name".to_string(),
298        };
299
300        let result = expr.transform(&mut transformer).await.unwrap();
301        assert_eq!(
302            result,
303            Expr::Eq(
304                Box::new(Expr::field_("new_name")),
305                Box::new(Expr::str_("value"))
306            )
307        );
308    }
309
310    #[tokio::test]
311    async fn test_transform_expr_to_load_datas_from_external_datasource() {
312        mod foo {
313            use std::time::Duration;
314
315            use super::*;
316
317            pub struct FooTransformer;
318
319            #[async_trait::async_trait]
320            impl Transform for FooTransformer {
321                async fn transform(&mut self, expr: Expr) -> Result<Expr, Error> {
322                    Ok(match expr {
323                        Expr::FuncCall(fn_name, args) if fn_name == "is_not_bad" => {
324                            if args.len() != 1 {
325                                return Err(Error::Transform("expected 1 argument".to_string()));
326                            }
327                            let datas = load_datas().await;
328                            Expr::In(Box::new(args[0].clone()), Box::new(Expr::Array(datas)))
329                        }
330                        _ => expr,
331                    })
332                }
333            }
334
335            async fn load_datas() -> Vec<Expr> {
336                tokio::time::sleep(Duration::from_millis(100)).await;
337
338                vec![
339                    Expr::Str("foo".to_string()),
340                    Expr::Str("bar".to_string()),
341                ]
342            }
343        }
344
345        let expr = Expr::and_([
346            Expr::func_call_("is_not_bad", vec![Expr::field_("magic")]),
347            Expr::func_call_("is_not_bad", vec![Expr::field_("foobar")]),
348        ]);
349
350        let mut transformer = foo::FooTransformer;
351        let result = expr.transform(&mut transformer).await.unwrap();
352        assert_eq!(result, Expr::and_([
353            Expr::in_(Expr::field_("magic"), Expr::array_([Expr::str_("foo"), Expr::str_("bar")])),
354            Expr::in_(Expr::field_("foobar"), Expr::array_([Expr::str_("foo"), Expr::str_("bar")])),
355        ]));
356    }
357}