qrlew/expr/
split.rs

1//! The splits with some improvements
2//! Each split has named Expr and anonymous exprs
3use super::{
4    aggregate, function, visitor::Acceptor, AggregateColumn, Column, Expr, Function, Identifier,
5    Value, Visitor,
6};
7use crate::{
8    namer::{self, FIELD},
9    And, Factor,
10};
11use colored::Colorize;
12use itertools::Itertools;
13use std::{fmt, sync::Arc};
14
15/* Basic rules
16Insertion of a split along another should happen at the bottom of an existing split if it has columns and at the top else.
17 */
18
19#[derive(Clone, Debug, Hash, PartialEq, Eq)]
20pub enum Split {
21    Map(Map),
22    Reduce(Reduce),
23}
24
25impl Split {
26    pub fn filter(expr: Expr) -> Map {
27        Map::new(vec![], Some(expr), vec![], None)
28    }
29
30    pub fn order_by(expr: Expr, asc: bool) -> Map {
31        Map::new(vec![], None, vec![(expr, asc)], None)
32    }
33
34    pub fn reduce<S: Into<String>>(name: S, aggregate: AggregateColumn) -> Reduce {
35        Reduce::new(vec![(name.into(), aggregate)], vec![], None)
36    }
37
38    pub fn group_by(expr: Expr) -> Reduce {
39        if let Expr::Column(col) = expr {
40            // If the expression is a column
41            Reduce::new(vec![], vec![col], None)
42        } else {
43            // If not
44            let name = namer::name_from_content(FIELD, &expr);
45            let map = Map::new(vec![(name.clone(), expr)], None, vec![], None);
46            Reduce::new(vec![], vec![name.into()], Some(map))
47        }
48    }
49
50    pub fn into_map(self) -> Map {
51        match self {
52            Split::Map(map) => map,
53            Split::Reduce(reduce) => reduce.into_map(),
54        }
55    }
56
57    pub fn into_reduce(self, aggregate: aggregate::Aggregate) -> Reduce {
58        match self {
59            Split::Map(map) => map.into_reduce(aggregate),
60            Split::Reduce(reduce) => reduce,
61        }
62    }
63
64    pub fn len(&self) -> usize {
65        match self {
66            Split::Map(m) => m.len(),
67            Split::Reduce(r) => r.len(),
68        }
69    }
70
71    pub fn map_last<F: FnOnce(Split) -> Split>(self, f: F) -> Self {
72        match self {
73            Split::Map(m) => m.map_last(f).into(),
74            Split::Reduce(r) => r.map_last(f).into(),
75        }
76    }
77
78    pub fn map_last_map<F: FnOnce(Map) -> Map>(self, f: F) -> Self {
79        match self {
80            Split::Map(m) => m.map_last_map(f).into(),
81            Split::Reduce(r) => r.map_last_map(f).into(),
82        }
83    }
84
85    pub fn map_last_reduce<F: FnOnce(Reduce) -> Reduce>(self, f: F) -> Self {
86        match self {
87            Split::Map(m) => m.map_last_reduce(f).into(),
88            Split::Reduce(r) => r.map_last_reduce(f).into(),
89        }
90    }
91}
92
93impl Default for Split {
94    fn default() -> Self {
95        Split::Reduce(Reduce::default())
96    }
97}
98
99impl fmt::Display for Split {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            Split::Map(map) => map.fmt(f),
103            Split::Reduce(reduce) => reduce.fmt(f),
104        }
105    }
106}
107
108impl From<Map> for Split {
109    fn from(map: Map) -> Self {
110        Split::Map(map)
111    }
112}
113
114impl From<Reduce> for Split {
115    fn from(reduce: Reduce) -> Self {
116        Split::Reduce(reduce)
117    }
118}
119
120impl And<Split> for Split {
121    type Product = Split;
122
123    fn and(self, other: Split) -> Self::Product {
124        match (self, other) {
125            (Split::Map(s), Split::Map(o)) => s.and(o).into(),
126            (Split::Map(s), Split::Reduce(o)) => s.and(o).into(),
127            (Split::Reduce(s), Split::Map(o)) => s.and(o).into(),
128            (Split::Reduce(s), Split::Reduce(o)) => s.and(o).into(),
129        }
130    }
131}
132
133/// A split with stable number of subsplits
134#[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
135pub struct Map {
136    pub named_exprs: Vec<(String, Expr)>,
137    pub filter: Option<Expr>,
138    pub order_by: Vec<(Expr, bool)>,
139    pub reduce: Option<Box<Reduce>>,
140}
141
142impl Map {
143    /// Maps should be built using this builder
144    pub fn new(
145        named_exprs: Vec<(String, Expr)>,
146        filter: Option<Expr>,
147        order_by: Vec<(Expr, bool)>,
148        reduce: Option<Reduce>,
149    ) -> Self {
150        Map {
151            named_exprs: named_exprs.into_iter().unique().collect(),
152            filter,
153            order_by: order_by.into_iter().unique().collect(),
154            reduce: reduce.map(Box::new),
155        }
156    }
157
158    pub fn named_exprs(&self) -> &[(String, Expr)] {
159        &self.named_exprs
160    }
161
162    pub fn filter(&self) -> &Option<Expr> {
163        &self.filter
164    }
165
166    pub fn order_by(&self) -> &Vec<(Expr, bool)> {
167        &self.order_by
168    }
169
170    pub fn reduce(&self) -> Option<&Reduce> {
171        self.reduce.as_deref()
172    }
173
174    pub fn into_reduce(self, aggregate: aggregate::Aggregate) -> Reduce {
175        let Map {
176            named_exprs,
177            filter,
178            order_by,
179            reduce,
180        } = self;
181        let (named_aliases, aliased_expr): (Vec<(String, AggregateColumn)>, Vec<(String, Expr)>) =
182            named_exprs
183                .into_iter()
184                .map(|(name, expr)| {
185                    let alias = namer::name_from_content(FIELD, &expr);
186                    (
187                        (name, AggregateColumn::new(aggregate, alias.clone().into())),
188                        (alias, expr),
189                    )
190                })
191                .unzip();
192        Reduce::new(
193            named_aliases,
194            vec![],
195            Some(Map::new(aliased_expr, filter, order_by, reduce.map(|r| *r))),
196        )
197    }
198
199    pub fn len(&self) -> usize {
200        1 + self.reduce().map_or(0, |r| r.len())
201    }
202
203    pub fn map_last<F: FnOnce(Split) -> Split>(self, f: F) -> Self {
204        match self.reduce {
205            Some(reduce) => Map::new(
206                self.named_exprs,
207                self.filter,
208                self.order_by,
209                Some(reduce.map_last(f)),
210            ),
211            None => {
212                let split = f(self.clone().into());
213                if let Split::Map(map) = split {
214                    map
215                } else {
216                    self
217                }
218            }
219        }
220    }
221
222    pub fn map_last_map<F: FnOnce(Map) -> Map>(self, f: F) -> Self {
223        match self.reduce {
224            Some(reduce) => match reduce.map {
225                Some(_) => Map::new(
226                    self.named_exprs,
227                    self.filter,
228                    self.order_by,
229                    Some(reduce.map_last_map(f)),
230                ),
231                None => f(Map::new(
232                    self.named_exprs,
233                    self.filter,
234                    self.order_by,
235                    Some(*reduce),
236                )),
237            },
238            None => f(self),
239        }
240    }
241
242    pub fn map_last_reduce<F: FnOnce(Reduce) -> Reduce>(self, f: F) -> Self {
243        match self.reduce {
244            Some(reduce) => Map::new(
245                self.named_exprs,
246                self.filter,
247                self.order_by,
248                Some(reduce.map_last_reduce(f)),
249            ),
250            None => self,
251        }
252    }
253}
254
255impl fmt::Display for Map {
256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257        let Map {
258            named_exprs,
259            filter,
260            order_by,
261            reduce,
262        } = self;
263        write!(
264            f,
265            "{}\n{}",
266            named_exprs
267                .iter()
268                .map(|(n, e)| format!("{} -> {}", n, e.to_string().yellow()))
269                .chain(
270                    filter
271                        .into_iter()
272                        .map(|e| format!("WHERE -> {}", e.to_string().yellow()))
273                )
274                .chain(
275                    order_by
276                        .iter()
277                        .map(|(e, _)| format!("ORDER BY -> {}", e.to_string().yellow()))
278                )
279                .join("\n"),
280            reduce.as_deref().map_or(String::new(), ToString::to_string),
281        )
282    }
283}
284
285/// Concatenate two Reduce split into one
286impl And<Self> for Map {
287    type Product = Self;
288
289    fn and(self, other: Self) -> Self::Product {
290        match (self.reduce, other.reduce) {
291            (None, None) => Map::new(
292                self.named_exprs
293                    .into_iter()
294                    .chain(other.named_exprs)
295                    .collect(),
296                self.filter.into_iter().chain(other.filter).last(),
297                self.order_by.into_iter().chain(other.order_by).collect(),
298                None,
299            ),
300            (Some(s), Some(o)) => Map::new(
301                self.named_exprs
302                    .into_iter()
303                    .chain(other.named_exprs)
304                    .collect(),
305                self.filter.into_iter().chain(other.filter).last(),
306                self.order_by.into_iter().chain(other.order_by).collect(),
307                Some(s.and(*o)),
308            ),
309            (None, Some(o)) => {
310                let (reduce, named_exprs) = self.named_exprs.into_iter().fold(
311                    (*o, vec![]),
312                    |(reduce, mut named_exprs), (name, expr)| {
313                        let (reduce, expr) = reduce.and(expr);
314                        named_exprs.push((name, expr));
315                        (reduce, named_exprs)
316                    },
317                );
318                let (reduce, filter) =
319                    self.filter
320                        .into_iter()
321                        .fold((reduce, None), |(reduce, _), expr| {
322                            let (reduce, expr) = reduce.and(expr);
323                            (reduce, Some(expr))
324                        });
325                let (reduce, order_by) = self.order_by.into_iter().fold(
326                    (reduce, vec![]),
327                    |(reduce, mut order_by), (expr, asc)| {
328                        let (reduce, expr) = reduce.and(expr);
329                        order_by.push((expr, asc));
330                        (reduce, order_by)
331                    },
332                );
333                Map::new(
334                    named_exprs.into_iter().chain(other.named_exprs).collect(),
335                    filter.into_iter().chain(other.filter).last(),
336                    order_by.into_iter().chain(other.order_by).collect(),
337                    Some(reduce),
338                )
339            }
340            (Some(s), None) => {
341                let (reduce, named_exprs) = other.named_exprs.into_iter().fold(
342                    (*s, vec![]),
343                    |(reduce, mut named_exprs), (name, expr)| {
344                        let (reduce, expr) = reduce.and(expr);
345                        named_exprs.push((name, expr));
346                        (reduce, named_exprs)
347                    },
348                );
349                let (reduce, filter) =
350                    other
351                        .filter
352                        .into_iter()
353                        .fold((reduce, None), |(reduce, _), expr| {
354                            let (reduce, expr) = reduce.and(expr);
355                            (reduce, Some(expr))
356                        });
357                let (reduce, order_by) = other.order_by.into_iter().fold(
358                    (reduce, vec![]),
359                    |(reduce, mut order_by), (expr, asc)| {
360                        let (reduce, expr) = reduce.and(expr);
361                        order_by.push((expr, asc));
362                        (reduce, order_by)
363                    },
364                );
365                Map::new(
366                    self.named_exprs.into_iter().chain(named_exprs).collect(),
367                    self.filter.into_iter().chain(filter).last(),
368                    self.order_by.into_iter().chain(order_by).collect(),
369                    Some(reduce),
370                )
371            }
372        }
373    }
374}
375
376impl And<Reduce> for Map {
377    type Product = Self;
378
379    fn and(self, other: Reduce) -> Self::Product {
380        self.and(other.into_map())
381    }
382}
383/// Propagate expr columns into the Map and return the modified expression
384impl And<Expr> for Map {
385    type Product = (Map, Expr);
386
387    fn and(self, expr: Expr) -> Self::Product {
388        let Map {
389            named_exprs,
390            filter,
391            order_by,
392            reduce,
393        } = self;
394        // Add the expr to the next split if needed
395        let (reduce, expr) = if let Some(r) = reduce {
396            let (r, expr) = r.and(expr);
397            (Some(r), expr)
398        } else {
399            (None, expr)
400        };
401        // Collect sub-expressions
402        let patterns: Vec<(String, Expr)> = expr
403            .columns()
404            .into_iter()
405            .map(|c| {
406                let column = Expr::Column(c.clone());
407                (namer::name_from_content(FIELD, &column), column)
408            })
409            .chain(named_exprs.clone())
410            .unique()
411            .collect();
412        // Replace the sub-expressions
413        let (expr, matched) = expr.alias(patterns);
414        // Add matched sub-expressions
415        (
416            Map::new(
417                named_exprs.into_iter().chain(matched).collect(),
418                filter,
419                order_by,
420                reduce,
421            ),
422            expr,
423        )
424    }
425}
426
427#[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
428pub struct Reduce {
429    pub named_aggregates: Vec<(String, AggregateColumn)>,
430    pub group_by: Vec<Column>,
431    pub map: Option<Box<Map>>,
432}
433
434impl Reduce {
435    pub fn new(
436        named_aggregates: Vec<(String, AggregateColumn)>,
437        group_by: Vec<Column>,
438        map: Option<Map>,
439    ) -> Self {
440        Reduce {
441            named_aggregates: named_aggregates.into_iter().unique().collect(),
442            group_by: group_by.into_iter().unique().collect(),
443            map: map.map(Box::new),
444        }
445    }
446
447    pub fn named_aggregates(&self) -> &[(String, AggregateColumn)] {
448        &self.named_aggregates
449    }
450
451    pub fn group_by(&self) -> &[Column] {
452        &self.group_by
453    }
454
455    pub fn map(&self) -> Option<&Map> {
456        self.map.as_deref()
457    }
458
459    pub fn into_map(self) -> Map {
460        let Reduce {
461            named_aggregates,
462            group_by,
463            map,
464        } = self;
465        let (named_aliases, aliased_expr): (Vec<(String, Expr)>, Vec<(String, AggregateColumn)>) =
466            named_aggregates
467                .into_iter()
468                .map(|(name, aggregate)| {
469                    let alias = namer::name_from_content(FIELD, &aggregate);
470                    ((name, Expr::col(alias.clone())), (alias.clone(), aggregate))
471                })
472                .unzip();
473        // If the reduce is empty, remove it
474        if aliased_expr.is_empty() && group_by.is_empty() {
475            Map::new(named_aliases, None, vec![], None)
476        } else {
477            Map::new(
478                named_aliases,
479                None,
480                vec![],
481                Some(Reduce::new(aliased_expr, group_by, map.map(|m| *m))),
482            )
483        }
484    }
485
486    pub fn len(&self) -> usize {
487        1 + self.map().map_or(0, |m| m.len())
488    }
489
490    pub fn map_last<F: FnOnce(Split) -> Split>(self, f: F) -> Self {
491        match self.map {
492            Some(map) => Reduce::new(self.named_aggregates, self.group_by, Some(map.map_last(f))),
493            None => {
494                let split = f(self.clone().into());
495                if let Split::Reduce(reduce) = split {
496                    reduce
497                } else {
498                    self
499                }
500            }
501        }
502    }
503
504    pub fn map_last_map<F: FnOnce(Map) -> Map>(self, f: F) -> Self {
505        match self.map {
506            Some(map) => Reduce::new(
507                self.named_aggregates,
508                self.group_by,
509                Some(map.map_last_map(f)),
510            ),
511            None => self,
512        }
513    }
514
515    pub fn map_last_reduce<F: FnOnce(Reduce) -> Reduce>(self, f: F) -> Self {
516        match self.map {
517            Some(map) => match map.reduce {
518                Some(_) => Reduce::new(
519                    self.named_aggregates,
520                    self.group_by,
521                    Some(map.map_last_reduce(f)),
522                ),
523                None => f(Reduce::new(
524                    self.named_aggregates,
525                    self.group_by,
526                    Some(*map),
527                )),
528            },
529            None => f(self),
530        }
531    }
532}
533
534impl fmt::Display for Reduce {
535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536        let Reduce {
537            named_aggregates: named_exprs,
538            group_by,
539            map,
540        } = self;
541        write!(
542            f,
543            "{}\n{}",
544            named_exprs
545                .iter()
546                .map(|(n, e)| format!("{} -> {}", n, e.to_string().red()))
547                .chain(
548                    group_by
549                        .iter()
550                        .map(|e| format!("GROUP BY -> {}", e.to_string().red()))
551                )
552                .join("\n"),
553            map.as_deref().map_or(String::new(), ToString::to_string),
554        )
555    }
556}
557
558/// Concatenate two Reduce split into one
559impl And<Self> for Reduce {
560    type Product = Self;
561
562    fn and(self, other: Self) -> Self::Product {
563        match (self.map, other.map) {
564            (None, None) => Reduce::new(
565                self.named_aggregates
566                    .into_iter()
567                    .chain(other.named_aggregates)
568                    .collect(),
569                self.group_by.into_iter().chain(other.group_by).collect(),
570                None,
571            ),
572            (Some(s), Some(o)) => Reduce::new(
573                self.named_aggregates
574                    .into_iter()
575                    .chain(other.named_aggregates)
576                    .collect(),
577                self.group_by.into_iter().chain(other.group_by).collect(),
578                Some(s.and(*o)),
579            ),
580            (None, Some(o)) => {
581                let (map, named_aggregates) = self.named_aggregates.into_iter().fold(
582                    (*o, vec![]),
583                    |(map, mut named_aggregates), (name, aggregate)| {
584                        let (map, expr) = map.and(Expr::from(aggregate));
585                        named_aggregates.push((name, expr.try_into().unwrap()));
586                        (map, named_aggregates)
587                    },
588                );
589                let (map, group_by) =
590                    self.group_by
591                        .into_iter()
592                        .fold((map, vec![]), |(map, mut group_by), col| {
593                            let (map, col) = map.and(Expr::from(col));
594                            group_by.push(col.try_into().unwrap());
595                            (map, group_by)
596                        });
597                Reduce::new(
598                    named_aggregates
599                        .into_iter()
600                        .chain(other.named_aggregates)
601                        .collect(),
602                    group_by.into_iter().chain(other.group_by).collect(),
603                    Some(map),
604                )
605            }
606            (Some(s), None) => {
607                let (map, named_aggregates) = other.named_aggregates.into_iter().fold(
608                    (*s, vec![]),
609                    |(map, mut named_aggregates), (name, aggregate)| {
610                        let (map, expr) = map.and(Expr::from(aggregate));
611                        named_aggregates.push((name, expr.try_into().unwrap()));
612                        (map, named_aggregates)
613                    },
614                );
615                let (map, group_by) =
616                    other
617                        .group_by
618                        .into_iter()
619                        .fold((map, vec![]), |(map, mut group_by), col| {
620                            let (map, col) = map.and(Expr::from(col));
621                            group_by.push(col.try_into().unwrap());
622                            (map, group_by)
623                        });
624                Reduce::new(
625                    self.named_aggregates
626                        .into_iter()
627                        .chain(named_aggregates)
628                        .collect(),
629                    self.group_by.into_iter().chain(group_by).collect(),
630                    Some(map),
631                )
632            }
633        }
634    }
635}
636
637impl And<Map> for Reduce {
638    type Product = Map;
639
640    fn and(self, other: Map) -> Self::Product {
641        self.into_map().and(other)
642    }
643}
644
645/// Propagate expr columns into the Reduce and return the modified expression
646impl And<Expr> for Reduce {
647    type Product = (Reduce, Expr);
648
649    fn and(self, expr: Expr) -> Self::Product {
650        let Reduce {
651            named_aggregates,
652            group_by,
653            map,
654        } = self;
655        // Add the expr to the next split if needed
656        let (map, expr) = if let Some(m) = map {
657            let (m, expr) = m.and(expr);
658            (Some(m), expr)
659        } else {
660            (None, expr)
661        };
662        // Collect sub-expressions
663        let patterns: Vec<(String, Expr)> = expr
664            .columns()
665            .into_iter()
666            .map(|c| {
667                let column = Expr::Column(c.clone());
668                (namer::name_from_content(FIELD, &column), column)
669            })
670            .chain(
671                group_by
672                    .clone()
673                    .into_iter()
674                    .map(|col| (namer::name_from_content(FIELD, &col), Expr::Column(col))),
675            )
676            .unique()
677            .collect();
678        // Replace the sub-expressions
679        let (expr, matched) = expr.alias(patterns);
680        // Express matched sub-expressions as aggregates
681        let matched: Vec<_> = matched
682            .into_iter()
683            .map(|(n, e)| (n, AggregateColumn::try_from(e).unwrap())) // We know the expression is an Aggregate Column
684            .collect();
685        // Add matched sub-expressions
686        (
687            Reduce::new(
688                named_aggregates.into_iter().chain(matched).collect(),
689                group_by,
690                map,
691            ),
692            expr,
693        )
694    }
695}
696
697#[derive(Clone, Debug)]
698pub struct SplitVisitor(String);
699
700impl<'a> Visitor<'a, Split> for SplitVisitor {
701    fn column(&self, column: &'a Column) -> Split {
702        Map::new(
703            vec![(self.0.clone(), Expr::Column(column.clone()))],
704            None,
705            vec![],
706            None,
707        )
708        .into()
709    }
710
711    fn value(&self, value: &'a Value) -> Split {
712        Map::new(
713            vec![(self.0.clone(), Expr::Value(value.clone()))],
714            None,
715            vec![],
716            None,
717        )
718        .into()
719    }
720
721    fn function(&self, function: &'a function::Function, arguments: Vec<Split>) -> Split {
722        let arguments: Vec<Map> = arguments.into_iter().map(|s| s.into_map()).collect();
723        let named_exprs: Vec<(String, Expr)> = arguments
724            .iter()
725            .map(|m| m.named_exprs()[0].clone())
726            .collect();
727        let Map {
728            named_exprs: _,
729            filter,
730            order_by,
731            reduce,
732        } = Map::all(arguments);
733        Map::new(
734            vec![(
735                self.0.clone(),
736                Expr::Function(Function::new(
737                    function.clone(),
738                    named_exprs
739                        .into_iter()
740                        .filter_map(|(n, e)| (n == self.0).then(|| Arc::new(e)))
741                        .collect(),
742                )),
743            )],
744            filter,
745            order_by,
746            reduce.map(|r| *r),
747        )
748        .into()
749    }
750
751    fn aggregate(&self, aggregate: &'a aggregate::Aggregate, argument: Split) -> Split {
752        argument.into_reduce(aggregate.clone()).into()
753    }
754
755    fn structured(&self, fields: Vec<(Identifier, Split)>) -> Split {
756        let (identifiers, fields): (Vec<Identifier>, Vec<Split>) = fields.into_iter().unzip();
757        let Map {
758            named_exprs,
759            filter,
760            order_by,
761            reduce,
762        } = Split::all(fields).into_map();
763        Map::new(
764            vec![(
765                self.0.clone(),
766                Expr::Struct(
767                    identifiers
768                        .into_iter()
769                        .zip(
770                            named_exprs
771                                .into_iter()
772                                .filter_map(|(n, e)| (n == self.0).then(|| Arc::new(e))),
773                        )
774                        .collect(),
775                ),
776            )],
777            filter,
778            order_by,
779            reduce.map(|r| *r),
780        )
781        .into()
782    }
783}
784
785// Builds a Split out of a named Expr
786impl<S: Into<String>> From<(S, Expr)> for Split {
787    fn from((name, expr): (S, Expr)) -> Self {
788        expr.accept(SplitVisitor(name.into()))
789    }
790}
791
792impl<S: Into<String>> FromIterator<(S, Expr)> for Split {
793    fn from_iter<T: IntoIterator<Item = (S, Expr)>>(iter: T) -> Self {
794        Split::all(iter.into_iter().map_into())
795    }
796}
797
798#[cfg(test)]
799mod tests {
800    use super::*;
801
802    #[test]
803    fn test_map() {
804        let map = Map::new(
805            vec![
806                ("a".into(), expr!(cos(x + y))),
807                ("b".into(), expr!(sin(x - y))),
808            ],
809            None,
810            vec![],
811            None,
812        );
813        println!("map = {map}");
814        // Extend the map
815        let map = map.and(Split::filter(expr!(gt(x, 2))));
816        println!("Extended map = {map}");
817        assert_eq!(map.len(), 1);
818    }
819
820    #[test]
821    fn test_reduce() {
822        let reduce = Reduce::new(
823            vec![
824                ("a".into(), expr!(count(x)).try_into().unwrap()),
825                ("b".into(), expr!(sum(y)).try_into().unwrap()),
826            ],
827            vec![],
828            None,
829        );
830        println!("reduce = {reduce}");
831
832        let reduce = reduce.and(Reduce::new(vec![], vec!["z".into()], None));
833        println!("reduce and group by = {}", reduce);
834        assert_eq!(reduce.len(), 1);
835        let map = reduce.clone().into_map();
836        println!("reduce into map = {}", map);
837        assert_eq!(map.len(), 2);
838    }
839
840    #[test]
841    fn test_and_split() {
842        let a = Split::default();
843        println!("a = {a}");
844        println!("a = {a:?}");
845        let b = Split::from(("b", expr!(exp(a))));
846        println!("b = {b}");
847        println!("b = {b:?}");
848        let c = a.and(b);
849        println!("a & b = {}", c);
850        assert_eq!(c.len(), 1);
851    }
852
853    #[test]
854    fn test_split_merge() {
855        let u = Split::from(("u", expr!(sum(cos(x)))));
856        println!("u = {u}");
857        let v = Split::from(("v", expr!(sin(y))));
858        println!("v = {v}");
859        let w = u.and(v);
860        println!("u & v = {}", w);
861        assert_eq!(w.len(), 3);
862    }
863
864    #[test]
865    fn test_split_merge_all() {
866        let u = Split::from(("u", expr!(1)));
867        println!("u = {u}");
868        let v = Split::from(("v", expr!(y)));
869        println!("v = {v}");
870        let w = Split::filter(expr!(lt(x, 5))).into();
871        println!("w = {w}");
872        let fact: Split = Factor::all([u, v, w]);
873        println!("u & v & w = {fact}");
874        if let Split::Map(m) = fact {
875            assert!(m.reduce == None)
876        }
877    }
878
879    #[test]
880    fn test_plus() {
881        println!(
882            "sum = {}",
883            Split::from(("a", expr!(1 + sum(x)))).and(Split::from(("b", expr!(count(y)))))
884        );
885    }
886
887    #[test]
888    fn test_and_expr() {
889        let s = Split::from(("a", expr!(1 + sum(x)))).and(Split::from(("b", expr!(count(1 + y)))));
890        let e = expr!(x);
891        println!("expr = {}", e);
892        if let Split::Map(m) = s {
893            let (m, e) = m.and(e);
894            println!("replaced split = {}", m);
895            println!("replaced expr = {}", e);
896        }
897    }
898
899    #[test]
900    fn test_reduce_and_expr() {
901        let reduce = Reduce::default();
902        println!("reduce = {}", reduce);
903        let (reduce, expr) = reduce.and(expr!(sum(1 + a)));
904        println!("reduce = {}, expr = {}", reduce, expr);
905    }
906
907    #[test]
908    fn test_reduce_and_where() {
909        let reduce = Reduce::new(
910            vec![
911                ("a".into(), expr!(count(x)).try_into().unwrap()),
912                ("b".into(), expr!(sum(y)).try_into().unwrap()),
913            ],
914            vec![],
915            None,
916        );
917        println!("reduce = {}", reduce);
918        let filter: Split = Split::filter(expr!(lt(x, 5)))
919            .into_reduce(aggregate::Aggregate::First)
920            .into();
921        let split: Split = reduce.into();
922        let split = split.and(filter);
923        println!("split = {}", split);
924    }
925
926    #[test]
927    fn test_split_map_reduce_map_expr() {
928        let split = Split::from_iter([
929            ("a", expr!(1 + sum(x))),
930            ("b", expr!(count(1 + y))),
931            ("c", expr!(c)),
932        ]);
933        println!("split = {split}");
934    }
935
936    #[test]
937    fn test_split_map_reduce_map_group_by_expr() {
938        let split = Split::from(("b", expr!(2 * count(1 + y))));
939        let split = split.and(Split::group_by(expr!(x - y)).into());
940        let split = split.and(Split::from(("a", expr!(x - y))));
941        println!("split = {split}");
942    }
943}