1use crate::data::datatable::DataValue;
3use crate::data::value_parsing::parse_bool;
4use crate::sql::functions::date_time::parse_datetime;
5use std::cmp::Ordering;
6
7pub fn values_equal(left: &DataValue, right: &DataValue, case_insensitive: bool) -> bool {
9 compare_values(left, right, case_insensitive) == Some(Ordering::Equal)
10}
11
12pub fn values_not_equal(left: &DataValue, right: &DataValue, case_insensitive: bool) -> bool {
14 compare_values(left, right, case_insensitive) != Some(Ordering::Equal)
15}
16
17pub fn compare_with_op(
19 left: &DataValue,
20 right: &DataValue,
21 op: &str,
22 case_insensitive: bool,
23) -> bool {
24 let ordering = compare_values(left, right, case_insensitive);
25
26 match (ordering, op) {
27 (Some(Ordering::Equal), "=" | "==") => true,
28 (Some(ord), "!=" | "<>") if ord != Ordering::Equal => true,
29 (Some(Ordering::Less), "<") => true,
30 (Some(ord), "<=") if ord != Ordering::Greater => true,
31 (Some(Ordering::Greater), ">") => true,
32 (Some(ord), ">=") if ord != Ordering::Less => true,
33 _ => false,
34 }
35}
36
37pub fn compare_values(
40 left: &DataValue,
41 right: &DataValue,
42 case_insensitive: bool,
43) -> Option<Ordering> {
44 match (left, right) {
45 (DataValue::Null, DataValue::Null) => Some(Ordering::Equal),
47 (DataValue::Null, _) | (_, DataValue::Null) => None, (DataValue::Boolean(a), DataValue::Boolean(b)) => Some(a.cmp(b)),
51
52 (DataValue::Integer(a), DataValue::Integer(b)) => Some(a.cmp(b)),
54
55 (DataValue::Float(a), DataValue::Float(b)) => {
57 if a.is_nan() && b.is_nan() {
59 Some(Ordering::Equal)
60 } else if a.is_nan() {
61 Some(Ordering::Greater) } else if b.is_nan() {
63 Some(Ordering::Less)
64 } else {
65 a.partial_cmp(b)
66 }
67 }
68
69 (DataValue::Integer(a), DataValue::Float(b)) => {
71 let a_float = *a as f64;
72 if b.is_nan() {
73 Some(Ordering::Less)
74 } else {
75 a_float.partial_cmp(b)
76 }
77 }
78 (DataValue::Float(a), DataValue::Integer(b)) => {
79 let b_float = *b as f64;
80 if a.is_nan() {
81 Some(Ordering::Greater)
82 } else {
83 a.partial_cmp(&b_float)
84 }
85 }
86
87 (DataValue::DateTime(a), DataValue::DateTime(b)) => {
89 match (parse_datetime(a), parse_datetime(b)) {
91 (Ok(a_dt), Ok(b_dt)) => Some(a_dt.cmp(&b_dt)),
92 _ => Some(a.cmp(b)), }
94 }
95
96 (DataValue::String(a), DataValue::String(b)) => {
98 if let (Ok(a_dt), Ok(b_dt)) = (parse_datetime(a), parse_datetime(b)) {
100 return Some(a_dt.cmp(&b_dt));
101 }
102
103 if case_insensitive {
105 Some(a.to_lowercase().cmp(&b.to_lowercase()))
106 } else {
107 Some(a.cmp(b))
108 }
109 }
110
111 (DataValue::InternedString(a), DataValue::InternedString(b)) => {
113 if let (Ok(a_dt), Ok(b_dt)) = (parse_datetime(a.as_str()), parse_datetime(b.as_str())) {
115 return Some(a_dt.cmp(&b_dt));
116 }
117
118 if case_insensitive {
120 Some(a.to_lowercase().cmp(&b.to_lowercase()))
121 } else {
122 Some(a.as_str().cmp(b.as_str()))
123 }
124 }
125
126 (DataValue::String(a), DataValue::InternedString(b)) => {
128 if let (Ok(a_dt), Ok(b_dt)) = (parse_datetime(a), parse_datetime(b.as_str())) {
130 return Some(a_dt.cmp(&b_dt));
131 }
132
133 if case_insensitive {
135 Some(a.to_lowercase().cmp(&b.to_lowercase()))
136 } else {
137 Some(a.as_str().cmp(b))
138 }
139 }
140 (DataValue::InternedString(a), DataValue::String(b)) => {
141 if let (Ok(a_dt), Ok(b_dt)) = (parse_datetime(a.as_str()), parse_datetime(b)) {
143 return Some(a_dt.cmp(&b_dt));
144 }
145
146 if case_insensitive {
148 Some(a.to_lowercase().cmp(&b.to_lowercase()))
149 } else {
150 Some(a.as_str().cmp(b))
151 }
152 }
153
154 (DataValue::DateTime(dt), DataValue::String(s)) => {
156 match (parse_datetime(dt), parse_datetime(s)) {
157 (Ok(dt_val), Ok(s_val)) => Some(dt_val.cmp(&s_val)),
158 _ => None,
159 }
160 }
161 (DataValue::String(s), DataValue::DateTime(dt)) => {
162 match (parse_datetime(s), parse_datetime(dt)) {
163 (Ok(s_val), Ok(dt_val)) => Some(s_val.cmp(&dt_val)),
164 _ => None,
165 }
166 }
167 (DataValue::DateTime(dt), DataValue::InternedString(s)) => {
168 match (parse_datetime(dt), parse_datetime(s.as_str())) {
169 (Ok(dt_val), Ok(s_val)) => Some(dt_val.cmp(&s_val)),
170 _ => None,
171 }
172 }
173 (DataValue::InternedString(s), DataValue::DateTime(dt)) => {
174 match (parse_datetime(s.as_str()), parse_datetime(dt)) {
175 (Ok(s_val), Ok(dt_val)) => Some(s_val.cmp(&dt_val)),
176 _ => None,
177 }
178 }
179
180 (DataValue::Boolean(a), DataValue::String(b))
184 | (DataValue::String(b), DataValue::Boolean(a)) => {
185 if let Some(b_bool) = parse_bool(b) {
187 Some(a.cmp(&b_bool))
188 } else {
189 let a_str = a.to_string();
191 if case_insensitive {
192 Some(a_str.to_lowercase().cmp(&b.to_lowercase()))
193 } else {
194 Some(a_str.cmp(b))
195 }
196 }
197 }
198
199 (DataValue::Boolean(a), DataValue::Integer(b))
201 | (DataValue::Integer(b), DataValue::Boolean(a)) => {
202 match *b {
203 0 => Some(a.cmp(&false)),
204 1 => Some(a.cmp(&true)),
205 _ => None, }
207 }
208
209 (DataValue::String(a), DataValue::Integer(b))
211 | (DataValue::Integer(b), DataValue::String(a)) => {
212 if let Ok(a_int) = a.parse::<i64>() {
213 Some(a_int.cmp(b))
214 } else {
215 None
216 }
217 }
218 (DataValue::String(a), DataValue::Float(b))
219 | (DataValue::Float(b), DataValue::String(a)) => {
220 if let Ok(a_float) = a.parse::<f64>() {
221 if b.is_nan() {
222 Some(Ordering::Less)
223 } else {
224 a_float.partial_cmp(b)
225 }
226 } else {
227 None
228 }
229 }
230
231 (DataValue::InternedString(a), DataValue::Integer(b))
233 | (DataValue::Integer(b), DataValue::InternedString(a)) => {
234 if let Ok(a_int) = a.parse::<i64>() {
235 Some(a_int.cmp(b))
236 } else {
237 None
238 }
239 }
240 (DataValue::InternedString(a), DataValue::Float(b))
241 | (DataValue::Float(b), DataValue::InternedString(a)) => {
242 if let Ok(a_float) = a.parse::<f64>() {
243 if b.is_nan() {
244 Some(Ordering::Less)
245 } else {
246 a_float.partial_cmp(b)
247 }
248 } else {
249 None
250 }
251 }
252
253 (DataValue::Boolean(a), DataValue::InternedString(b)) => {
255 if let Some(b_bool) = parse_bool(b.as_str()) {
256 Some(a.cmp(&b_bool))
257 } else {
258 let a_str = a.to_string();
259 if case_insensitive {
260 Some(a_str.to_lowercase().cmp(&b.to_lowercase()))
261 } else {
262 Some(a_str.as_str().cmp(b.as_str()))
263 }
264 }
265 }
266 (DataValue::InternedString(a), DataValue::Boolean(b)) => {
267 if let Some(a_bool) = parse_bool(a.as_str()) {
268 Some(a_bool.cmp(b))
269 } else {
270 let b_str = b.to_string();
271 if case_insensitive {
272 Some(a.to_lowercase().cmp(&b_str.to_lowercase()))
273 } else {
274 Some(a.as_str().cmp(&b_str))
275 }
276 }
277 }
278
279 _ => None,
281 }
282}
283
284pub fn compare_value_with_literal(
287 table_value: &DataValue,
288 op: &str,
289 literal: &str,
290 case_insensitive: bool,
291) -> bool {
292 let literal_value = parse_literal(literal);
294 compare_with_op(table_value, &literal_value, op, case_insensitive)
295}
296
297fn parse_literal(literal: &str) -> DataValue {
299 if let Some(b) = parse_bool(literal) {
301 return DataValue::Boolean(b);
302 }
303
304 if let Ok(i) = literal.parse::<i64>() {
306 return DataValue::Integer(i);
307 }
308
309 if let Ok(f) = literal.parse::<f64>() {
311 return DataValue::Float(f);
312 }
313
314 if let Ok(dt) = parse_datetime(literal) {
316 return DataValue::DateTime(dt.format("%Y-%m-%d %H:%M:%S%.3f").to_string());
317 }
318
319 DataValue::String(literal.to_string())
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326
327 #[test]
328 fn test_boolean_comparisons() {
329 let true_val = DataValue::Boolean(true);
330 let false_val = DataValue::Boolean(false);
331
332 assert!(values_equal(&true_val, &true_val, false));
333 assert!(!values_equal(&true_val, &false_val, false));
334 assert!(compare_with_op(&true_val, &false_val, ">", false));
335 }
336
337 #[test]
338 fn test_boolean_string_coercion() {
339 let bool_val = DataValue::Boolean(true);
340 let str_val = DataValue::String("true".to_string());
341 let num_str = DataValue::String("1".to_string());
342
343 assert!(values_equal(&bool_val, &str_val, false));
344 assert!(values_equal(&bool_val, &num_str, false));
345 }
346
347 #[test]
348 fn test_boolean_integer_coercion() {
349 let bool_true = DataValue::Boolean(true);
350 let bool_false = DataValue::Boolean(false);
351 let one = DataValue::Integer(1);
352 let zero = DataValue::Integer(0);
353
354 assert!(values_equal(&bool_true, &one, false));
355 assert!(values_equal(&bool_false, &zero, false));
356 }
357
358 #[test]
359 fn test_case_insensitive_strings() {
360 let upper = DataValue::String("HELLO".to_string());
361 let lower = DataValue::String("hello".to_string());
362
363 assert!(!values_equal(&upper, &lower, false));
364 assert!(values_equal(&upper, &lower, true));
365 }
366}