gitql_engine/
engine_window_functions.rs1use std::collections::HashMap;
2
3use gitql_ast::statement::GroupByStatement;
4use gitql_ast::statement::WindowDefinition;
5use gitql_ast::statement::WindowFunctionKind;
6use gitql_ast::statement::WindowFunctionsStatement;
7use gitql_ast::statement::WindowValue;
8use gitql_core::environment::Environment;
9use gitql_core::object::GitQLObject;
10
11use crate::engine_evaluator::evaluate_expression;
12use crate::engine_executor::resolve_actual_column_name;
13use crate::engine_group::execute_group_by_statement;
14use crate::engine_ordering::execute_order_by_statement;
15
16pub(crate) fn execute_window_functions_statement(
17 env: &mut Environment,
18 statement: &WindowFunctionsStatement,
19 gitql_object: &mut GitQLObject,
20 alias_table: &HashMap<String, String>,
21) -> Result<(), String> {
22 if gitql_object.is_empty() {
23 return Ok(());
24 }
25
26 if gitql_object.len() > 1 {
27 gitql_object.flat()
28 }
29
30 let main_group = &mut gitql_object.groups[0];
31 let rows_len = main_group.rows.len();
32
33 for (result_column_name, window_value) in statement.window_values.iter() {
35 if let WindowValue::Function(function) = window_value {
36 let column_name = resolve_actual_column_name(alias_table, result_column_name);
37 let column_index = gitql_object
38 .titles
39 .iter()
40 .position(|r| r.eq(&column_name))
41 .unwrap();
42
43 apply_window_definition_on_gitql_object(
45 env,
46 gitql_object,
47 &function.window_definition,
48 )?;
49
50 let args_len = function.arguments.len();
52 for frame_index in 0..gitql_object.len() {
53 let mut frame_values = Vec::with_capacity(rows_len);
54 let frame = &mut gitql_object.groups[frame_index];
55 for row in frame.rows.iter_mut() {
56 let mut row_selected_values = Vec::with_capacity(args_len);
57 for argument in function.arguments.iter() {
58 let argument =
59 evaluate_expression(env, argument, &gitql_object.titles, &row.values)?;
60 row_selected_values.push(argument);
61 }
62
63 frame_values.push(row_selected_values);
64 }
65
66 if frame_values.is_empty() {
67 continue;
68 }
69
70 match function.kind {
72 WindowFunctionKind::AggregatedWindowFunction => {
73 let aggregation_function =
74 env.aggregation_function(&function.function_name).unwrap();
75 let aggregated_value = aggregation_function(&frame_values);
76 for row in frame.rows.iter_mut() {
77 row.values[column_index] = aggregated_value.clone();
78 }
79 }
80 WindowFunctionKind::PureWindowFunction => {
81 let window_function = env.window_function(&function.function_name).unwrap();
82 let window_values = window_function(&frame_values);
83 for (index, value) in window_values.iter().enumerate() {
84 frame.rows[index].values[column_index] = value.clone();
85 }
86 }
87 };
88 }
89 }
90 gitql_object.flat();
91 }
92
93 for (result_column_name, window_value) in statement.window_values.iter() {
95 if let WindowValue::Expression(expression) = window_value {
96 let column_name = resolve_actual_column_name(alias_table, result_column_name);
97 let column_index = gitql_object
98 .titles
99 .iter()
100 .position(|r| r.eq(&column_name))
101 .unwrap();
102
103 for frame_index in 0..gitql_object.len() {
104 let frame = &mut gitql_object.groups[frame_index];
105 for row in frame.rows.iter_mut() {
106 let window_value =
107 evaluate_expression(env, expression, &gitql_object.titles, &row.values)?;
108 row.values[column_index] = window_value.clone();
109 }
110 }
111 }
112 gitql_object.flat();
113 }
114
115 Ok(())
116}
117
118fn apply_window_definition_on_gitql_object(
119 env: &mut Environment,
120 gitql_object: &mut GitQLObject,
121 window_definition: &WindowDefinition,
122) -> Result<(), String> {
123 if let Some(partition_by) = &window_definition.partitioning_clause {
125 let group_by = GroupByStatement {
126 values: vec![partition_by.expr.clone()],
127 has_with_roll_up: false,
128 };
129 execute_group_by_statement(env, &group_by, gitql_object)?;
130 }
131
132 if let Some(window_ordering) = &window_definition.ordering_clause {
134 for index in 0..gitql_object.len() {
135 execute_order_by_statement(env, &window_ordering.order_by, gitql_object, index)?;
136 }
137 }
138
139 Ok(())
141}