1use crate::data::datatable::DataValue;
2use std::cmp::Ordering;
3
4#[must_use]
7pub fn compare_datavalues(a: &DataValue, b: &DataValue) -> Ordering {
8 match (a, b) {
9 (DataValue::Integer(a), DataValue::Integer(b)) => a.cmp(b),
11
12 (DataValue::Float(a), DataValue::Float(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
14
15 (DataValue::String(a), DataValue::String(b)) => a.cmp(b),
17
18 (DataValue::InternedString(a), DataValue::InternedString(b)) => a.as_ref().cmp(b.as_ref()),
20
21 (DataValue::String(a), DataValue::InternedString(b)) => a.cmp(b.as_ref()),
23 (DataValue::InternedString(a), DataValue::String(b)) => a.as_ref().cmp(b),
24
25 (DataValue::Boolean(a), DataValue::Boolean(b)) => a.cmp(b),
27
28 (DataValue::DateTime(a), DataValue::DateTime(b)) => a.cmp(b),
30
31 (DataValue::Null, DataValue::Null) => Ordering::Equal,
33 (DataValue::Null, _) => Ordering::Less,
34 (_, DataValue::Null) => Ordering::Greater,
35
36 (DataValue::Boolean(_), DataValue::Integer(_)) => Ordering::Less,
39 (DataValue::Boolean(_), DataValue::Float(_)) => Ordering::Less,
40 (DataValue::Boolean(_), DataValue::String(_)) => Ordering::Less,
41 (DataValue::Boolean(_), DataValue::InternedString(_)) => Ordering::Less,
42 (DataValue::Boolean(_), DataValue::DateTime(_)) => Ordering::Less,
43
44 (DataValue::Integer(_), DataValue::Boolean(_)) => Ordering::Greater,
45 (DataValue::Integer(i), DataValue::Float(f)) => {
46 (*i as f64).partial_cmp(f).unwrap_or(Ordering::Equal)
48 }
49 (DataValue::Integer(_), DataValue::String(_)) => Ordering::Less,
50 (DataValue::Integer(_), DataValue::InternedString(_)) => Ordering::Less,
51 (DataValue::Integer(_), DataValue::DateTime(_)) => Ordering::Less,
52
53 (DataValue::Float(_), DataValue::Boolean(_)) => Ordering::Greater,
54 (DataValue::Float(f), DataValue::Integer(i)) => {
55 f.partial_cmp(&(*i as f64)).unwrap_or(Ordering::Equal)
57 }
58 (DataValue::Float(_), DataValue::String(_)) => Ordering::Less,
59 (DataValue::Float(_), DataValue::InternedString(_)) => Ordering::Less,
60 (DataValue::Float(_), DataValue::DateTime(_)) => Ordering::Less,
61
62 (DataValue::String(_), DataValue::Boolean(_)) => Ordering::Greater,
63 (DataValue::String(_), DataValue::Integer(_)) => Ordering::Greater,
64 (DataValue::String(_), DataValue::Float(_)) => Ordering::Greater,
65 (DataValue::String(_), DataValue::DateTime(_)) => Ordering::Less,
66
67 (DataValue::InternedString(_), DataValue::Boolean(_)) => Ordering::Greater,
68 (DataValue::InternedString(_), DataValue::Integer(_)) => Ordering::Greater,
69 (DataValue::InternedString(_), DataValue::Float(_)) => Ordering::Greater,
70 (DataValue::InternedString(_), DataValue::DateTime(_)) => Ordering::Less,
71
72 (DataValue::DateTime(_), DataValue::Boolean(_)) => Ordering::Greater,
73 (DataValue::DateTime(_), DataValue::Integer(_)) => Ordering::Greater,
74 (DataValue::DateTime(_), DataValue::Float(_)) => Ordering::Greater,
75 (DataValue::DateTime(_), DataValue::String(_)) => Ordering::Greater,
76 (DataValue::DateTime(_), DataValue::InternedString(_)) => Ordering::Greater,
77 }
78}
79
80#[must_use]
82pub fn compare_optional_datavalues(a: Option<&DataValue>, b: Option<&DataValue>) -> Ordering {
83 match (a, b) {
84 (None, None) => Ordering::Equal,
85 (None, Some(_)) => Ordering::Less,
86 (Some(_), None) => Ordering::Greater,
87 (Some(a), Some(b)) => compare_datavalues(a, b),
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use std::sync::Arc;
95
96 #[test]
97 fn test_integer_comparison() {
98 assert_eq!(
99 compare_datavalues(&DataValue::Integer(1), &DataValue::Integer(2)),
100 Ordering::Less
101 );
102 assert_eq!(
103 compare_datavalues(&DataValue::Integer(2), &DataValue::Integer(2)),
104 Ordering::Equal
105 );
106 assert_eq!(
107 compare_datavalues(&DataValue::Integer(3), &DataValue::Integer(2)),
108 Ordering::Greater
109 );
110 }
111
112 #[test]
113 fn test_string_comparison() {
114 assert_eq!(
115 compare_datavalues(
116 &DataValue::String("apple".to_string()),
117 &DataValue::String("banana".to_string())
118 ),
119 Ordering::Less
120 );
121 }
122
123 #[test]
124 fn test_interned_string_comparison() {
125 let a = Arc::new("apple".to_string());
126 let b = Arc::new("banana".to_string());
127 assert_eq!(
128 compare_datavalues(&DataValue::InternedString(a), &DataValue::InternedString(b)),
129 Ordering::Less
130 );
131 }
132
133 #[test]
134 fn test_mixed_string_comparison() {
135 let interned = Arc::new("banana".to_string());
136 assert_eq!(
137 compare_datavalues(
138 &DataValue::String("apple".to_string()),
139 &DataValue::InternedString(interned.clone())
140 ),
141 Ordering::Less
142 );
143 assert_eq!(
144 compare_datavalues(
145 &DataValue::InternedString(interned),
146 &DataValue::String("apple".to_string())
147 ),
148 Ordering::Greater
149 );
150 }
151
152 #[test]
153 fn test_null_comparison() {
154 assert_eq!(
155 compare_datavalues(&DataValue::Null, &DataValue::Integer(1)),
156 Ordering::Less
157 );
158 assert_eq!(
159 compare_datavalues(&DataValue::Integer(1), &DataValue::Null),
160 Ordering::Greater
161 );
162 assert_eq!(
163 compare_datavalues(&DataValue::Null, &DataValue::Null),
164 Ordering::Equal
165 );
166 }
167
168 #[test]
169 fn test_cross_type_comparison() {
170 assert_eq!(
172 compare_datavalues(&DataValue::Boolean(true), &DataValue::Integer(1)),
173 Ordering::Less
174 );
175
176 assert_eq!(
178 compare_datavalues(&DataValue::Integer(1), &DataValue::Float(1.0)),
179 Ordering::Equal );
181 assert_eq!(
182 compare_datavalues(&DataValue::Integer(1), &DataValue::Float(1.5)),
183 Ordering::Less );
185 assert_eq!(
186 compare_datavalues(&DataValue::Integer(2), &DataValue::Float(1.5)),
187 Ordering::Greater );
189
190 assert_eq!(
191 compare_datavalues(&DataValue::Float(1.0), &DataValue::String("a".to_string())),
192 Ordering::Less
193 );
194 }
195}