grafeo_core/execution/operators/
value_utils.rs1use std::cmp::Ordering;
7
8use grafeo_common::types::Value;
9
10pub fn value_to_f64(value: &Value) -> Option<f64> {
14 match value {
15 Value::Int64(i) => Some(*i as f64),
16 Value::Float64(f) => Some(*f),
17 Value::String(s) => s.parse::<f64>().ok(),
19 _ => None,
20 }
21}
22
23pub fn compare_values(a: &Value, b: &Value) -> Option<Ordering> {
28 match (a, b) {
29 (Value::Int64(a), Value::Int64(b)) => Some(a.cmp(b)),
30 (Value::Float64(a), Value::Float64(b)) => a.partial_cmp(b),
31 (Value::String(a), Value::String(b)) => {
32 if let (Ok(a_num), Ok(b_num)) = (a.parse::<f64>(), b.parse::<f64>()) {
34 a_num.partial_cmp(&b_num)
35 } else {
36 Some(a.cmp(b))
37 }
38 }
39 (Value::Bool(a), Value::Bool(b)) => Some(a.cmp(b)),
40 (Value::Int64(a), Value::Float64(b)) => (*a as f64).partial_cmp(b),
41 (Value::Float64(a), Value::Int64(b)) => a.partial_cmp(&(*b as f64)),
42 (Value::String(s), Value::Int64(i)) => s.parse::<f64>().ok()?.partial_cmp(&(*i as f64)),
44 (Value::String(s), Value::Float64(f)) => s.parse::<f64>().ok()?.partial_cmp(f),
45 (Value::Int64(i), Value::String(s)) => (*i as f64).partial_cmp(&s.parse::<f64>().ok()?),
46 (Value::Float64(f), Value::String(s)) => f.partial_cmp(&s.parse::<f64>().ok()?),
47 (Value::Timestamp(a), Value::Timestamp(b)) => Some(a.cmp(b)),
48 (Value::Date(a), Value::Date(b)) => Some(a.cmp(b)),
49 (Value::Time(a), Value::Time(b)) => Some(a.cmp(b)),
50 _ => None,
51 }
52}
53
54pub fn compare_values_total(a: &Value, b: &Value) -> Ordering {
58 match (a, b) {
59 (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
60 (Value::Int64(a), Value::Int64(b)) => a.cmp(b),
61 (Value::Float64(a), Value::Float64(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
62 (Value::String(a), Value::String(b)) => a.cmp(b),
63 (Value::Int64(a), Value::Float64(b)) => {
64 (*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
65 }
66 (Value::Float64(a), Value::Int64(b)) => {
67 a.partial_cmp(&(*b as f64)).unwrap_or(Ordering::Equal)
68 }
69 (Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
70 (Value::Date(a), Value::Date(b)) => a.cmp(b),
71 (Value::Time(a), Value::Time(b)) => a.cmp(b),
72 _ => Ordering::Equal,
73 }
74}
75
76pub fn is_less_than(current: &Option<Value>, new: &Value) -> bool {
80 match current {
81 None => true,
82 Some(curr) => compare_values(new, curr) == Some(Ordering::Less),
83 }
84}
85
86pub fn is_greater_than(current: &Option<Value>, new: &Value) -> bool {
90 match current {
91 None => true,
92 Some(curr) => compare_values(new, curr) == Some(Ordering::Greater),
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn value_to_f64_int() {
102 assert_eq!(value_to_f64(&Value::Int64(42)), Some(42.0));
103 }
104
105 #[test]
106 fn value_to_f64_float() {
107 assert_eq!(value_to_f64(&Value::Float64(2.72)), Some(2.72));
108 }
109
110 #[test]
111 fn value_to_f64_numeric_string() {
112 assert_eq!(value_to_f64(&Value::String("2.5".into())), Some(2.5));
113 }
114
115 #[test]
116 fn value_to_f64_non_numeric_string() {
117 assert_eq!(value_to_f64(&Value::String("abc".into())), None);
118 }
119
120 #[test]
121 fn value_to_f64_null() {
122 assert_eq!(value_to_f64(&Value::Null), None);
123 }
124
125 #[test]
126 fn compare_same_type_int() {
127 assert_eq!(
128 compare_values(&Value::Int64(1), &Value::Int64(2)),
129 Some(Ordering::Less)
130 );
131 }
132
133 #[test]
134 fn compare_cross_type_int_float() {
135 assert_eq!(
136 compare_values(&Value::Int64(2), &Value::Float64(2.0)),
137 Some(Ordering::Equal)
138 );
139 }
140
141 #[test]
142 fn compare_rdf_numeric_strings() {
143 assert_eq!(
144 compare_values(&Value::String("10".into()), &Value::String("9".into())),
145 Some(Ordering::Greater)
146 );
147 }
148
149 #[test]
150 fn compare_incomparable() {
151 assert_eq!(compare_values(&Value::Bool(true), &Value::Int64(1)), None);
152 }
153
154 #[test]
155 fn total_ordering_incomparable_returns_equal() {
156 assert_eq!(
157 compare_values_total(&Value::Bool(true), &Value::Int64(1)),
158 Ordering::Equal
159 );
160 }
161
162 #[test]
163 fn is_less_than_none_always_true() {
164 assert!(is_less_than(&None, &Value::Int64(5)));
165 }
166
167 #[test]
168 fn is_less_than_smaller() {
169 assert!(is_less_than(&Some(Value::Int64(10)), &Value::Int64(5)));
170 }
171
172 #[test]
173 fn is_less_than_larger() {
174 assert!(!is_less_than(&Some(Value::Int64(3)), &Value::Int64(5)));
175 }
176
177 #[test]
178 fn is_greater_than_none_always_true() {
179 assert!(is_greater_than(&None, &Value::Int64(5)));
180 }
181
182 #[test]
183 fn is_greater_than_larger() {
184 assert!(is_greater_than(&Some(Value::Int64(3)), &Value::Int64(5)));
185 }
186
187 #[test]
188 fn is_greater_than_smaller() {
189 assert!(!is_greater_than(&Some(Value::Int64(10)), &Value::Int64(5)));
190 }
191}