gitql_engine/
engine_group.rs1use std::collections::hash_map::Entry::Vacant;
2use std::collections::HashMap;
3use std::hash::DefaultHasher;
4use std::hash::Hash;
5use std::hash::Hasher;
6
7use gitql_ast::statement::GroupByStatement;
8use gitql_core::combinations_generator::generate_list_of_all_combinations;
9use gitql_core::environment::Environment;
10use gitql_core::object::GitQLObject;
11use gitql_core::object::Group;
12
13use crate::engine_evaluator::evaluate_expression;
14
15pub(crate) fn execute_group_by_statement(
16 env: &mut Environment,
17 statement: &GroupByStatement,
18 gitql_object: &mut GitQLObject,
19) -> Result<(), String> {
20 if gitql_object.is_empty() {
21 return Ok(());
22 }
23
24 let main_group = gitql_object.groups.remove(0);
25 if main_group.is_empty() {
26 return Ok(());
27 }
28
29 let mut groups_map: HashMap<u64, usize> = HashMap::new();
31
32 let mut next_group_index = 0;
34 let values_count = statement.values.len();
35
36 let is_roll_up_enabled = statement.has_with_roll_up;
37 let indexes_combinations = if is_roll_up_enabled {
38 generate_list_of_all_combinations(values_count)
39 } else {
40 vec![(0..values_count).collect()]
41 };
42
43 for row in main_group.rows.iter() {
45 for indexes in indexes_combinations.iter() {
47 let mut row_values: Vec<String> = Vec::with_capacity(indexes.len());
48 for index in indexes {
49 let value = evaluate_expression(
50 env,
51 &statement.values[*index],
52 &gitql_object.titles,
53 &row.values,
54 )?;
55 row_values.push(value.literal());
56 }
57
58 let mut hasher = DefaultHasher::new();
60 row_values.hash(&mut hasher);
61 let values_hash = hasher.finish();
62
63 if let Vacant(e) = groups_map.entry(values_hash) {
65 e.insert(next_group_index);
66 next_group_index += 1;
67 gitql_object.groups.push(Group {
68 rows: vec![row.clone()],
69 });
70 continue;
71 }
72
73 let index = *groups_map.get(&values_hash).unwrap();
75 let target_group = &mut gitql_object.groups[index];
76 target_group.rows.push(row.clone());
77 }
78 }
79
80 if is_roll_up_enabled && indexes_combinations.len() == 1 && indexes_combinations[0].len() == 1 {
84 gitql_object.groups.push(main_group);
85 }
86
87 Ok(())
88}