gitql_engine/
engine_ordering.rs1use std::cmp::Ordering;
2use std::collections::HashMap;
3
4use gitql_ast::statement::NullsOrderPolicy;
5use gitql_ast::statement::OrderByStatement;
6use gitql_ast::statement::SortingOrder;
7use gitql_core::environment::Environment;
8use gitql_core::object::GitQLObject;
9use gitql_core::object::Group;
10use gitql_core::values::null::NullValue;
11use gitql_core::values::Value;
12
13use crate::engine_evaluator::evaluate_expression;
14
15pub(crate) fn execute_order_by_statement(
16 env: &mut Environment,
17 statement: &OrderByStatement,
18 gitql_object: &mut GitQLObject,
19 group_index: usize,
20) -> Result<(), String> {
21 if gitql_object.is_empty() || group_index >= gitql_object.len() {
22 return Ok(());
23 }
24
25 let main_group: &mut Group = &mut gitql_object.groups[group_index];
26 if main_group.is_empty() {
27 return Ok(());
28 }
29
30 let rows_len = main_group.rows.len();
31 let arguments_len = statement.arguments.len();
32 let main_group_rows = &main_group.rows;
33 let titles = &gitql_object.titles;
34
35 let mut eval_map: HashMap<usize, Vec<Box<dyn Value>>> = HashMap::with_capacity(rows_len);
36
37 for row in main_group_rows.iter() {
38 let row_addr = row.values.as_ptr() as usize;
39 let mut arguments_values: Vec<Box<dyn Value>> = Vec::with_capacity(arguments_len);
40 for argument in statement.arguments.iter() {
41 if argument.is_const() {
43 arguments_values.push(Box::new(NullValue));
44 continue;
45 }
46
47 let value = &evaluate_expression(env, argument, titles, &row.values)?;
48 arguments_values.push(value.to_owned());
49 }
50
51 eval_map.insert(row_addr, arguments_values);
52 }
53
54 main_group.rows.sort_by(|a, b| {
55 for arg_index in 0..arguments_len {
56 let argument = &statement.arguments[arg_index];
57 if argument.is_const() {
59 continue;
60 }
61
62 let a_addr = a.values.as_ptr() as usize;
64 let b_addr = b.values.as_ptr() as usize;
65
66 let a_value = &eval_map.get(&a_addr).unwrap()[arg_index];
68 let b_value = &eval_map.get(&b_addr).unwrap()[arg_index];
69
70 let null_ordering_policy = &statement.nulls_order_policies[arg_index];
71 if a_value.is_null() {
72 return if null_ordering_policy.eq(&NullsOrderPolicy::NullsFirst) {
73 Ordering::Less
74 } else {
75 Ordering::Greater
76 };
77 }
78
79 if b_value.is_null() {
80 return if null_ordering_policy.eq(&NullsOrderPolicy::NullsFirst) {
81 Ordering::Greater
82 } else {
83 Ordering::Less
84 };
85 }
86
87 if let Some(order) = a_value.compare(b_value) {
89 if order == Ordering::Equal {
90 continue;
91 }
92
93 return if statement.sorting_orders[arg_index] == SortingOrder::Descending {
95 order.reverse()
96 } else {
97 order
98 };
99 }
100 }
101
102 Ordering::Equal
103 });
104
105 Ok(())
106}