• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16943034431

13 Aug 2025 04:15PM UTC coverage: 87.687% (+0.02%) from 87.665%
16943034431

Pull #4230

github

web-flow
Merge 655f3955a into e305f7ca3
Pull Request #4230: feat[expr]: add back the expression folder, implemented over `Node`

111 of 125 new or added lines in 2 files covered. (88.8%)

1 existing line in 1 file now uncovered.

56608 of 64557 relevant lines covered (87.69%)

626279.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.08
/vortex-expr/src/traversal/mod.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
//! Datafusion inspired tree traversal logic.
5
//!
6
//! Users should want to implement [`Node`] and potentially [`NodeContainer`].
7

8
mod fold;
9
mod references;
10
mod visitor;
11

12
use std::marker::PhantomData;
13
use std::sync::Arc;
14

15
use itertools::Itertools;
16
pub use references::ReferenceCollector;
17
pub use visitor::{pre_order_visit_down, pre_order_visit_up};
18
use vortex_error::VortexResult;
19

20
use crate::ExprRef;
21
use crate::traversal::fold::{NodeFolder, NodeFolderContext, NodeFolderContextWrapper};
22

23
/// Signal to control a traversal's flow
24
#[derive(Debug, Clone, PartialEq, Eq)]
25
pub enum TraversalOrder {
26
    /// In a top-down traversal, skip visiting the children of the current node.
27
    /// In the bottom-up phase of the traversal, skip the next step. Either skipping the children of the node,
28
    /// moving to its next sibling, or skipping its parent once the children are traversed.
29
    Skip,
30
    /// Stop visiting any more nodes in the traversal.
31
    Stop,
32
    /// Continue with the traversal as expected.
33
    Continue,
34
}
35

36
impl TraversalOrder {
37
    /// If directed to, continue to visit nodes by running `f`, which should apply on the node's children.
38
    pub fn visit_children<F: FnOnce() -> VortexResult<TraversalOrder>>(
155,389✔
39
        self,
155,389✔
40
        f: F,
155,389✔
41
    ) -> VortexResult<TraversalOrder> {
155,389✔
42
        match self {
155,389✔
43
            Self::Skip => Ok(TraversalOrder::Continue),
15,141✔
44
            Self::Stop => Ok(self),
1✔
45
            Self::Continue => f(),
140,247✔
46
        }
47
    }
155,389✔
48

49
    /// If directed to, continue to visit nodes by running `f`, which should apply on the node's parent.
50
    pub fn visit_parent<F: FnOnce() -> VortexResult<TraversalOrder>>(
155,389✔
51
        self,
155,389✔
52
        f: F,
155,389✔
53
    ) -> VortexResult<TraversalOrder> {
155,389✔
54
        match self {
155,389✔
55
            Self::Continue => f(),
155,387✔
56
            Self::Skip | Self::Stop => Ok(self),
2✔
57
        }
58
    }
155,389✔
59
}
60

61
pub enum FoldDownContext<C, R> {
62
    Continue(C),
63
    Stop(R),
64
    Skip(R),
65
}
66

67
pub enum FoldDown<R> {
68
    Continue,
69
    Stop(R),
70
    Skip(R),
71
}
72

73
pub enum FoldUp<R> {
74
    Continue(R),
75
    Stop(R),
76
}
77

78
impl<R> FoldUp<R> {
79
    pub fn value(self) -> R {
4✔
80
        match self {
4✔
81
            Self::Continue(r) => r,
3✔
82
            Self::Stop(r) => r,
1✔
83
        }
84
    }
4✔
85
}
86

87
#[derive(Debug, Clone)]
88
pub struct Transformed<T> {
89
    /// Value that was being rewritten.
90
    pub value: T,
91
    /// Controls the flow of rewriting, see [`TraversalOrder`] for more details.
92
    pub order: TraversalOrder,
93
    /// Was the value changed during rewriting.
94
    pub changed: bool,
95
}
96

