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 super::*;
64 use crate::error::Error;
65 use crate::sst::index::inverted_index::applier::builder::tests::{
66 encoded_string, field_column, int64_lit, nonexistent_column, string_lit, tag_column,
67 test_object_store, test_region_metadata,
68 };
69 use crate::sst::index::puffin_manager::PuffinManagerFactory;
70
71 #[test]
72 fn test_collect_between_basic() {
73 let (_d, facotry) = PuffinManagerFactory::new_for_test_block("test_collect_between_basic_");
74 let metadata = test_region_metadata();
75 let mut builder = InvertedIndexApplierBuilder::new(
76 "test".to_string(),
77 test_object_store(),
78 &metadata,
79 HashSet::from_iter([1, 2, 3]),
80 facotry,
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.output.get(&1).unwrap();
93 assert_eq!(predicates.len(), 1);
94 assert_eq!(
95 predicates[0],
96 Predicate::Range(RangePredicate {
97 range: Range {
98 lower: Some(Bound {
99 inclusive: true,
100 value: encoded_string("abc"),
101 }),
102 upper: Some(Bound {
103 inclusive: true,
104 value: encoded_string("def"),
105 }),
106 }
107 })
108 );
109 }
110
111 #[test]
112 fn test_collect_between_negated() {
113 let (_d, facotry) =
114 PuffinManagerFactory::new_for_test_block("test_collect_between_negated_");
115 let metadata = test_region_metadata();
116 let mut builder = InvertedIndexApplierBuilder::new(
117 "test".to_string(),
118 test_object_store(),
119 &metadata,
120 HashSet::from_iter([1, 2, 3]),
121 facotry,
122 );
123
124 let between = Between {
125 negated: true,
126 expr: Box::new(tag_column()),
127 low: Box::new(string_lit("abc")),
128 high: Box::new(string_lit("def")),
129 };
130
131 builder.collect_between(&between).unwrap();
132 assert!(builder.output.is_empty());
133 }
134
135 #[test]
136 fn test_collect_between_field_column() {
137 let (_d, facotry) =
138 PuffinManagerFactory::new_for_test_block("test_collect_between_field_column_");
139 let metadata = test_region_metadata();
140 let mut builder = InvertedIndexApplierBuilder::new(
141 "test".to_string(),
142 test_object_store(),
143 &metadata,
144 HashSet::from_iter([1, 2, 3]),
145 facotry,
146 );
147
148 let between = Between {
149 negated: false,
150 expr: Box::new(field_column()),
151 low: Box::new(string_lit("abc")),
152 high: Box::new(string_lit("def")),
153 };
154
155 builder.collect_between(&between).unwrap();
156
157 let predicates = builder.output.get(&3).unwrap();
158 assert_eq!(predicates.len(), 1);
159 assert_eq!(
160 predicates[0],
161 Predicate::Range(RangePredicate {
162 range: Range {
163 lower: Some(Bound {
164 inclusive: true,
165 value: encoded_string("abc"),
166 }),
167 upper: Some(Bound {
168 inclusive: true,
169 value: encoded_string("def"),
170 }),
171 }
172 })
173 );
174 }
175
176 #[test]
177 fn test_collect_between_type_mismatch() {
178 let (_d, facotry) =
179 PuffinManagerFactory::new_for_test_block("test_collect_between_type_mismatch_");
180 let metadata = test_region_metadata();
181 let mut builder = InvertedIndexApplierBuilder::new(
182 "test".to_string(),
183 test_object_store(),
184 &metadata,
185 HashSet::from_iter([1, 2, 3]),
186 facotry,
187 );
188
189 let between = Between {
190 negated: false,
191 expr: Box::new(tag_column()),
192 low: Box::new(int64_lit(123)),
193 high: Box::new(int64_lit(456)),
194 };
195
196 let res = builder.collect_between(&between);
197 assert!(matches!(res, Err(Error::FieldTypeMismatch { .. })));
198 assert!(builder.output.is_empty());
199 }
200
201 #[test]
202 fn test_collect_between_nonexistent_column() {
203 let (_d, facotry) =
204 PuffinManagerFactory::new_for_test_block("test_collect_between_nonexistent_column_");
205 let metadata = test_region_metadata();
206 let mut builder = InvertedIndexApplierBuilder::new(
207 "test".to_string(),
208 test_object_store(),
209 &metadata,
210 HashSet::from_iter([1, 2, 3]),
211 facotry,
212 );
213
214 let between = Between {
215 negated: false,
216 expr: Box::new(nonexistent_column()),
217 low: Box::new(string_lit("abc")),
218 high: Box::new(string_lit("def")),
219 };
220
221 let res = builder.collect_between(&between);
222 assert!(matches!(res, Err(Error::ColumnNotFound { .. })));
223 assert!(builder.output.is_empty());
224 }
225}