1use super::Expr;
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum WindowFunctionType {
8 RowNumber,
10 Rank,
12 DenseRank,
14 NTile(u32),
16 Lag {
18 expr: Box<Expr>,
19 offset: i64,
20 default: Option<Box<Expr>>,
21 },
22 Lead {
24 expr: Box<Expr>,
25 offset: i64,
26 default: Option<Box<Expr>>,
27 },
28 FirstValue(Box<Expr>),
30 LastValue(Box<Expr>),
32 NthValue(Box<Expr>, u32),
34 Sum(Box<Expr>),
36 Avg(Box<Expr>),
37 Count(Option<Box<Expr>>),
38 Min(Box<Expr>),
39 Max(Box<Expr>),
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum FrameUnit {
45 Rows,
47 Range,
49 Groups,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum FrameBound {
56 UnboundedPreceding,
58 Preceding(u64),
60 CurrentRow,
62 Following(u64),
64 UnboundedFollowing,
66}
67
68#[derive(Debug, Clone, PartialEq)]
70pub struct WindowFrame {
71 pub unit: FrameUnit,
73 pub start: FrameBound,
75 pub end: FrameBound,
77}
78
79impl Default for WindowFrame {
80 fn default() -> Self {
81 WindowFrame {
83 unit: FrameUnit::Range,
84 start: FrameBound::UnboundedPreceding,
85 end: FrameBound::CurrentRow,
86 }
87 }
88}
89
90impl WindowFrame {
91 pub fn unbounded() -> Self {
93 WindowFrame {
94 unit: FrameUnit::Rows,
95 start: FrameBound::UnboundedPreceding,
96 end: FrameBound::UnboundedFollowing,
97 }
98 }
99
100 pub fn to_current_row() -> Self {
102 WindowFrame {
103 unit: FrameUnit::Rows,
104 start: FrameBound::UnboundedPreceding,
105 end: FrameBound::CurrentRow,
106 }
107 }
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub enum WindowSortOrder {
113 Asc,
114 Desc,
115}
116
117#[derive(Debug, Clone, PartialEq)]
119pub struct WindowOrderByExpr {
120 pub expr: Expr,
121 pub order: WindowSortOrder,
122 pub nulls_first: Option<bool>,
123}
124
125#[derive(Debug, Clone, PartialEq)]
127pub struct WindowFunction {
128 pub function: WindowFunctionType,
130 pub partition_by: Vec<Expr>,
132 pub order_by: Vec<WindowOrderByExpr>,
134 pub frame: Option<WindowFrame>,
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_window_frame_default() {
144 let frame = WindowFrame::default();
145 assert_eq!(frame.unit, FrameUnit::Range);
146 assert_eq!(frame.start, FrameBound::UnboundedPreceding);
147 assert_eq!(frame.end, FrameBound::CurrentRow);
148 }
149
150 #[test]
151 fn test_window_frame_unbounded() {
152 let frame = WindowFrame::unbounded();
153 assert_eq!(frame.unit, FrameUnit::Rows);
154 assert_eq!(frame.start, FrameBound::UnboundedPreceding);
155 assert_eq!(frame.end, FrameBound::UnboundedFollowing);
156 }
157
158 #[test]
159 fn test_window_frame_to_current_row() {
160 let frame = WindowFrame::to_current_row();
161 assert_eq!(frame.unit, FrameUnit::Rows);
162 assert_eq!(frame.start, FrameBound::UnboundedPreceding);
163 assert_eq!(frame.end, FrameBound::CurrentRow);
164 }
165
166 #[test]
167 fn test_window_function_type_clone() {
168 let func = WindowFunctionType::RowNumber;
169 let cloned = func.clone();
170 assert_eq!(func, cloned);
171 }
172
173 #[test]
174 fn test_window_frame_clone() {
175 let frame = WindowFrame {
176 unit: FrameUnit::Rows,
177 start: FrameBound::Preceding(5),
178 end: FrameBound::Following(5),
179 };
180 let cloned = frame.clone();
181 assert_eq!(frame, cloned);
182 }
183
184 #[test]
185 fn test_window_order_by_expr() {
186 let order = WindowOrderByExpr {
187 expr: Expr::Column {
188 table: None,
189 name: "age".to_string(),
190 index: None,
191 },
192 order: WindowSortOrder::Desc,
193 nulls_first: None,
194 };
195 assert_eq!(order.order, WindowSortOrder::Desc);
196 assert_eq!(order.nulls_first, None);
197 }
198
199 #[test]
200 fn test_window_function_complete() {
201 let func = WindowFunction {
202 function: WindowFunctionType::Rank,
203 partition_by: vec![Expr::Column {
204 table: None,
205 name: "department".to_string(),
206 index: None,
207 }],
208 order_by: vec![WindowOrderByExpr {
209 expr: Expr::Column {
210 table: None,
211 name: "salary".to_string(),
212 index: None,
213 },
214 order: WindowSortOrder::Desc,
215 nulls_first: None,
216 }],
217 frame: None,
218 };
219
220 assert!(matches!(func.function, WindowFunctionType::Rank));
221 assert_eq!(func.partition_by.len(), 1);
222 assert_eq!(func.order_by.len(), 1);
223 assert!(func.frame.is_none());
224 }
225
226 #[test]
227 fn test_frame_unit_variants() {
228 let rows = FrameUnit::Rows;
229 let range = FrameUnit::Range;
230 let groups = FrameUnit::Groups;
231
232 assert_ne!(rows, range);
233 assert_ne!(range, groups);
234 assert_ne!(rows, groups);
235 }
236
237 #[test]
238 fn test_frame_bound_variants() {
239 let unbounded_preceding = FrameBound::UnboundedPreceding;
240 let preceding = FrameBound::Preceding(5);
241 let current_row = FrameBound::CurrentRow;
242 let following = FrameBound::Following(5);
243 let unbounded_following = FrameBound::UnboundedFollowing;
244
245 assert_ne!(unbounded_preceding, current_row);
246 assert_ne!(preceding, following);
247 assert_ne!(current_row, unbounded_following);
248 }
249}