diff --git a/src/query/range_query/range_query_u64_fastfield.rs b/src/query/range_query/range_query_u64_fastfield.rs index 1b95de553c..71ab18a74c 100644 --- a/src/query/range_query/range_query_u64_fastfield.rs +++ b/src/query/range_query/range_query_u64_fastfield.rs @@ -85,7 +85,7 @@ impl Weight for FastFieldRangeWeight { let docset = RangeDocSet::new(value_range, ip_addr_column); Ok(Box::new(ConstScorer::new(docset, boost))) } else { - let (lower_bound, upper_bound) = if field_type.is_term() { + let (lower_bound, upper_bound) = if field_type.is_str() { let Some(str_dict_column): Option = reader.fast_fields().str(field_name)? else { @@ -260,6 +260,27 @@ pub mod tests { test_query("title:[ccc TO ddd]", 1); test_query("title:[ccc TO eee]", 1); + test_query("title:[aaa TO *}", 2); + test_query("title:[bbb TO *]", 2); + test_query("title:[bb TO *]", 2); + test_query("title:[ccc TO *]", 1); + test_query("title:[ddd TO *]", 1); + test_query("title:[dddd TO *]", 0); + + test_query("title:{aaa TO *}", 2); + test_query("title:{bbb TO *]", 1); + test_query("title:{bb TO *]", 2); + test_query("title:{ccc TO *]", 1); + test_query("title:{ddd TO *]", 0); + test_query("title:{dddd TO *]", 0); + + test_query("title:[* TO bb]", 0); + test_query("title:[* TO bbb]", 1); + test_query("title:[* TO ccc]", 1); + test_query("title:[* TO ddd]", 2); + test_query("title:[* TO ddd}", 1); + test_query("title:[* TO eee]", 2); + Ok(()) } diff --git a/src/schema/field_type.rs b/src/schema/field_type.rs index aead66deb5..cc7daf8b0e 100644 --- a/src/schema/field_type.rs +++ b/src/schema/field_type.rs @@ -202,7 +202,7 @@ impl FieldType { } /// returns true if this is an str field - pub fn is_term(&self) -> bool { + pub fn is_str(&self) -> bool { matches!(self, FieldType::Str(_)) } diff --git a/sstable/src/dictionary.rs b/sstable/src/dictionary.rs index dc29449708..c301f7a157 100644 --- a/sstable/src/dictionary.rs +++ b/sstable/src/dictionary.rs @@ -65,7 +65,9 @@ fn map_bound(bound: &Bound, transform: impl Fn(&TFrom) -> TTo } } -fn map_bound_res( +/// Takes a bound and transforms the inner value into a new bound via a closure. +/// The bound variant may change by the value returned value from the closure. +fn transform_bound_inner( bound: &Bound, transform: impl Fn(&TFrom) -> io::Result>, ) -> io::Result> { @@ -407,14 +409,14 @@ impl Dictionary { lower_bound: Bound, upper_bound: Bound, ) -> io::Result<(Bound, Bound)> { - let lower_bound = map_bound_res(&lower_bound, |start_bound_bytes| { + let lower_bound = transform_bound_inner(&lower_bound, |start_bound_bytes| { let ord = self.term_ord_or_next(start_bound_bytes)?; match ord { TermOrdHit::Exact(ord) => Ok(map_bound(&lower_bound, |_| ord)), TermOrdHit::Next(ord) => Ok(Bound::Included(ord)), // Change bounds to included } })?; - let upper_bound = map_bound_res(&upper_bound, |end_bound_bytes| { + let upper_bound = transform_bound_inner(&upper_bound, |end_bound_bytes| { let ord = self.term_ord_or_next(end_bound_bytes)?; match ord { TermOrdHit::Exact(ord) => Ok(map_bound(&upper_bound, |_| ord)), @@ -731,126 +733,42 @@ mod tests { }; // Test cases for lower_bound - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"aaa".as_slice()), - Bound::Included(b"ignored") - ) - .unwrap() - .0, - Bound::Included(0) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"aaa".as_slice()), - Bound::Excluded(b"ignored") - ) - .unwrap() - .0, - Bound::Included(0) - ); + let test_lower_bound = |bound, expected| { + assert_eq!( + dict.term_bounds_to_ord::<&[u8]>(bound, Bound::Included(b"ignored")) + .unwrap() + .0, + expected + ); + }; - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"ccc".as_slice()), - Bound::Included(b"ignored") - ) - .unwrap() - .0, - Bound::Included(1) - ); + test_lower_bound(Bound::Included(b"aaa".as_slice()), Bound::Included(0)); + test_lower_bound(Bound::Excluded(b"aaa".as_slice()), Bound::Included(0)); - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"ccc".as_slice()), - Bound::Excluded(b"ignored") - ) - .unwrap() - .0, - Bound::Included(1) - ); + test_lower_bound(Bound::Included(b"bbb".as_slice()), Bound::Included(0)); + test_lower_bound(Bound::Excluded(b"bbb".as_slice()), Bound::Excluded(0)); - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"zzz".as_slice()), - Bound::Included(b"ignored") - ) - .unwrap() - .0, - Bound::Included(2) - ); + test_lower_bound(Bound::Included(b"ccc".as_slice()), Bound::Included(1)); + test_lower_bound(Bound::Excluded(b"ccc".as_slice()), Bound::Included(1)); - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"zzz".as_slice()), - Bound::Excluded(b"ignored") - ) - .unwrap() - .0, - Bound::Included(2) - ); + test_lower_bound(Bound::Included(b"zzz".as_slice()), Bound::Included(2)); + test_lower_bound(Bound::Excluded(b"zzz".as_slice()), Bound::Included(2)); // Test cases for upper_bound - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"ignored".as_slice()), - Bound::Included(b"ccc") - ) - .unwrap() - .1, - Bound::Excluded(1) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"ignored".as_slice()), - Bound::Excluded(b"ccc") - ) - .unwrap() - .1, - Bound::Excluded(1) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"ignored".as_slice()), - Bound::Included(b"zzz") - ) - .unwrap() - .1, - Bound::Excluded(2) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"ignored".as_slice()), - Bound::Excluded(b"zzz") - ) - .unwrap() - .1, - Bound::Excluded(2) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Included(b"ignored".as_slice()), - Bound::Included(b"ddd") - ) - .unwrap() - .1, - Bound::Included(1) - ); - - assert_eq!( - dict.term_bounds_to_ord( - Bound::Excluded(b"ignored".as_slice()), - Bound::Excluded(b"ddd") - ) - .unwrap() - .1, - Bound::Excluded(1) - ); + let test_upper_bound = |bound, expected| { + assert_eq!( + dict.term_bounds_to_ord::<&[u8]>(Bound::Included(b"ignored"), bound,) + .unwrap() + .1, + expected + ); + }; + test_upper_bound(Bound::Included(b"ccc".as_slice()), Bound::Excluded(1)); + test_upper_bound(Bound::Excluded(b"ccc".as_slice()), Bound::Excluded(1)); + test_upper_bound(Bound::Included(b"zzz".as_slice()), Bound::Excluded(2)); + test_upper_bound(Bound::Excluded(b"zzz".as_slice()), Bound::Excluded(2)); + test_upper_bound(Bound::Included(b"ddd".as_slice()), Bound::Included(1)); + test_upper_bound(Bound::Excluded(b"ddd".as_slice()), Bound::Excluded(1)); } #[test]