Add support for comparing mismatched OwnedValue types.

This commit is contained in:
Stu Hood
2025-12-12 16:28:11 -08:00
parent ad4fa353eb
commit e42af4f68e
2 changed files with 80 additions and 1 deletions

View File

@@ -34,7 +34,34 @@ fn compare_owned_value<const NULLS_FIRST: bool>(lhs: &OwnedValue, rhs: &OwnedVal
(OwnedValue::Facet(a), OwnedValue::Facet(b)) => a.cmp(b),
(OwnedValue::Bytes(a), OwnedValue::Bytes(b)) => a.cmp(b),
(OwnedValue::IpAddr(a), OwnedValue::IpAddr(b)) => a.cmp(b),
x => panic!("Unsupported comparison: {x:?}"),
(OwnedValue::U64(a), OwnedValue::I64(b)) => {
if *b < 0 {
Ordering::Greater
} else {
a.cmp(&(*b as u64))
}
}
(OwnedValue::I64(a), OwnedValue::U64(b)) => {
if *a < 0 {
Ordering::Less
} else {
(*a as u64).cmp(b)
}
}
(OwnedValue::U64(a), OwnedValue::F64(b)) => (*a as f64).to_u64().cmp(&b.to_u64()),
(OwnedValue::F64(a), OwnedValue::U64(b)) => a.to_u64().cmp(&(*b as f64).to_u64()),
(OwnedValue::I64(a), OwnedValue::F64(b)) => (*a as f64).to_u64().cmp(&b.to_u64()),
(OwnedValue::F64(a), OwnedValue::I64(b)) => a.to_u64().cmp(&(*b as f64).to_u64()),
(a, b) => {
let ord = a.discriminant_value().cmp(&b.discriminant_value());
// If the discriminant is equal, it's because a new type was added, but hasn't been
// included in this `match` statement.
assert!(
ord != Ordering::Equal,
"Unimplemented comparison for type of {a:?}, {b:?}"
);
ord
}
}
}
@@ -397,3 +424,32 @@ where
.convert_segment_sort_key(sort_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::schema::OwnedValue;
#[test]
fn test_mixed_ownedvalue_compare() {
let u = OwnedValue::U64(10);
let i = OwnedValue::I64(10);
let f = OwnedValue::F64(10.0);
let nc = NaturalComparator::default();
assert_eq!(nc.compare(&u, &i), Ordering::Equal);
assert_eq!(nc.compare(&u, &f), Ordering::Equal);
assert_eq!(nc.compare(&i, &f), Ordering::Equal);
let u2 = OwnedValue::U64(11);
assert_eq!(nc.compare(&u2, &f), Ordering::Greater);
let s = OwnedValue::Str("a".to_string());
// Str < U64
assert_eq!(nc.compare(&s, &u), Ordering::Less);
// Str < I64
assert_eq!(nc.compare(&s, &i), Ordering::Less);
// Str < F64
assert_eq!(nc.compare(&s, &f), Ordering::Less);
}
}

View File

@@ -58,6 +58,29 @@ impl AsRef<OwnedValue> for OwnedValue {
}
}
impl OwnedValue {
/// Returns a u8 discriminant value for the `OwnedValue` variant.
///
/// This can be used to sort `OwnedValue` instances by their type.
pub fn discriminant_value(&self) -> u8 {
match self {
OwnedValue::Null => 0,
OwnedValue::Str(_) => 1,
OwnedValue::PreTokStr(_) => 2,
OwnedValue::U64(_) => 3,
OwnedValue::I64(_) => 4,
OwnedValue::F64(_) => 5,
OwnedValue::Bool(_) => 6,
OwnedValue::Date(_) => 7,
OwnedValue::Facet(_) => 8,
OwnedValue::Bytes(_) => 9,
OwnedValue::Array(_) => 10,
OwnedValue::Object(_) => 11,
OwnedValue::IpAddr(_) => 12,
}
}
}
impl<'a> Value<'a> for &'a OwnedValue {
type ArrayIter = std::slice::Iter<'a, OwnedValue>;
type ObjectIter = ObjectMapIter<'a>;