cypherlite_query/executor/operators/
sort.rs1use crate::executor::eval::{compare_values, eval};
4use crate::executor::{Params, Record, ScalarFnLookup};
5use crate::parser::ast::OrderItem;
6use cypherlite_storage::StorageEngine;
7
8pub fn execute_sort(
10 mut records: Vec<Record>,
11 items: &[OrderItem],
12 engine: &StorageEngine,
13 params: &Params,
14 scalar_fns: &dyn ScalarFnLookup,
15) -> Vec<Record> {
16 records.sort_by(|a, b| {
17 for item in items {
18 let val_a = eval(&item.expr, a, engine, params, scalar_fns)
19 .unwrap_or(crate::executor::Value::Null);
20 let val_b = eval(&item.expr, b, engine, params, scalar_fns)
21 .unwrap_or(crate::executor::Value::Null);
22 let ord = compare_values(&val_a, &val_b);
23 let ord = if item.ascending { ord } else { ord.reverse() };
24 if ord != std::cmp::Ordering::Equal {
25 return ord;
26 }
27 }
28 std::cmp::Ordering::Equal
29 });
30 records
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use crate::executor::Value;
37 use crate::parser::ast::*;
38 use cypherlite_core::{DatabaseConfig, SyncMode};
39 use tempfile::tempdir;
40
41 fn test_engine(dir: &std::path::Path) -> cypherlite_storage::StorageEngine {
42 let config = DatabaseConfig {
43 path: dir.join("test.cyl"),
44 wal_sync_mode: SyncMode::Normal,
45 ..Default::default()
46 };
47 cypherlite_storage::StorageEngine::open(config).expect("open")
48 }
49
50 #[test]
51 fn test_sort_ascending() {
52 let dir = tempdir().expect("tempdir");
53 let engine = test_engine(dir.path());
54
55 let mut r1 = Record::new();
56 r1.insert("x".to_string(), Value::Int64(3));
57 let mut r2 = Record::new();
58 r2.insert("x".to_string(), Value::Int64(1));
59 let mut r3 = Record::new();
60 r3.insert("x".to_string(), Value::Int64(2));
61
62 let items = vec![OrderItem {
63 expr: Expression::Variable("x".to_string()),
64 ascending: true,
65 }];
66
67 let params = Params::new();
68 let result = execute_sort(vec![r1, r2, r3], &items, &engine, ¶ms, &());
69 assert_eq!(result[0].get("x"), Some(&Value::Int64(1)));
70 assert_eq!(result[1].get("x"), Some(&Value::Int64(2)));
71 assert_eq!(result[2].get("x"), Some(&Value::Int64(3)));
72 }
73
74 #[test]
75 fn test_sort_descending() {
76 let dir = tempdir().expect("tempdir");
77 let engine = test_engine(dir.path());
78
79 let mut r1 = Record::new();
80 r1.insert("x".to_string(), Value::Int64(1));
81 let mut r2 = Record::new();
82 r2.insert("x".to_string(), Value::Int64(3));
83
84 let items = vec![OrderItem {
85 expr: Expression::Variable("x".to_string()),
86 ascending: false,
87 }];
88
89 let params = Params::new();
90 let result = execute_sort(vec![r1, r2], &items, &engine, ¶ms, &());
91 assert_eq!(result[0].get("x"), Some(&Value::Int64(3)));
92 assert_eq!(result[1].get("x"), Some(&Value::Int64(1)));
93 }
94}