97
impl<T> Transformed<T> {
98
    pub fn yes(value: T) -> Self {
17,054✔
99
        Self {
17,054✔
100
            value,
17,054✔
101
            order: TraversalOrder::Continue,
17,054✔
102
            changed: true,
17,054✔
103
        }
17,054✔
104
    }
17,054✔
105

106
    pub fn no(value: T) -> Self {
1,413,121✔
107
        Self {
1,413,121✔
108
            value,
1,413,121✔
109
            order: TraversalOrder::Continue,
1,413,121✔
110
            changed: false,
1,413,121✔
111
        }
1,413,121✔
112
    }
1,413,121✔
113

114
    pub fn into_inner(self) -> T {
87,235✔
115
        self.value
87,235✔
116
    }
87,235✔
117

118
    /// Apply a function to `value`, changing it without changing the `changed` field.
119
    pub fn map<O, F: FnOnce(T) -> O>(self, f: F) -> Transformed<O> {
×
120
        Transformed {
×
121
            value: f(self.value),
×
122
            order: self.order,
×
123
            changed: self.changed,
×
124
        }
×
125
    }
×
126
}
127

128
pub trait NodeVisitor<'a> {
129
    type NodeTy: Node;
130

131
    fn visit_down(&mut self, node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
×
132
        _ = node;
×
NEW
133
        Ok(TraversalOrder::Continue)
×
134
    }
×
135

136
    fn visit_up(&mut self, node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
122,061✔
137
        _ = node;
122,061✔
138
        Ok(TraversalOrder::Continue)
122,061✔
139
    }
122,061✔
140
}
141

142
pub trait NodeRewriter: Sized {
143
    type NodeTy: Node;
144

145
    fn visit_down(&mut self, node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
×
146
        Ok(Transformed::no(node))
×
NEW
147
    }
×
148

NEW
149
    fn visit_up(&mut self, node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
×
NEW
150
        Ok(Transformed::no(node))
×
NEW
151
    }
×
152
}
153

154
pub trait Node: Sized + Clone {
155
    /// Walk the node's children by applying `f` to them.
156
    ///
157
    /// This is a lower level API that other functions rely on for their implementation.
158
    fn apply_children<'a, F: FnMut(&'a Self) -> VortexResult<TraversalOrder>>(
159
        &'a self,
160
        f: F,
161
    ) -> VortexResult<TraversalOrder>;
162

163
    /// Rewrite the node's children by applying `f` to them.
164
    ///
165
    /// This is a lower level API that other functions rely on for their implementation.
166
    fn map_children<F: FnMut(Self) -> VortexResult<Transformed<Self>>>(
167
        self,
168
        f: F,
169
    ) -> VortexResult<Transformed<Self>>;
170

171
    /// This is a lower level API that other functions rely on for their implementation.
172
    fn iter_children<T>(&self, f: impl FnOnce(&mut dyn Iterator<Item = &Self>) -> T) -> T;
173

174
    /// This is a lower level API that other functions rely on for their implementation.
175
    fn children_count(&self) -> usize;
176
}
177

