mito2/sst/index/inverted_index/applier/builder/
between.rs1use datafusion_expr::Between;
16use index::inverted_index::search::predicate::{Bound, Predicate, Range, RangePredicate};
17
18use crate::error::Result;
19use crate::sst::index::inverted_index::applier::builder::InvertedIndexApplierBuilder;
20
21impl InvertedIndexApplierBuilder<'_> {
22 pub(crate) fn collect_between(&mut self, between: &Between) -> Result<()> {
24 if between.negated {
25 return Ok(());
26 }
27
28 let Some(column_name) = Self::column_name(&between.expr) else {
29 return Ok(());
30 };
31 let Some((column_id, data_type)) = self.column_id_and_type(column_name)? else {
32 return Ok(());
33 };
34 let Some(low) = Self::nonnull_lit(&between.low) else {
35 return Ok(());
36 };
37 let Some(high) = Self::nonnull_lit(&between.high) else {
38 return Ok(());
39 };
40
41 let predicate = Predicate::Range(RangePredicate {
42 range: Range {
43 lower: Some(Bound {
44 inclusive: true,
45 value: Self::encode_lit(low, data_type.clone())?,
46 }),
47 upper: Some(Bound {
48 inclusive: true,
49 value: Self::encode_lit(high, data_type)?,
50 }),
51 },
52 });
53
54 self.add_predicate(column_id, predicate);
55 Ok(())
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use std::collections::HashSet;
62
63 use store_api::region_request::PathType;
64
65 use super::*;
66 use crate::error::Error;
67 use crate::sst::index::inverted_index::applier::builder::tests::{
68 encoded_string, field_column, int64_lit, nonexistent_column, string_lit, tag_column,
69 test_object_store, test_region_metadata,
70 };
71 use crate::sst::index::puffin_manager::PuffinManagerFactory;
72
73 #[test]
74 fn test_collect_between_basic() {
75 let (_d, facotry) = PuffinManagerFactory::new_for_test_block("test_collect_between_basic_");
76 let metadata = test_region_metadata();
77 let mut builder = InvertedIndexApplierBuilder::new(
78 "test".to_string(),
79 PathType::Bare,
80 test_object_store(),
81 &metadata,
82 HashSet::from_iter([1, 2, 3]),
83 facotry,
84 );
85
86 let between = Between {
87 negated: false,
88 expr: Box::new(tag_column()),
89 low: Box::new(string_lit("abc")),
90 high: Box::new(string_lit("def")),
91 };
92
93 builder.collect_between(&between).unwrap();
94
95 let predicates = builder.output.get(&1).unwrap();
96 assert_eq!(predicates.len(), 1);
97 assert_eq!(
98 predicates[0],
99 Predicate::Range(RangePredicate {
100 range: Range {
101 lower: Some(Bound {
102 inclusive: true,
103 value: encoded_string("abc"),
104 }),
105 upper: Some(Bound {
106 inclusive: true,
107 value: encoded_string("def"),
108 }),
109 }
110 })
111 );
112 }
113
114 #[test]
115 fn test_collect_between_negated() {
116 let (_d, facotry) =
117 PuffinManagerFactory::new_for_test_block("test_collect_between_negated_");
118 let metadata = test_region_metadata();
119 let mut builder = InvertedIndexApplierBuilder::new(
120 "test".to_string(),
121 PathType::Bare,
122 test_object_store(),
123 &metadata,
124 HashSet::from_iter([1, 2, 3]),
125 facotry,
126 );
127
128 let between = Between {
129 negated: true,
130 expr: Box::new(tag_column()),
131 low: Box::new(string_lit("abc")),
132 high: Box::new(string_lit("def")),
133 };
134
135 builder.collect_between(&between).unwrap();
136 assert!(builder.output.is_empty());
137 }
138
139 #[test]
140 fn test_collect_between_field_column() {
141 let (_d, facotry) =
142 PuffinManagerFactory::new_for_test_block("test_collect_between_field_column_");
143 let metadata = test_region_metadata();
144 let mut builder = InvertedIndexApplierBuilder::new(
145 "test".to_string(),
146 PathType::Bare,
147 test_object_store(),
148 &metadata,
149 HashSet::from_iter([1, 2, 3]),
150 facotry,
151 );
152
153 let between = Between {
154 negated: false,
155 expr: Box::new(field_column()),
156 low: Box::new(string_lit("abc")),
157 high: Box::new(string_lit("def")),
158 };
159
160 builder.collect_between(&between).unwrap();
161
162 let predicates = builder.output.get(&3).unwrap();
163 assert_eq!(predicates.len(), 1);
164 assert_eq!(
165 predicates[0],
166 Predicate::Range(RangePredicate {
167 range: Range {
168 lower: Some(Bound {
169 inclusive: true,
170 value: encoded_string("abc"),
171 }),
172 upper: Some(Bound {
173 inclusive: true,
174 value: encoded_string("def"),
175 }),
176 }
177 })
178 );
179 }
180
181 #[test]
182 fn test_collect_between_type_mismatch() {
183 let (_d, facotry) =
184 PuffinManagerFactory::new_for_test_block("test_collect_between_type_mismatch_");
185 let metadata = test_region_metadata();
186 let mut builder = InvertedIndexApplierBuilder::new(
187 "test".to_string(),
188 PathType::Bare,
189 test_object_store(),
190 &metadata,
191 HashSet::from_iter([1, 2, 3]),
192 facotry,
193 );
194
195 let between = Between {
196 negated: false,
197 expr: Box::new(tag_column()),
198 low: Box::new(int64_lit(123)),
199 high: Box::new(int64_lit(456)),
200 };
201
202 let res = builder.collect_between(&between);
203 assert!(matches!(res, Err(Error::Encode { .. })));
204 assert!(builder.output.is_empty());
205 }
206
207 #[test]
208 fn test_collect_between_nonexistent_column() {
209 let (_d, facotry) =
210 PuffinManagerFactory::new_for_test_block("test_collect_between_nonexistent_column_");
211 let metadata = test_region_metadata();
212 let mut builder = InvertedIndexApplierBuilder::new(
213 "test".to_string(),
214 PathType::Bare,
215 test_object_store(),
216 &metadata,
217 HashSet::from_iter([1, 2, 3]),
218 facotry,
219 );
220
221 let between = Between {
222 negated: false,
223 expr: Box::new(nonexistent_column()),
224 low: Box::new(string_lit("abc")),
225 high: Box::new(string_lit("def")),
226 };
227
228 let res = builder.collect_between(&between);
229 assert!(matches!(res, Err(Error::ColumnNotFound { .. })));
230 assert!(builder.output.is_empty());
231 }
232}