Skip to main content

cynos_query/executor/
sort.rs

1//! Sort executor.
2
3use crate::ast::SortOrder;
4use crate::executor::{Relation, RelationEntry};
5use alloc::vec::Vec;
6use core::cmp::Ordering;
7
8/// Sort executor - sorts rows by specified columns.
9pub struct SortExecutor {
10    /// Column indices and sort orders.
11    order_by: Vec<(usize, SortOrder)>,
12}
13
14impl SortExecutor {
15    /// Creates a new sort executor.
16    pub fn new(order_by: Vec<(usize, SortOrder)>) -> Self {
17        Self { order_by }
18    }
19
20    /// Executes the sort on the input relation.
21    pub fn execute(&self, mut input: Relation) -> Relation {
22        input.entries.sort_by(|a, b| self.compare_entries(a, b));
23        input
24    }
25
26    fn compare_entries(&self, a: &RelationEntry, b: &RelationEntry) -> Ordering {
27        for (col_idx, order) in &self.order_by {
28            let a_val = a.get_field(*col_idx);
29            let b_val = b.get_field(*col_idx);
30
31            let cmp = match (a_val, b_val) {
32                (Some(av), Some(bv)) => av.cmp(bv),
33                (None, Some(_)) => Ordering::Less,
34                (Some(_), None) => Ordering::Greater,
35                (None, None) => Ordering::Equal,
36            };
37
38            if cmp != Ordering::Equal {
39                return match order {
40                    SortOrder::Asc => cmp,
41                    SortOrder::Desc => cmp.reverse(),
42                };
43            }
44        }
45        Ordering::Equal
46    }
47}
48
49/// Sorts a relation by a key function.
50#[allow(dead_code)]
51pub fn sort_relation<K, F>(mut input: Relation, key_fn: F) -> Relation
52where
53    K: Ord,
54    F: Fn(&RelationEntry) -> K,
55{
56    input.entries.sort_by(|a, b| key_fn(a).cmp(&key_fn(b)));
57    input
58}
59
60/// Sorts a relation by a comparison function.
61#[allow(dead_code)]
62pub fn sort_relation_by<F>(mut input: Relation, compare: F) -> Relation
63where
64    F: Fn(&RelationEntry, &RelationEntry) -> Ordering,
65{
66    input.entries.sort_by(compare);
67    input
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use alloc::rc::Rc;
74    use alloc::vec;
75    use cynos_core::{Row, Value};
76
77    #[test]
78    fn test_sort_executor_asc() {
79        let rows = vec![
80            Rc::new(Row::new(1, vec![Value::Int64(30)])),
81            Rc::new(Row::new(2, vec![Value::Int64(10)])),
82            Rc::new(Row::new(3, vec![Value::Int64(20)])),
83        ];
84        let input = Relation::from_rows(rows, vec!["t".into()]);
85
86        let executor = SortExecutor::new(vec![(0, SortOrder::Asc)]);
87        let result = executor.execute(input);
88
89        assert_eq!(result.entries[0].get_field(0), Some(&Value::Int64(10)));
90        assert_eq!(result.entries[1].get_field(0), Some(&Value::Int64(20)));
91        assert_eq!(result.entries[2].get_field(0), Some(&Value::Int64(30)));
92    }
93
94    #[test]
95    fn test_sort_executor_desc() {
96        let rows = vec![
97            Rc::new(Row::new(1, vec![Value::Int64(10)])),
98            Rc::new(Row::new(2, vec![Value::Int64(30)])),
99            Rc::new(Row::new(3, vec![Value::Int64(20)])),
100        ];
101        let input = Relation::from_rows(rows, vec!["t".into()]);
102
103        let executor = SortExecutor::new(vec![(0, SortOrder::Desc)]);
104        let result = executor.execute(input);
105
106        assert_eq!(result.entries[0].get_field(0), Some(&Value::Int64(30)));
107        assert_eq!(result.entries[1].get_field(0), Some(&Value::Int64(20)));
108        assert_eq!(result.entries[2].get_field(0), Some(&Value::Int64(10)));
109    }
110
111    #[test]
112    fn test_sort_executor_multi_column() {
113        let rows = vec![
114            Rc::new(Row::new(1, vec![Value::Int64(1), Value::String("B".into())])),
115            Rc::new(Row::new(2, vec![Value::Int64(1), Value::String("A".into())])),
116            Rc::new(Row::new(3, vec![Value::Int64(2), Value::String("A".into())])),
117        ];
118        let input = Relation::from_rows(rows, vec!["t".into()]);
119
120        let executor = SortExecutor::new(vec![(0, SortOrder::Asc), (1, SortOrder::Asc)]);
121        let result = executor.execute(input);
122
123        // Should be sorted by col 0 first, then col 1
124        assert_eq!(result.entries[0].get_field(1), Some(&Value::String("A".into())));
125        assert_eq!(result.entries[1].get_field(1), Some(&Value::String("B".into())));
126        assert_eq!(result.entries[2].get_field(0), Some(&Value::Int64(2)));
127    }
128}