178
pub trait NodeExt: Node {
179
    fn fold_context<R, F: NodeFolderContext<NodeTy = Self, Result = R>>(
15✔
180
        self,
15✔
181
        ctx: &F::Context,
15✔
182
        folder: &mut F,
15✔
183
    ) -> VortexResult<FoldUp<R>> {
15✔
184
        let transformed = folder.visit_down(ctx, &self)?;
15✔
185
        let ctx = match transformed {
15✔
186
            FoldDownContext::Continue(ctx) => ctx,
12✔
187
            FoldDownContext::Skip(r) => return Ok(FoldUp::Continue(r)),
2✔
188
            FoldDownContext::Stop(r) => return Ok(FoldUp::Stop(r)),
1✔
189
        };
190

191
        let mut children = Vec::with_capacity(self.children_count());
12✔
192
        let mut stop_result = None;
12✔
193
        self.iter_children(|children_iter| -> VortexResult<()> {
12✔
194
            for c in children_iter {
21✔
195
                let t = c.clone().fold_context(&ctx, folder)?;
11✔
196
                match t {
11✔
197
                    FoldUp::Stop(r) => {
2✔
198
                        stop_result = Some(r);
2✔
199
                        return Ok(());
2✔
200
                    }
201
                    FoldUp::Continue(r) => {
9✔
202
                        children.push(r);
9✔
203
                    }
9✔
204
                }
205
            }
206
            Ok(())
10✔
207
        })?;
12✔
208

209
        if let Some(result) = stop_result {
12✔
210
            return Ok(FoldUp::Stop(result));
2✔
211
        }
10✔
212

213
        folder.visit_up(self, &ctx, children)
10✔
214
    }
15✔
215

216
    fn fold<R, F: NodeFolder<NodeTy = Self, Result = R>>(
4✔
217
        self,
4✔
218
        folder: &mut F,
4✔
219
    ) -> VortexResult<FoldUp<R>> {
4✔
220
        let mut folder = NodeFolderContextWrapper { inner: folder };
4✔
221
        self.fold_context(&(), &mut folder)
4✔
222
    }
4✔
223

224
    /// Walk the tree in pre-order (top-down) way, rewriting it as it goes.
225
    fn rewrite<R: NodeRewriter<NodeTy = Self>>(
486,938✔
226
        self,
486,938✔
227
        rewriter: &mut R,
486,938✔
228
    ) -> VortexResult<Transformed<Self>> {
486,938✔
229
        let mut transformed = rewriter.visit_down(self)?;
486,938✔
230

231
        let transformed = match transformed.order {
486,938✔
NEW
232
            TraversalOrder::Stop => Ok(transformed),
×
233
            TraversalOrder::Skip => {
234
                transformed.order = TraversalOrder::Continue;
7,669✔
235
                Ok(transformed)
7,669✔
236
            }
237
            TraversalOrder::Continue => transformed
479,269✔
238
                .value
479,269✔
239
                .map_children(|c| c.rewrite(rewriter))
479,269✔
240
                .map(|mut t| {
479,269✔
241
                    t.changed |= transformed.changed;
479,269✔
242
                    t
479,269✔
243
                }),
479,269✔
NEW
244
        }?;
×
245

246
        match transformed.order {
486,938✔
NEW
247
            TraversalOrder::Stop | TraversalOrder::Skip => Ok(transformed),
×
248
            TraversalOrder::Continue => {
249
                let mut up_rewrite = rewriter.visit_up(transformed.value)?;
486,938✔
250
                up_rewrite.changed |= transformed.changed;
486,938✔
251
                Ok(up_rewrite)
486,938✔
252
            }
253
        }
254
    }
486,938✔
255

256
    /// A pre-order (top-down) traversal.
257
    fn accept<'a, V: NodeVisitor<'a, NodeTy = Self>>(
155,389✔
258
        &'a self,
155,389✔
259
        visitor: &mut V,
155,389✔
260
    ) -> VortexResult<TraversalOrder> {
155,389✔
261
        visitor
155,389✔
262
            .visit_down(self)?
155,389✔
263
            .visit_children(|| self.apply_children(|c| c.accept(visitor)))?
155,389✔
264
            .visit_parent(|| visitor.visit_up(self))
155,389✔
265
    }
155,389✔
266

267
    /// A pre-order transformation
NEW
268
    fn transform_down<F: FnMut(Self) -> VortexResult<Transformed<Self>>>(
×
NEW
269
        self,
×
NEW
270
        f: F,
×
NEW
271
    ) -> VortexResult<Transformed<Self>> {
×
272
        let mut rewriter = FnRewriter {
×
273
            f_down: Some(f),
×
NEW
274
            f_up: None,
×
NEW
275
            _data: PhantomData,
×
276
        };
×
277

278
        self.rewrite(&mut rewriter)
×
279
    }
×
280

281
    /// A post-order transform
282
    fn transform_up<F: FnMut(Self) -> VortexResult<Transformed<Self>>>(
87,236✔
283
        self,
87,236✔
284
        f: F,
87,236✔
285
    ) -> VortexResult<Transformed<Self>> {
87,236✔
286
        let mut rewriter = FnRewriter {
87,236✔
287
            f_down: None,
87,236✔
288
            f_up: Some(f),
87,236✔
289
            _data: PhantomData,
87,236✔
290
        };
87,236✔
291

292
        self.rewrite(&mut rewriter)
87,236✔
293
    }
87,236✔
294
}
295

296
impl<T: Node> NodeExt for T {}
297

298
struct FnRewriter<F, T> {
299
    f_down: Option<F>,
300
    f_up: Option<F>,
301
    _data: PhantomData<T>,
302
}
303

304
impl<F, T> NodeRewriter for FnRewriter<F, T>
305
where
306
    T: Node,
307
    F: FnMut(T) -> VortexResult<Transformed<T>>,
