1use crate::registry::*;
2use akar_common::types::Value;
3
4pub(crate) fn evaluate_comparison(op: ComparisonOp, args: &[Value]) -> Result<Value, String> {
7 if args.len() < 2 && !matches!(op, ComparisonOp::IsNull | ComparisonOp::IsNotNull) {
8 return Err("Comparison requires 2 arguments".into());
9 }
10
11 match op {
12 ComparisonOp::Eq => Ok(Value::Bool(values_equal(&args[0], &args[1]))),
13 ComparisonOp::NotEq => Ok(Value::Bool(!values_equal(&args[0], &args[1]))),
14 ComparisonOp::Lt => Ok(Value::Bool(compare_values(&args[0], &args[1])?.is_lt())),
15 ComparisonOp::Lte => Ok(Value::Bool(!compare_values(&args[0], &args[1])?.is_gt())),
16 ComparisonOp::Gt => Ok(Value::Bool(compare_values(&args[0], &args[1])?.is_gt())),
17 ComparisonOp::Gte => Ok(Value::Bool(!compare_values(&args[0], &args[1])?.is_lt())),
18 ComparisonOp::IsNull => Ok(Value::Bool(matches!(args[0], Value::Null))),
19 ComparisonOp::IsNotNull => Ok(Value::Bool(!matches!(args[0], Value::Null))),
20 }
21}
22
23fn values_equal(a: &Value, b: &Value) -> bool {
30 if a == b {
31 return true;
32 }
33 if let (Value::Double(x), Value::Double(y)) = (a, b) {
34 return x.is_nan() && y.is_nan();
35 }
36 if let (Value::Float(x), Value::Float(y)) = (a, b) {
37 return x.is_nan() && y.is_nan();
38 }
39 if let (Some(x), Some(y)) = (integer_to_i128(a), integer_to_i128(b)) {
40 return x == y;
41 }
42 if let (Ok(x), Ok(y)) = (
45 super::arithmetic::numeric_to_f64(a),
46 super::arithmetic::numeric_to_f64(b),
47 ) {
48 return x.to_bits() == y.to_bits() || (x.is_nan() && y.is_nan());
49 }
50 false
51}
52
53#[inline]
56pub(crate) fn double_cmp(a: f64, b: f64) -> std::cmp::Ordering {
57 if a.is_nan() {
58 if b.is_nan() {
59 std::cmp::Ordering::Equal
60 } else {
61 std::cmp::Ordering::Greater
62 }
63 } else if b.is_nan() {
64 std::cmp::Ordering::Less
65 } else {
66 a.partial_cmp(&b).unwrap_or(std::cmp::Ordering::Equal)
67 }
68}
69
70fn integer_to_i128(v: &Value) -> Option<i128> {
72 match v {
73 Value::Int64(x) => Some(*x as i128),
74 Value::Int32(x) => Some(*x as i128),
75 Value::Int16(x) => Some(*x as i128),
76 Value::Int8(x) => Some(*x as i128),
77 Value::UInt64(x) => Some(*x as i128),
78 Value::UInt32(x) => Some(*x as i128),
79 Value::UInt16(x) => Some(*x as i128),
80 Value::UInt8(x) => Some(*x as i128),
81 _ => None,
82 }
83}
84
85pub(crate) fn compare_values(a: &Value, b: &Value) -> Result<std::cmp::Ordering, String> {
86 match (a, b) {
87 (Value::Int64(x), Value::Int64(y)) => Ok(x.cmp(y)),
88 (Value::Int32(x), Value::Int32(y)) => Ok(x.cmp(y)),
89 (Value::Int16(x), Value::Int16(y)) => Ok(x.cmp(y)),
90 (Value::Int8(x), Value::Int8(y)) => Ok(x.cmp(y)),
91 (Value::UInt64(x), Value::UInt64(y)) => Ok(x.cmp(y)),
92 (Value::UInt32(x), Value::UInt32(y)) => Ok(x.cmp(y)),
93 (Value::UInt16(x), Value::UInt16(y)) => Ok(x.cmp(y)),
94 (Value::UInt8(x), Value::UInt8(y)) => Ok(x.cmp(y)),
95 (Value::Double(x), Value::Double(y)) => Ok(double_cmp(*x, *y)),
96 (Value::Float(x), Value::Float(y)) => Ok(double_cmp(*x as f64, *y as f64)),
97 (Value::String(x), Value::String(y)) => Ok(x.cmp(y)),
98 (Value::Bool(x), Value::Bool(y)) => Ok(x.cmp(y)),
99 (Value::Date(x), Value::Date(y)) => Ok(x.cmp(y)),
100 (Value::Timestamp(x), Value::Timestamp(y)) => Ok(x.cmp(y)),
101 (Value::Int64(x), Value::Double(y)) => Ok(double_cmp(*x as f64, *y)),
103 (Value::Double(x), Value::Int64(y)) => Ok(double_cmp(*x, *y as f64)),
104 (Value::Float(x), Value::Double(y)) => Ok(double_cmp(*x as f64, *y)),
105 (Value::Double(x), Value::Float(y)) => Ok(double_cmp(*x, *y as f64)),
106 (Value::Float(x), Value::Int64(y)) => Ok(double_cmp(*x as f64, *y as f64)),
107 (Value::Int64(x), Value::Float(y)) => Ok(double_cmp(*x as f64, *y as f64)),
108 _ => {
112 if let (Some(x), Some(y)) = (integer_to_i128(a), integer_to_i128(b)) {
113 Ok(x.cmp(&y))
114 } else {
115 Err("Cannot compare types".into())
116 }
117 }
118 }
119}