use vibesql_types::SqlValue;
use super::compare;
use crate::errors::ExecutorError;
#[inline]
pub fn less_than(left: &SqlValue, right: &SqlValue) -> Result<SqlValue, ExecutorError> {
compare(left, right, |cmp| cmp == std::cmp::Ordering::Less, "<")
}
#[inline]
pub fn less_than_or_equal(left: &SqlValue, right: &SqlValue) -> Result<SqlValue, ExecutorError> {
compare(left, right, |cmp| cmp != std::cmp::Ordering::Greater, "<=")
}
#[inline]
pub fn greater_than(left: &SqlValue, right: &SqlValue) -> Result<SqlValue, ExecutorError> {
compare(left, right, |cmp| cmp == std::cmp::Ordering::Greater, ">")
}
#[inline]
pub fn greater_than_or_equal(left: &SqlValue, right: &SqlValue) -> Result<SqlValue, ExecutorError> {
compare(left, right, |cmp| cmp != std::cmp::Ordering::Less, ">=")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integer_comparisons() {
assert_eq!(
less_than(&SqlValue::Integer(3), &SqlValue::Integer(5)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Integer(5), &SqlValue::Integer(3)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than_or_equal(&SqlValue::Integer(5), &SqlValue::Integer(5)).unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_temporal_comparisons() {
let result = less_than(
&SqlValue::Date("2024-01-01".parse().unwrap()),
&SqlValue::Date("2024-12-31".parse().unwrap()),
)
.unwrap();
assert_eq!(result, SqlValue::Boolean(true));
}
#[test]
fn test_timestamp_vs_string_ordering() {
let timestamp = SqlValue::Timestamp("2022-01-27 13:15:44".parse().unwrap());
let later = SqlValue::Varchar(arcstr::ArcStr::from("2022-01-27 13:15:45"));
let earlier = SqlValue::Varchar(arcstr::ArcStr::from("2022-01-27"));
assert_eq!(less_than(×tamp, &later).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than(×tamp, &earlier).unwrap(), SqlValue::Boolean(true));
assert_eq!(less_than(&earlier, ×tamp).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than_or_equal(&later, ×tamp).unwrap(), SqlValue::Boolean(true));
}
#[test]
fn test_timestamp_vs_date_only_string_is_lexicographic() {
let midnight = SqlValue::Timestamp("2017-07-08 00:00:00".parse().unwrap());
let date_only = SqlValue::Varchar(arcstr::ArcStr::from("2017-07-08"));
assert_eq!(greater_than(&midnight, &date_only).unwrap(), SqlValue::Boolean(true));
assert_eq!(less_than_or_equal(&midnight, &date_only).unwrap(), SqlValue::Boolean(false));
assert_eq!(less_than(&date_only, &midnight).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than_or_equal(&date_only, &midnight).unwrap(), SqlValue::Boolean(false));
let date_only_char = SqlValue::Character(arcstr::ArcStr::from("2017-07-08"));
assert_eq!(greater_than(&midnight, &date_only_char).unwrap(), SqlValue::Boolean(true));
let t_separated = SqlValue::Varchar(arcstr::ArcStr::from("2022-01-27T13:15:44"));
let ts = SqlValue::Timestamp("2022-01-27 13:15:44".parse().unwrap());
assert_eq!(less_than(&ts, &t_separated).unwrap(), SqlValue::Boolean(true));
}
#[test]
fn test_boolean_less_than_integer() {
assert_eq!(
less_than(&SqlValue::Boolean(false), &SqlValue::Integer(5)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than(&SqlValue::Boolean(true), &SqlValue::Integer(5)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than(&SqlValue::Boolean(true), &SqlValue::Integer(1)).unwrap(),
SqlValue::Boolean(false)
);
assert_eq!(
less_than(&SqlValue::Boolean(true), &SqlValue::Integer(0)).unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_integer_greater_than_boolean() {
assert_eq!(
greater_than(&SqlValue::Integer(5), &SqlValue::Boolean(true)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Integer(0), &SqlValue::Boolean(false)).unwrap(),
SqlValue::Boolean(false)
);
assert_eq!(
greater_than(&SqlValue::Integer(1), &SqlValue::Boolean(true)).unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_boolean_comparison_with_float() {
assert_eq!(
less_than(&SqlValue::Boolean(false), &SqlValue::Float(3.5)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Boolean(true), &SqlValue::Float(0.5)).unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_boolean_comparison_with_numeric() {
assert_eq!(
less_than(&SqlValue::Boolean(false), &SqlValue::Numeric(0.5)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than_or_equal(&SqlValue::Boolean(false), &SqlValue::Numeric(0.0)).unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_boolean_less_than_or_equal() {
assert_eq!(
less_than_or_equal(&SqlValue::Boolean(true), &SqlValue::Integer(1)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than_or_equal(&SqlValue::Boolean(false), &SqlValue::Integer(0)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than_or_equal(&SqlValue::Boolean(true), &SqlValue::Integer(0)).unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_boolean_greater_than_or_equal() {
assert_eq!(
greater_than_or_equal(&SqlValue::Boolean(true), &SqlValue::Integer(1)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than_or_equal(&SqlValue::Boolean(true), &SqlValue::Integer(0)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than_or_equal(&SqlValue::Boolean(false), &SqlValue::Integer(1)).unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_real_greater_than_bigint() {
assert_eq!(
greater_than(&SqlValue::Real(846.0), &SqlValue::Bigint(221)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Real(100.0), &SqlValue::Bigint(221)).unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_text_greater_than_integer() {
assert_eq!(
greater_than(&SqlValue::Varchar(arcstr::ArcStr::from("10")), &SqlValue::Integer(10))
.unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than(&SqlValue::Integer(10), &SqlValue::Varchar(arcstr::ArcStr::from("10")))
.unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Varchar(arcstr::ArcStr::from("20")), &SqlValue::Integer(10))
.unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_text_greater_than_real() {
assert_eq!(
greater_than(&SqlValue::Varchar(arcstr::ArcStr::from("10")), &SqlValue::Double(10.0))
.unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
less_than(&SqlValue::Double(10.0), &SqlValue::Varchar(arcstr::ArcStr::from("10")))
.unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&SqlValue::Varchar(arcstr::ArcStr::from("10.5")), &SqlValue::Double(10.0))
.unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_numeric_text_type_ordering() {
assert_eq!(
less_than(&SqlValue::Varchar(arcstr::ArcStr::from("10")), &SqlValue::Integer(10))
.unwrap(),
SqlValue::Boolean(false)
);
assert_eq!(
greater_than(&SqlValue::Integer(10), &SqlValue::Varchar(arcstr::ArcStr::from("10")))
.unwrap(),
SqlValue::Boolean(false)
);
assert_eq!(
less_than(&SqlValue::Varchar(arcstr::ArcStr::from("5")), &SqlValue::Integer(10))
.unwrap(),
SqlValue::Boolean(false)
);
}
#[test]
fn test_text_ordering_with_all_numeric_types() {
let text_val = SqlValue::Varchar(arcstr::ArcStr::from("test"));
assert_eq!(
greater_than(&text_val, &SqlValue::Integer(100)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Smallint(100)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Bigint(100)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Float(100.0)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Real(100.0)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Double(100.0)).unwrap(),
SqlValue::Boolean(true)
);
assert_eq!(
greater_than(&text_val, &SqlValue::Numeric(100.0)).unwrap(),
SqlValue::Boolean(true)
);
}
#[test]
fn test_text_vs_blob_ordering() {
let text = SqlValue::Varchar(arcstr::ArcStr::from("abc"));
let blob = SqlValue::Blob(vec![0x61, 0x62]);
assert_eq!(less_than(&text, &blob).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than_or_equal(&text, &blob).unwrap(), SqlValue::Boolean(false));
assert_eq!(greater_than(&blob, &text).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than_or_equal(&blob, &text).unwrap(), SqlValue::Boolean(true));
let chr = SqlValue::Character(arcstr::ArcStr::from("abc"));
assert_eq!(less_than(&chr, &blob).unwrap(), SqlValue::Boolean(true));
}
#[test]
fn test_numeric_vs_blob_ordering() {
let blob = SqlValue::Blob(vec![0x00]);
assert_eq!(less_than(&SqlValue::Integer(99), &blob).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than(&blob, &SqlValue::Integer(99)).unwrap(), SqlValue::Boolean(true));
assert_eq!(less_than(&SqlValue::Real(0.5), &blob).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than(&blob, &SqlValue::Real(0.5)).unwrap(), SqlValue::Boolean(true));
}
#[test]
fn test_blob_vs_blob_ordering_bytewise() {
let abc = SqlValue::Blob(vec![0x61, 0x62, 0x63]);
let ab = SqlValue::Blob(vec![0x61, 0x62]);
assert_eq!(greater_than(&abc, &ab).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than_or_equal(&abc, &ab).unwrap(), SqlValue::Boolean(true));
assert_eq!(less_than(&ab, &abc).unwrap(), SqlValue::Boolean(true));
let a = SqlValue::Blob(vec![0x61]);
let b = SqlValue::Blob(vec![0x62]);
assert_eq!(less_than(&a, &b).unwrap(), SqlValue::Boolean(true));
assert_eq!(greater_than(&b, &a).unwrap(), SqlValue::Boolean(true));
let equal_a = SqlValue::Blob(vec![0x01, 0x02]);
let equal_b = SqlValue::Blob(vec![0x01, 0x02]);
assert_eq!(greater_than_or_equal(&equal_a, &equal_b).unwrap(), SqlValue::Boolean(true));
assert_eq!(less_than_or_equal(&equal_a, &equal_b).unwrap(), SqlValue::Boolean(true));
}
}