308
{
309
    type NodeTy = T;
310

311
    fn visit_down(&mut self, node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
477,837✔
312
        if let Some(f) = self.f_down.as_mut() {
477,837✔
313
            f(node)
×
314
        } else {
315
            Ok(Transformed::no(node))
477,837✔
316
        }
317
    }
477,837✔
318

319
    fn visit_up(&mut self, node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
477,837✔
320
        if let Some(f) = self.f_up.as_mut() {
477,837✔
321
            f(node)
477,837✔
322
        } else {
323
            Ok(Transformed::no(node))
×
324
        }
325
    }
477,837✔
326
}
327

328
/// A container holding a [`Node`]'s children, which a function can be applied (or mapped) to.
329
///
330
/// The trait is also implemented to container types in order to make implementing [`Node::map_children`]
331
/// and [`Node::apply_children`] easier.
332
pub trait NodeContainer<'a, T: 'a>: Sized {
333
    /// Applies `f` to all elements of the container, accepting them by reference
334
    fn apply_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
335
        &'a self,
336
        f: F,
337
    ) -> VortexResult<TraversalOrder>;
338

339
    /// Consumes all the children of the node, replacing them with the result of `f`.
340
    fn map_elements<F: FnMut(T) -> VortexResult<Transformed<T>>>(
341
        self,
342
        f: F,
343
    ) -> VortexResult<Transformed<Self>>;
344
}
345

346
pub trait NodeRefContainer<'a, T: 'a>: Sized {
347
    fn apply_ref_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
348
        &self,
349
        f: F,
350
    ) -> VortexResult<TraversalOrder>;
351
}
352

353
impl<'a, T: 'a, C: NodeContainer<'a, T>> NodeRefContainer<'a, T> for Vec<&'a C> {
354
    fn apply_ref_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
140,247✔
355
        &self,
140,247✔
356
        mut f: F,
140,247✔
357
    ) -> VortexResult<TraversalOrder> {
140,247✔
358
        let mut order = TraversalOrder::Continue;
140,247✔
359

360
        for c in self {
250,047✔
361
            order = c.apply_elements(&mut f)?;
109,801✔
362
            match order {
109,801✔
363
                TraversalOrder::Continue | TraversalOrder::Skip => {}
109,800✔
364
                TraversalOrder::Stop => return Ok(TraversalOrder::Stop),
1✔
365
            }
366
        }
367

368
        Ok(order)
140,246✔
369
    }
140,247✔
370
}
371

372
impl<'a, T: 'a, C: NodeContainer<'a, T>> NodeContainer<'a, T> for Box<C> {
373
    fn apply_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
×
374
        &'a self,
×
375
        f: F,
×
376
    ) -> VortexResult<TraversalOrder> {
×
377
        self.as_ref().apply_elements(f)
×
378
    }
×
379

380
    fn map_elements<F: FnMut(T) -> VortexResult<Transformed<T>>>(
×
381
        self,
×
382
        f: F,
×
383
    ) -> VortexResult<Transformed<Box<C>>> {
×
384
        Ok((*self).map_elements(f)?.map(Box::new))
×
385
    }
×
386
}
387

388
impl<'a, T, C> NodeContainer<'a, T> for Arc<C>
389
where
390
    T: 'a,
391
    C: NodeContainer<'a, T> + Clone,
392
{
393
    fn apply_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
×
394
        &'a self,
×
395
        f: F,
×
396
    ) -> VortexResult<TraversalOrder> {
×
397
        self.as_ref().apply_elements(f)
×
398
    }
×
399

400
    fn map_elements<F: FnMut(T) -> VortexResult<Transformed<T>>>(
×
401
        self,
×
402
        f: F,
×
403
    ) -> VortexResult<Transformed<Arc<C>>> {
×
404
        Ok(Arc::unwrap_or_clone(self).map_elements(f)?.map(Arc::new))
×
405
    }
×
406
}
407

408
impl<'a, T: 'a, C: NodeContainer<'a, T>> NodeContainer<'a, T> for [C; 2] {
409
    fn apply_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
×
410
        &'a self,
×
411
        mut f: F,
×
412
    ) -> VortexResult<TraversalOrder> {
×
413
        let [lhs, rhs] = self;
×
414
        match lhs.apply_elements(&mut f)? {
×
415
            TraversalOrder::Skip | TraversalOrder::Continue => rhs.apply_elements(&mut f),
×
416
            TraversalOrder::Stop => Ok(TraversalOrder::Stop),
×
417
        }
418
    }
×
419

