siderite_orm/expr/
window.rs1#![allow(clippy::new_ret_no_self)]
11
12use super::{Aggregate, Expr};
13use crate::plan::OrderExpr;
14
15#[derive(Debug, Clone, PartialEq)]
17pub enum WindowFunc {
18 RowNumber,
20 Rank,
22 DenseRank,
24 PercentRank,
26 CumeDist,
28 Ntile(u32),
30 Lag {
32 expr: Box<Expr>,
34 offset: u32,
36 default: Option<Box<Expr>>,
38 },
39 Lead {
41 expr: Box<Expr>,
43 offset: u32,
45 default: Option<Box<Expr>>,
47 },
48 FirstValue(Box<Expr>),
50 LastValue(Box<Expr>),
52 Aggregate(Aggregate),
54}
55
56#[derive(Debug, Clone, PartialEq)]
58pub struct Window {
59 pub func: WindowFunc,
61 pub partition_by: Vec<Expr>,
63 pub order_by: Vec<OrderExpr>,
65}
66
67impl Window {
68 pub fn over(func: WindowFunc) -> Self {
70 Self {
71 func,
72 partition_by: Vec::new(),
73 order_by: Vec::new(),
74 }
75 }
76
77 #[must_use]
79 pub fn partition_by<E: Into<Expr>>(mut self, exprs: impl IntoIterator<Item = E>) -> Self {
80 self.partition_by = exprs.into_iter().map(Into::into).collect();
81 self
82 }
83
84 #[must_use]
86 pub fn order_by(mut self, terms: impl IntoIterator<Item = OrderExpr>) -> Self {
87 self.order_by = terms.into_iter().collect();
88 self
89 }
90
91 pub(super) fn children(&self) -> Vec<&Expr> {
94 let func: Vec<&Expr> = match &self.func {
95 WindowFunc::Lag { expr, default, .. } | WindowFunc::Lead { expr, default, .. } => {
96 std::iter::once(&**expr).chain(default.as_deref()).collect()
97 }
98 WindowFunc::FirstValue(expr) | WindowFunc::LastValue(expr) => vec![expr],
99 WindowFunc::Aggregate(agg) => agg.children(),
100 _ => Vec::new(),
101 };
102 func.into_iter()
103 .chain(&self.partition_by)
104 .chain(self.order_by.iter().map(|o| &o.expr))
105 .collect()
106 }
107
108 pub(super) fn children_mut(&mut self) -> Vec<&mut Expr> {
110 let func: Vec<&mut Expr> = match &mut self.func {
111 WindowFunc::Lag { expr, default, .. } | WindowFunc::Lead { expr, default, .. } => {
112 std::iter::once(&mut **expr)
113 .chain(default.as_deref_mut())
114 .collect()
115 }
116 WindowFunc::FirstValue(expr) | WindowFunc::LastValue(expr) => vec![expr],
117 WindowFunc::Aggregate(agg) => agg.children_mut(),
118 _ => Vec::new(),
119 };
120 func.into_iter()
121 .chain(&mut self.partition_by)
122 .chain(self.order_by.iter_mut().map(|o| &mut o.expr))
123 .collect()
124 }
125}
126
127impl From<Window> for Expr {
128 fn from(window: Window) -> Self {
129 Expr::Window(Box::new(window))
130 }
131}
132
133macro_rules! window_fn {
134 ($($(#[$doc:meta])* $name:ident => $func:ident;)*) => {$(
135 $(#[$doc])*
136 #[derive(Debug, Clone, Copy)]
137 pub struct $name;
138
139 impl $name {
140 pub fn new() -> Window {
142 Window::over(WindowFunc::$func)
143 }
144 }
145 )*};
146}
147
148window_fn! {
149 RowNumber => RowNumber;
151 Rank => Rank;
153 DenseRank => DenseRank;
155 PercentRank => PercentRank;
157 CumeDist => CumeDist;
159}
160
161#[derive(Debug, Clone, Copy)]
163pub struct Ntile;
164
165impl Ntile {
166 pub fn new(buckets: u32) -> Window {
168 Window::over(WindowFunc::Ntile(buckets))
169 }
170}
171
172macro_rules! shift_fn {
173 ($($(#[$doc:meta])* $name:ident => $func:ident;)*) => {$(
174 $(#[$doc])*
175 #[derive(Debug, Clone, Copy)]
176 pub struct $name;
177
178 impl $name {
179 pub fn new(expr: impl Into<Expr>, offset: u32) -> Window {
181 Window::over(WindowFunc::$func {
182 expr: Box::new(expr.into()),
183 offset,
184 default: None,
185 })
186 }
187
188 pub fn or_default(
190 expr: impl Into<Expr>,
191 offset: u32,
192 default: impl Into<Expr>,
193 ) -> Window {
194 Window::over(WindowFunc::$func {
195 expr: Box::new(expr.into()),
196 offset,
197 default: Some(Box::new(default.into())),
198 })
199 }
200 }
201 )*};
202}
203
204shift_fn! {
205 Lag => Lag;
207 Lead => Lead;
209}
210
211macro_rules! value_fn {
212 ($($(#[$doc:meta])* $name:ident => $func:ident;)*) => {$(
213 $(#[$doc])*
214 #[derive(Debug, Clone, Copy)]
215 pub struct $name;
216
217 impl $name {
218 pub fn new(expr: impl Into<Expr>) -> Window {
220 Window::over(WindowFunc::$func(Box::new(expr.into())))
221 }
222 }
223 )*};
224}
225
226value_fn! {
227 FirstValue => FirstValue;
229 LastValue => LastValue;
231}