polars_plan/dsl/arity.rs
1use super::*;
2
3/// Utility struct for the `when-then-otherwise` expression.
4///
5/// Represents the state of the expression after [when] is called.
6///
7/// In this state, `then` must be called to continue to finish the expression.
8#[derive(Clone)]
9pub struct When {
10 condition: Expr,
11}
12
13/// Utility struct for the `when-then-otherwise` expression.
14///
15/// Represents the state of the expression after `when(...).then(...)` is called.
16#[derive(Clone)]
17pub struct Then {
18 condition: Expr,
19 statement: Expr,
20}
21
22/// Utility struct for the `when-then-otherwise` expression.
23///
24/// Represents the state of the expression after an additional `when` is called.
25///
26/// In this state, `then` must be called to continue to finish the expression.
27#[derive(Clone)]
28pub struct ChainedWhen {
29 conditions: Vec<Expr>,
30 statements: Vec<Expr>,
31}
32
33/// Utility struct for the `when-then-otherwise` expression.
34///
35/// Represents the state of the expression after an additional `then` is called.
36#[derive(Clone)]
37pub struct ChainedThen {
38 conditions: Vec<Expr>,
39 statements: Vec<Expr>,
40}
41
42impl When {
43 /// Add a condition to the `when-then-otherwise` expression.
44 pub fn then<E: Into<Expr>>(self, expr: E) -> Then {
45 Then {
46 condition: self.condition,
47 statement: expr.into(),
48 }
49 }
50}
51
52impl Then {
53 /// Attach a statement to the corresponding condition.
54 pub fn when<E: Into<Expr>>(self, condition: E) -> ChainedWhen {
55 ChainedWhen {
56 conditions: vec![self.condition, condition.into()],
57 statements: vec![self.statement],
58 }
59 }
60
61 /// Define a default for the `when-then-otherwise` expression.
62 pub fn otherwise<E: Into<Expr>>(self, statement: E) -> Expr {
63 ternary_expr(self.condition, self.statement, statement.into())
64 }
65}
66
67impl ChainedWhen {
68 pub fn then<E: Into<Expr>>(mut self, statement: E) -> ChainedThen {
69 self.statements.push(statement.into());
70 ChainedThen {
71 conditions: self.conditions,
72 statements: self.statements,
73 }
74 }
75}
76
77impl ChainedThen {
78 /// Add another condition to the `when-then-otherwise` expression.
79 pub fn when<E: Into<Expr>>(mut self, condition: E) -> ChainedWhen {
80 self.conditions.push(condition.into());
81
82 ChainedWhen {
83 conditions: self.conditions,
84 statements: self.statements,
85 }
86 }
87
88 /// Define a default for the `when-then-otherwise` expression.
89 pub fn otherwise<E: Into<Expr>>(self, expr: E) -> Expr {
90 // we iterate the preds/ exprs last in first out
91 // and nest them.
92 //
93 // // this expr:
94 // when((col('x') == 'a')).then(1)
95 // .when(col('x') == 'b').then(2)
96 // .when(col('x') == 'c').then(3)
97 // .otherwise(4)
98 //
99 // needs to become:
100 // when((col('x') == 'a')).then(1) -
101 // .otherwise( |
102 // when(col('x') == 'b').then(2) - |
103 // .otherwise( | |
104 // pl.when(col('x') == 'c').then(3) | |
105 // .otherwise(4) | inner | outer
106 // ) | |
107 // ) _| _|
108 //
109 // by iterating LIFO we first create
110 // `inner` and then assign that to `otherwise`,
111 // which will be used in the next layer `outer`
112 //
113
114 let conditions_iter = self.conditions.into_iter().rev();
115 let mut statements_iter = self.statements.into_iter().rev();
116
117 let mut otherwise = expr.into();
118
119 for e in conditions_iter {
120 otherwise = ternary_expr(
121 e,
122 statements_iter
123 .next()
124 .expect("expr expected, did you call when().then().otherwise?"),
125 otherwise,
126 );
127 }
128
129 otherwise
130 }
131}
132
133/// Start a `when-then-otherwise` expression.
134pub fn when<E: Into<Expr>>(condition: E) -> When {
135 When {
136 condition: condition.into(),
137 }
138}
139
140pub fn ternary_expr(predicate: Expr, truthy: Expr, falsy: Expr) -> Expr {
141 Expr::Ternary {
142 predicate: Arc::new(predicate),
143 truthy: Arc::new(truthy),
144 falsy: Arc::new(falsy),
145 }
146}
147
148/// Compute `op(l, r)` (or equivalently `l op r`). `l` and `r` must have types compatible with the Operator.
149pub fn binary_expr(l: Expr, op: Operator, r: Expr) -> Expr {
150 Expr::BinaryExpr {
151 left: Arc::new(l),
152 op,
153 right: Arc::new(r),
154 }
155}