420
    fn map_elements<F: FnMut(T) -> VortexResult<Transformed<T>>>(
×
421
        self,
×
422
        mut f: F,
×
423
    ) -> VortexResult<Transformed<[C; 2]>> {
×
424
        let [lhs, rhs] = self;
×
425
        let transformed = lhs.map_elements(&mut f)?;
×
426
        match transformed.order {
×
427
            TraversalOrder::Skip | TraversalOrder::Continue => {
428
                let mut t = rhs.map_elements(&mut f)?;
×
429
                t.changed |= transformed.changed;
×
430
                Ok(t.map(|new_lhs| [new_lhs, transformed.value]))
×
431
            }
432
            TraversalOrder::Stop => Ok(transformed.map(|new_lhs| [new_lhs, rhs])),
×
433
        }
434
    }
×
435
}
436

437
impl<'a, T: 'a, C: NodeContainer<'a, T>> NodeContainer<'a, T> for Vec<C> {
438
    fn apply_elements<F: FnMut(&'a T) -> VortexResult<TraversalOrder>>(
×
439
        &'a self,
×
440
        mut f: F,
×
441
    ) -> VortexResult<TraversalOrder> {
×
442
        let mut order = TraversalOrder::Continue;
×
443

444
        for c in self {
×
445
            order = c.apply_elements(&mut f)?;
×
446
            match order {
×
447
                TraversalOrder::Continue | TraversalOrder::Skip => {}
×
448
                TraversalOrder::Stop => return Ok(TraversalOrder::Stop),
×
449
            }
450
        }
451

452
        Ok(order)
×
453
    }
×
454

455
    fn map_elements<F: FnMut(T) -> VortexResult<Transformed<T>>>(
479,269✔
456
        self,
479,269✔
457
        mut f: F,
479,269✔
458
    ) -> VortexResult<Transformed<Self>> {
479,269✔
459
        let mut order = TraversalOrder::Continue;
479,269✔
460
        let mut changed = false;
479,269✔
461

462
        let value = self
479,269✔
463
            .into_iter()
479,269✔
464
            .map(|c| match order {
479,269✔
465
                TraversalOrder::Continue | TraversalOrder::Skip => {
466
                    c.map_elements(&mut f).map(|result| {
394,072✔
467
                        order = result.order;
394,072✔
468
                        changed |= result.changed;
394,072✔
469
                        result.value
394,072✔
470
                    })
394,072✔
471
                }
472
                TraversalOrder::Stop => Ok(c),
×
473
            })
394,072✔
474
            .collect::<VortexResult<Vec<_>>>()?;
479,269✔
475

476
        Ok(Transformed {
479,269✔
477
            value,
479,269✔
478
            order,
479,269✔
479
            changed,
479,269✔
480
        })
479,269✔
481
    }
479,269✔
482
}
483

484
impl<'a> NodeContainer<'a, Self> for ExprRef {
485
    fn apply_elements<F: FnMut(&'a Self) -> VortexResult<TraversalOrder>>(
109,801✔
486
        &'a self,
109,801✔
487
        mut f: F,
109,801✔
488
    ) -> VortexResult<TraversalOrder> {
109,801✔
489
        f(self)
109,801✔
490
    }
109,801✔
491

492
    fn map_elements<F: FnMut(Self) -> VortexResult<Transformed<Self>>>(
394,072✔
493
        self,
394,072✔
494
        mut f: F,
394,072✔
495
    ) -> VortexResult<Transformed<Self>> {
394,072✔
496
        f(self)
394,072✔
497
    }
394,072✔
498
}
499

500
impl Node for ExprRef {
501
    fn apply_children<'a, F: FnMut(&'a Self) -> VortexResult<TraversalOrder>>(
140,247✔
502
        &'a self,
140,247✔
503
        mut f: F,
140,247✔
504
    ) -> VortexResult<TraversalOrder> {
140,247✔
505
        self.children().apply_ref_elements(&mut f)
140,247✔
506
    }
140,247✔
507

508
    fn map_children<F: FnMut(Self) -> VortexResult<Transformed<Self>>>(
479,269✔
509
        self,
479,269✔
510
        f: F,
479,269✔
511
    ) -> VortexResult<Transformed<Self>> {
479,269✔
512
        let transformed = self
479,269✔
513
            .children()
479,269✔
514
            .into_iter()
479,269✔
515
            .cloned()
479,269✔
516
            .collect_vec()
479,269✔
517
            .map_elements(f)?;
479,269✔
518

519
        if transformed.changed {
479,269✔
520
            Ok(Transformed {
521
                value: self.with_children(transformed.value)?,
16,034✔
522
                order: transformed.order,
16,034✔
523
                changed: true,
524
            })
525
        } else {
526
            Ok(Transformed::no(self))
463,235✔
527
        }
528
    }
