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((target, data_type)) = self.expr_to_index_target(&between.expr)? else {
29 return Ok(());
30 };
31 let Some(low) = Self::nonnull_lit(&between.low) else {
32 return Ok(());
33 };
34 let Some(high) = Self::nonnull_lit(&between.high) else {
35 return Ok(());
36 };
37
38 let predicate = Predicate::Range(RangePredicate {
39 range: Range {
40 lower: Some(Bound {
41 inclusive: true,
42 value: Self::encode_lit(low, data_type.clone())?,
43 }),
44 upper: Some(Bound {
45 inclusive: true,
46 value: Self::encode_lit(high, data_type)?,
47 }),
48 },
49 });
50
51 self.add_predicate(target, predicate);
52 Ok(())
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use std::collections::HashSet;
59
60 use store_api::region_request::PathType;
61
62 use super::*;
63 use crate::error::Error;
64 use crate::sst::index::inverted_index::applier::builder::tests::{
65 encoded_string, field_column, int64_lit, nonexistent_column, string_lit, tag_column,
66 test_object_store, test_region_metadata,
67 };
68 use crate::sst::index::puffin_manager::PuffinManagerFactory;
69
70 #[test]
71 fn test_collect_between_basic() {
72 let (_d, factory) = PuffinManagerFactory::new_for_test_block("test_collect_between_basic_");
73 let metadata = test_region_metadata();
74 let mut builder = InvertedIndexApplierBuilder::new(
75 "test".to_string(),
76 PathType::Bare,
77 test_object_store(),
78 &metadata,
79 HashSet::from_iter([1, 2, 3]),
80 factory,
81 );
82
83 let between = Between {
84 negated: false,
85 expr: Box::new(tag_column()),
86 low: Box::new(string_lit("abc")),
87 high: Box::new(string_lit("def")),
88 };
89
90 builder.collect_between(&between).unwrap();
91
92 let predicates = builder
93 .output
94 .get(&index::target::IndexTarget::ColumnId(1))
95 .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, factory) =
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 factory,
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, factory) =
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 factory,
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
163 .output
164 .get(&index::target::IndexTarget::ColumnId(3))
165 .unwrap();
166 assert_eq!(predicates.len(), 1);
167 assert_eq!(
168 predicates[0],
169 Predicate::Range(RangePredicate {
170 range: Range {
171 lower: Some(Bound {
172 inclusive: true,
173 value: encoded_string("abc"),
174 }),
175 upper: Some(Bound {
176 inclusive: true,
177 value: encoded_string("def"),
178 }),
179 }
180 })
181 );
182 }
183
184 #[test]
185 fn test_collect_between_type_mismatch() {
186 let (_d, factory) =
187 PuffinManagerFactory::new_for_test_block("test_collect_between_type_mismatch_");
188 let metadata = test_region_metadata();
189 let mut builder = InvertedIndexApplierBuilder::new(
190 "test".to_string(),
191 PathType::Bare,
192 test_object_store(),
193 &metadata,
194 HashSet::from_iter([1, 2, 3]),
195 factory,
196 );
197
198 let between = Between {
199 negated: false,
200 expr: Box::new(tag_column()),
201 low: Box::new(int64_lit(123)),
202 high: Box::new(int64_lit(456)),
203 };
204
205 let res = builder.collect_between(&between);
206 assert!(matches!(res, Err(Error::Encode { .. })));
207 assert!(builder.output.is_empty());
208 }
209
210 #[test]
211 fn test_collect_between_nonexistent_column() {
212 let (_d, factory) =
213 PuffinManagerFactory::new_for_test_block("test_collect_between_nonexistent_column_");
214 let metadata = test_region_metadata();
215 let mut builder = InvertedIndexApplierBuilder::new(
216 "test".to_string(),
217 PathType::Bare,
218 test_object_store(),
219 &metadata,
220 HashSet::from_iter([1, 2, 3]),
221 factory,
222 );
223
224 let between = Between {
225 negated: false,
226 expr: Box::new(nonexistent_column()),
227 low: Box::new(string_lit("abc")),
228 high: Box::new(string_lit("def")),
229 };
230
231 let res = builder.collect_between(&between);
232 assert!(matches!(res, Err(Error::ColumnNotFound { .. })));
233 assert!(builder.output.is_empty());
234 }
235}