diff --git a/src/collector/sort_key/order.rs b/src/collector/sort_key/order.rs index 61b9e25d7..db5e4d56d 100644 --- a/src/collector/sort_key/order.rs +++ b/src/collector/sort_key/order.rs @@ -34,7 +34,34 @@ fn compare_owned_value(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); + } +} diff --git a/src/schema/document/owned_value.rs b/src/schema/document/owned_value.rs index 9fbf1f8c2..4491d66c1 100644 --- a/src/schema/document/owned_value.rs +++ b/src/schema/document/owned_value.rs @@ -58,6 +58,29 @@ impl AsRef 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>;