479,269✔
529

530
    fn iter_children<T>(&self, f: impl FnOnce(&mut dyn Iterator<Item = &Self>) -> T) -> T {
12✔
531
        f(&mut self.children().into_iter())
12✔
532
    }
12✔
533

534
    fn children_count(&self) -> usize {
12✔
535
        self.children().len()
12✔
536
    }
12✔
537
}
538

539
#[cfg(test)]
540
mod tests {
541
    use std::sync::Arc;
542

543
    use vortex_error::VortexResult;
544
    use vortex_utils::aliases::hash_set::HashSet;
545

546
    use crate::traversal::visitor::pre_order_visit_down;
547
    use crate::traversal::{NodeExt, NodeRewriter, NodeVisitor, Transformed, TraversalOrder};
548
    use crate::{
549
        BinaryExpr, BinaryVTable, ExprRef, GetItemVTable, IntoExpr, LiteralExpr, LiteralVTable,
550
        Operator, VortexExpr, col, is_root, root,
551
    };
552

553
    #[derive(Default)]
554
    pub struct ExprLitCollector<'a>(pub Vec<&'a ExprRef>);
555

556
    impl<'a> NodeVisitor<'a> for ExprLitCollector<'a> {
557
        type NodeTy = ExprRef;
558

559
        fn visit_down(&mut self, node: &'a ExprRef) -> VortexResult<TraversalOrder> {
11✔
560
            if node.is::<LiteralVTable>() {
11✔
561
                self.0.push(node)
5✔
562
            }
6✔
563
            Ok(TraversalOrder::Continue)
11✔
564
        }
11✔
565

566
        fn visit_up(&mut self, _node: &'a ExprRef) -> VortexResult<TraversalOrder> {
11✔
567
            Ok(TraversalOrder::Continue)
11✔
568
        }
11✔
569
    }
570

571
    fn expr_col_to_lit_transform(
7✔
572
        node: ExprRef,
7✔
573
        idx: &mut i32,
7✔
574
    ) -> VortexResult<Transformed<ExprRef>> {
7✔
575
        if node.is::<GetItemVTable>() {
7✔
576
            let lit_id = *idx;
2✔
577
            *idx += 1;
2✔
578
            Ok(Transformed::yes(LiteralExpr::new_expr(lit_id)))
2✔
579
        } else {
580
            Ok(Transformed::no(node))
5✔
581
        }
582
    }
7✔
583

584
    #[derive(Default)]
585
    pub struct SkipDownRewriter;
586

587
    impl NodeRewriter for SkipDownRewriter {
588
        type NodeTy = ExprRef;
589

590
        fn visit_down(&mut self, node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
1✔
591
            Ok(Transformed {
1✔
592
                value: node,
1✔
593
                order: TraversalOrder::Skip,
1✔
594
                changed: false,
1✔
595
            })
1✔
596
        }
1✔
597

598
        fn visit_up(&mut self, _node: Self::NodeTy) -> VortexResult<Transformed<Self::NodeTy>> {
1✔
599
            Ok(Transformed::yes(root()))
1✔
600
        }
1✔
601
    }
602

603
    #[test]
604
    fn expr_deep_visitor_test() {
1✔
605
        let col1: Arc<dyn VortexExpr> = col("col1");
1✔
606
        let lit1 = LiteralExpr::new(1).into_expr();
1✔
607
        let expr = BinaryExpr::new(col1.clone(), Operator::Eq, lit1.clone()).into_expr();
1✔
608
        let lit2 = LiteralExpr::new(2).into_expr();
1✔
609
        let expr = BinaryExpr::new(expr, Operator::And, lit2).into_expr();
1✔
610
        let mut printer = ExprLitCollector::default();
1✔
611
        expr.accept(&mut printer).unwrap();
1✔
612
        assert_eq!(printer.0.len(), 2);
1✔
613
    }
1✔
614

615
    #[test]
616
    fn expr_deep_mut_visitor_test() {
1✔
617
        let col1: Arc<dyn VortexExpr> = col("col1");
1✔
618
        let col2: Arc<dyn VortexExpr> = col("col2");
1✔
619
        let expr = BinaryExpr::new_expr(col1.clone(), Operator::Eq, col2.clone());
1✔
620
        let lit2 = LiteralExpr::new_expr(2);
1✔
621
        let expr = BinaryExpr::new_expr(expr, Operator::And, lit2);
1✔
622

623
        let mut idx = 0_i32;
1✔
624
        let new = expr
1✔
625
            .transform_up(|node| expr_col_to_lit_transform(node, &mut idx))
7✔
626
            .unwrap();
1✔
627
        assert!(new.changed);
1✔
628

629
        let expr = new.value;
1✔
630

631
        let mut printer = ExprLitCollector::default();
1✔
632
        expr.accept(&mut printer).unwrap();
1✔
633
        assert_eq!(printer.0.len(), 3);
1✔
634
    }
1✔
635

636
    #[test]
637
    fn expr_skip_test() {
1✔
638
        let col1: Arc<dyn VortexExpr> = col("col1");
1✔
639
        let col2: Arc<dyn VortexExpr> = col("col2");
1✔
640
        let expr1 = BinaryExpr::new_expr(col1.clone(), Operator::Eq, col2.clone());
1✔
641
        let col3: Arc<dyn VortexExpr> = col("col3");
1✔
642
        let col4: Arc<dyn VortexExpr> = col("col4");
1✔
643
        let expr2 = BinaryExpr::new_expr(col3.clone(), Operator::NotEq, col4.clone());
1✔
644
        let expr = BinaryExpr::new_expr(expr1, Operator::And, expr2);
1✔
645

646
        let mut nodes = Vec::new();
1✔
647
        pre_order_visit_down(&expr, |node: &ExprRef| {
7✔
648
            if node.is::<GetItemVTable>() {
7✔
649
                nodes.push(node)
2✔
650
            }
5✔
651
            if let Some(bin) = node.as_opt::<BinaryVTable>()
7✔
652
                && bin.op() == Operator::Eq
3✔
653
            {
654
                return Ok(TraversalOrder::Skip);
1✔
655
            }
6✔
656
            Ok(TraversalOrder::Continue)
6✔
657
        })
7✔
658
        .unwrap();
1✔
659

660
        let nodes: HashSet<ExprRef> = HashSet::from_iter(nodes.into_iter().cloned());
1✔
661
        assert_eq!(nodes, HashSet::from_iter([col("col3"), col("col4")]));
1✔
662
    }
1✔
663

664
    #[test]
665
    fn expr_stop_test() {
1✔
666
        let col1: Arc<dyn VortexExpr> = col("col1");
1✔
667
        let col2: Arc<dyn VortexExpr> = col("col2");
1✔
668
        let expr1 = BinaryExpr::new_expr(col1.clone(), Operator::Eq, col2.clone());
1✔
669
        let col3: Arc<dyn VortexExpr> = col("col3");
1✔
670
        let col4: Arc<dyn VortexExpr> = col("col4");
1✔
671
        let expr2 = BinaryExpr::new_expr(col3.clone(), Operator::NotEq, col4.clone());
1✔
672
        let expr = BinaryExpr::new_expr(expr1, Operator::And, expr2);
1✔
673

674
        let mut nodes = Vec::new();
1✔
675
        pre_order_visit_down(&expr, |node: &ExprRef| {
2✔
676
            if node.is::<GetItemVTable>() {
2✔
677
                nodes.push(node)
678
            }
2✔
679
            if let Some(bin) = node.as_opt::<BinaryVTable>()
2✔
680
                && bin.op() == Operator::Eq
2✔
681
            {
682
                return Ok(TraversalOrder::Stop);
1✔
683
            }
1✔
684
            Ok(TraversalOrder::Continue)
1✔
685
        })
2✔
686
        .unwrap();
1✔
687

688
        assert!(nodes.is_empty());
1✔
689
    }
1✔
690

691
    #[test]
692
    fn expr_skip_down_visit_up() {
1✔
693
        let col = col("col");
1✔
694

695
        let mut visitor = SkipDownRewriter;
1✔
696
        let result = col.rewrite(&mut visitor).unwrap();
1✔
697

698
        assert!(result.changed);
1✔
699
        assert!(is_root(&result.value));
1✔
700
    }
1✔
701
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc