1use std::collections::HashMap;
19
20use fnv::FnvHashSet;
21
22use crate::expr::visitors::bound_predicate_visitor::{BoundPredicateVisitor, visit};
23use crate::expr::{BoundPredicate, BoundReference, Predicate};
24use crate::spec::{Datum, PartitionField, PartitionSpecRef};
25use crate::{Error, ErrorKind};
26
27#[allow(dead_code)]
30pub(crate) struct StrictProjection {
31 partition_spec: PartitionSpecRef,
32 cached_parts: HashMap<i32, Vec<PartitionField>>,
33}
34
35#[allow(dead_code)]
36impl StrictProjection {
37 pub(crate) fn new(partition_spec: PartitionSpecRef) -> Self {
38 Self {
39 partition_spec,
40 cached_parts: HashMap::new(),
41 }
42 }
43
44 fn get_parts_for_field_id(&mut self, field_id: i32) -> &Vec<PartitionField> {
45 if let std::collections::hash_map::Entry::Vacant(e) = self.cached_parts.entry(field_id) {
46 let mut parts: Vec<PartitionField> = vec![];
47 for partition_spec_field in self.partition_spec.fields() {
48 if partition_spec_field.source_id == field_id {
49 parts.push(partition_spec_field.clone())
50 }
51 }
52
53 e.insert(parts);
54 }
55
56 &self.cached_parts[&field_id]
57 }
58
59 pub(crate) fn strict_project(
60 &mut self,
61 predicate: &BoundPredicate,
62 ) -> crate::Result<Predicate> {
63 visit(self, predicate)
64 }
65
66 fn get_parts(
67 &mut self,
68 reference: &BoundReference,
69 predicate: &BoundPredicate,
70 ) -> Result<Predicate, Error> {
71 let field_id = reference.field().id;
72
73 self.get_parts_for_field_id(field_id).iter().try_fold(
75 Predicate::AlwaysFalse,
76 |res, part| {
77 Ok(
83 if let Some(pred_for_part) =
84 part.transform.strict_project(&part.name, predicate)?
85 {
86 if res == Predicate::AlwaysFalse {
87 pred_for_part
88 } else {
89 res.or(pred_for_part)
90 }
91 } else {
92 res
93 },
94 )
95 },
96 )
97 }
98}
99
100impl BoundPredicateVisitor for StrictProjection {
101 type T = Predicate;
102
103 fn always_true(&mut self) -> crate::Result<Self::T> {
104 Ok(Predicate::AlwaysTrue)
105 }
106
107 fn always_false(&mut self) -> crate::Result<Self::T> {
108 Ok(Predicate::AlwaysFalse)
109 }
110
111 fn and(&mut self, lhs: Self::T, rhs: Self::T) -> crate::Result<Self::T> {
112 Ok(lhs.and(rhs))
113 }
114
115 fn or(&mut self, lhs: Self::T, rhs: Self::T) -> crate::Result<Self::T> {
116 Ok(lhs.or(rhs))
117 }
118
119 fn not(&mut self, _inner: Self::T) -> crate::Result<Self::T> {
120 Err(Error::new(
121 ErrorKind::Unexpected,
122 "StrictProjection should not be performed against Predicates that contain a Not operator. Ensure that \"Rewrite Not\" gets applied to the originating Predicate before binding it.",
123 ))
124 }
125
126 fn is_null(
127 &mut self,
128 reference: &BoundReference,
129 predicate: &BoundPredicate,
130 ) -> crate::Result<Self::T> {
131 self.get_parts(reference, predicate)
132 }
133
134 fn not_null(
135 &mut self,
136 reference: &BoundReference,
137 predicate: &BoundPredicate,
138 ) -> crate::Result<Self::T> {
139 self.get_parts(reference, predicate)
140 }
141
142 fn is_nan(
143 &mut self,
144 reference: &BoundReference,
145 predicate: &BoundPredicate,
146 ) -> crate::Result<Self::T> {
147 self.get_parts(reference, predicate)
148 }
149
150 fn not_nan(
151 &mut self,
152 reference: &BoundReference,
153 predicate: &BoundPredicate,
154 ) -> crate::Result<Self::T> {
155 self.get_parts(reference, predicate)
156 }
157
158 fn less_than(
159 &mut self,
160 reference: &BoundReference,
161 _literal: &Datum,
162 predicate: &BoundPredicate,
163 ) -> crate::Result<Self::T> {
164 self.get_parts(reference, predicate)
165 }
166
167 fn less_than_or_eq(
168 &mut self,
169 reference: &BoundReference,
170 _literal: &Datum,
171 predicate: &BoundPredicate,
172 ) -> crate::Result<Self::T> {
173 self.get_parts(reference, predicate)
174 }
175
176 fn greater_than(
177 &mut self,
178 reference: &BoundReference,
179 _literal: &Datum,
180 predicate: &BoundPredicate,
181 ) -> crate::Result<Self::T> {
182 self.get_parts(reference, predicate)
183 }
184
185 fn greater_than_or_eq(
186 &mut self,
187 reference: &BoundReference,
188 _literal: &Datum,
189 predicate: &BoundPredicate,
190 ) -> crate::Result<Self::T> {
191 self.get_parts(reference, predicate)
192 }
193
194 fn eq(
195 &mut self,
196 reference: &BoundReference,
197 _literal: &Datum,
198 predicate: &BoundPredicate,
199 ) -> crate::Result<Self::T> {
200 self.get_parts(reference, predicate)
201 }
202
203 fn not_eq(
204 &mut self,
205 reference: &BoundReference,
206 _literal: &Datum,
207 predicate: &BoundPredicate,
208 ) -> crate::Result<Self::T> {
209 self.get_parts(reference, predicate)
210 }
211
212 fn starts_with(
213 &mut self,
214 reference: &BoundReference,
215 _literal: &Datum,
216 predicate: &BoundPredicate,
217 ) -> crate::Result<Self::T> {
218 self.get_parts(reference, predicate)
219 }
220
221 fn not_starts_with(
222 &mut self,
223 reference: &BoundReference,
224 _literal: &Datum,
225 predicate: &BoundPredicate,
226 ) -> crate::Result<Self::T> {
227 self.get_parts(reference, predicate)
228 }
229
230 fn r#in(
231 &mut self,
232 reference: &BoundReference,
233 _literals: &FnvHashSet<Datum>,
234 predicate: &BoundPredicate,
235 ) -> crate::Result<Self::T> {
236 self.get_parts(reference, predicate)
237 }
238
239 fn not_in(
240 &mut self,
241 reference: &BoundReference,
242 _literals: &FnvHashSet<Datum>,
243 predicate: &BoundPredicate,
244 ) -> crate::Result<Self::T> {
245 self.get_parts(reference, predicate)
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use std::sync::Arc;
252
253 use uuid::Uuid;
254
255 use crate::expr::visitors::strict_projection::StrictProjection;
256 use crate::expr::{Bind, Reference};
257 use crate::spec::{
258 Datum, NestedField, PartitionSpec, PrimitiveLiteral, PrimitiveType, Schema, Transform, Type,
259 };
260
261 #[tokio::test]
262 async fn test_strict_projection_month_epoch() {
263 let schema = Arc::new(
264 Schema::builder()
265 .with_fields(vec![
266 Arc::new(NestedField::required(
267 1,
268 "col1",
269 Type::Primitive(PrimitiveType::Date),
270 )),
271 Arc::new(NestedField::required(
272 2,
273 "col2",
274 Type::Primitive(PrimitiveType::Timestamp),
275 )),
276 Arc::new(NestedField::required(
277 3,
278 "col3",
279 Type::Primitive(PrimitiveType::Timestamptz),
280 )),
281 Arc::new(NestedField::required(
282 4,
283 "col4",
284 Type::Primitive(PrimitiveType::TimestampNs),
285 )),
286 Arc::new(NestedField::required(
287 5,
288 "col5",
289 Type::Primitive(PrimitiveType::TimestamptzNs),
290 )),
291 ])
292 .build()
293 .unwrap(),
294 );
295 let partition_spec = Arc::new(
296 PartitionSpec::builder(schema.clone())
297 .with_spec_id(1)
298 .add_partition_field("col1", "pcol1", Transform::Month)
299 .unwrap()
300 .add_partition_field("col2", "pcol2", Transform::Month)
301 .unwrap()
302 .add_partition_field("col3", "pcol3", Transform::Month)
303 .unwrap()
304 .add_partition_field("col4", "pcol4", Transform::Month)
305 .unwrap()
306 .add_partition_field("col5", "pcol5", Transform::Month)
307 .unwrap()
308 .build()
309 .unwrap(),
310 );
311
312 let mut strict_projection = StrictProjection::new(partition_spec.clone());
313
314 let predicate = Reference::new("col1")
316 .equal_to(Datum::date(0))
317 .and(Reference::new("col2").equal_to(Datum::timestamp_micros(0)))
318 .and(Reference::new("col3").equal_to(Datum::timestamptz_micros(0)))
319 .and(Reference::new("col4").equal_to(Datum::timestamp_nanos(0)))
320 .and(Reference::new("col5").equal_to(Datum::timestamptz_nanos(0)))
321 .bind(schema.clone(), false)
322 .unwrap();
323 let result = strict_projection.strict_project(&predicate).unwrap();
324 assert_eq!(result.to_string(), "FALSE".to_string());
325
326 let predicate = Reference::new("col1")
328 .not_equal_to(Datum::date(0))
329 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(0)))
330 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(0)))
331 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(0)))
332 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(0)))
333 .bind(schema.clone(), false)
334 .unwrap();
335 let result = strict_projection.strict_project(&predicate).unwrap();
336 assert_eq!(result.to_string(), "((((pcol1 != 0) AND (pcol2 != 0)) AND (pcol3 != 0)) AND (pcol4 != 0)) AND (pcol5 != 0)".to_string());
337
338 let predicate = Reference::new("col1")
340 .less_than(Datum::date(0))
341 .and(Reference::new("col2").less_than(Datum::timestamp_micros(0)))
342 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(0)))
343 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(0)))
344 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(0)))
345 .bind(schema.clone(), false)
346 .unwrap();
347 let result = strict_projection.strict_project(&predicate).unwrap();
348 assert_eq!(
349 result.to_string(),
350 "((((pcol1 < 0) AND (pcol2 < 0)) AND (pcol3 < 0)) AND (pcol4 < 0)) AND (pcol5 < 0)"
351 .to_string()
352 );
353
354 let predicate = Reference::new("col1")
356 .less_than_or_equal_to(Datum::date(0))
357 .and(Reference::new("col2").less_than_or_equal_to(Datum::timestamp_micros(0)))
358 .and(Reference::new("col3").less_than_or_equal_to(Datum::timestamptz_micros(0)))
359 .and(Reference::new("col4").less_than_or_equal_to(Datum::timestamp_nanos(0)))
360 .and(Reference::new("col5").less_than_or_equal_to(Datum::timestamptz_nanos(0)))
361 .bind(schema.clone(), false)
362 .unwrap();
363 let result = strict_projection.strict_project(&predicate).unwrap();
364 assert_eq!(
365 result.to_string(),
366 "((((pcol1 < 0) AND (pcol2 < 0)) AND (pcol3 < 0)) AND (pcol4 < 0)) AND (pcol5 < 0)"
367 .to_string()
368 );
369
370 let predicate = Reference::new("col1")
372 .greater_than(Datum::date(0))
373 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(0)))
374 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(0)))
375 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(0)))
376 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(0)))
377 .bind(schema.clone(), false)
378 .unwrap();
379 let result = strict_projection.strict_project(&predicate).unwrap();
380 assert_eq!(
381 result.to_string(),
382 "((((pcol1 > 0) AND (pcol2 > 0)) AND (pcol3 > 0)) AND (pcol4 > 0)) AND (pcol5 > 0)"
383 .to_string()
384 );
385
386 let predicate = Reference::new("col1")
388 .greater_than_or_equal_to(Datum::date(0))
389 .and(Reference::new("col2").greater_than_or_equal_to(Datum::timestamp_micros(0)))
390 .and(Reference::new("col3").greater_than_or_equal_to(Datum::timestamptz_micros(0)))
391 .and(Reference::new("col4").greater_than_or_equal_to(Datum::timestamp_nanos(0)))
392 .and(Reference::new("col5").greater_than_or_equal_to(Datum::timestamptz_nanos(0)))
393 .bind(schema.clone(), false)
394 .unwrap();
395 let result = strict_projection.strict_project(&predicate).unwrap();
396 assert_eq!(
397 result.to_string(),
398 "((((pcol1 > -1) AND (pcol2 > -1)) AND (pcol3 > -1)) AND (pcol4 > -1)) AND (pcol5 > -1)"
399 .to_string()
400 );
401
402 let predicate =
404 Reference::new("col1")
405 .is_not_in(
406 vec![
407 Datum::date_from_str("1970-01-01").unwrap(),
408 Datum::date_from_str("1969-12-31").unwrap(),
409 ]
410 .into_iter(),
411 )
412 .and(Reference::new("col2").is_not_in(
413 vec![Datum::timestamp_micros(0), Datum::timestamp_micros(-1)].into_iter(),
414 ))
415 .and(Reference::new("col3").is_not_in(
416 vec![Datum::timestamptz_micros(0), Datum::timestamptz_micros(-1)].into_iter(),
417 ))
418 .and(Reference::new("col4").is_not_in(
419 vec![Datum::timestamp_nanos(0), Datum::timestamp_nanos(-1)].into_iter(),
420 ))
421 .and(Reference::new("col5").is_not_in(
422 vec![Datum::timestamptz_nanos(0), Datum::timestamptz_nanos(-1)].into_iter(),
423 ))
424 .bind(schema.clone(), false)
425 .unwrap();
426 let result = strict_projection.strict_project(&predicate).unwrap();
427 assert_eq!(result.to_string(), "((((pcol1 NOT IN (0, -1)) AND (pcol2 NOT IN (0, -1))) AND (pcol3 NOT IN (0, -1))) AND (pcol4 NOT IN (0, -1))) AND (pcol5 NOT IN (0, -1))".to_string());
428
429 let predicate =
431 Reference::new("col1")
432 .is_in(
433 vec![
434 Datum::date_from_str("1970-01-01").unwrap(),
435 Datum::date_from_str("1969-12-31").unwrap(),
436 ]
437 .into_iter(),
438 )
439 .and(Reference::new("col2").is_in(
440 vec![Datum::timestamp_micros(0), Datum::timestamp_micros(-1)].into_iter(),
441 ))
442 .bind(schema.clone(), false)
443 .unwrap();
444 let result = strict_projection.strict_project(&predicate).unwrap();
445 assert_eq!(result.to_string(), "FALSE".to_string());
446 }
447
448 #[tokio::test]
449 async fn test_strict_projection_month_lower_bound() {
450 let schema = Arc::new(
451 Schema::builder()
452 .with_fields(vec![
453 Arc::new(NestedField::required(
454 1,
455 "col1",
456 Type::Primitive(PrimitiveType::Date),
457 )),
458 Arc::new(NestedField::required(
459 2,
460 "col2",
461 Type::Primitive(PrimitiveType::Timestamp),
462 )),
463 Arc::new(NestedField::required(
464 3,
465 "col3",
466 Type::Primitive(PrimitiveType::Timestamptz),
467 )),
468 Arc::new(NestedField::required(
469 4,
470 "col4",
471 Type::Primitive(PrimitiveType::TimestampNs),
472 )),
473 Arc::new(NestedField::required(
474 5,
475 "col5",
476 Type::Primitive(PrimitiveType::TimestamptzNs),
477 )),
478 ])
479 .build()
480 .unwrap(),
481 );
482 let partition_spec = Arc::new(
483 PartitionSpec::builder(schema.clone())
484 .with_spec_id(1)
485 .add_partition_field("col1", "pcol1", Transform::Month)
486 .unwrap()
487 .add_partition_field("col2", "pcol2", Transform::Month)
488 .unwrap()
489 .add_partition_field("col3", "pcol3", Transform::Month)
490 .unwrap()
491 .add_partition_field("col4", "pcol4", Transform::Month)
492 .unwrap()
493 .add_partition_field("col5", "pcol5", Transform::Month)
494 .unwrap()
495 .build()
496 .unwrap(),
497 );
498
499 let mut strict_projection = StrictProjection::new(partition_spec.clone());
500
501 let predicate = Reference::new("col1")
503 .equal_to(Datum::date_from_str("2017-01-01").unwrap())
504 .and(Reference::new("col2").equal_to(Datum::timestamp_micros(1483228800000000)))
505 .and(Reference::new("col3").equal_to(Datum::timestamptz_micros(1483228800000000)))
506 .and(Reference::new("col4").equal_to(Datum::timestamp_nanos(1483228800000000000)))
507 .and(Reference::new("col5").equal_to(Datum::timestamptz_nanos(1483228800000000000)))
508 .bind(schema.clone(), false)
509 .unwrap();
510 let result = strict_projection.strict_project(&predicate).unwrap();
511 assert_eq!(result.to_string(), "FALSE".to_string());
512
513 let predicate = Reference::new("col1")
515 .not_equal_to(Datum::date_from_str("2017-01-01").unwrap())
516 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(1483228800000000)))
517 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(1483228800000000)))
518 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(1483228800000000000)))
519 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(1483228800000000000)))
520 .bind(schema.clone(), false)
521 .unwrap();
522 let result = strict_projection.strict_project(&predicate).unwrap();
523 assert_eq!(result.to_string(), "((((pcol1 != 564) AND (pcol2 != 564)) AND (pcol3 != 564)) AND (pcol4 != 564)) AND (pcol5 != 564)".to_string());
524
525 let predicate = Reference::new("col1")
527 .less_than(Datum::date_from_str("2017-01-01").unwrap())
528 .and(Reference::new("col2").less_than(Datum::timestamp_micros(1483228800000000)))
529 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(1483228800000000)))
530 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(1483228800000000000)))
531 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(1483228800000000000)))
532 .bind(schema.clone(), false)
533 .unwrap();
534 let result = strict_projection.strict_project(&predicate).unwrap();
535 assert_eq!(
536 result.to_string(),
537 "((((pcol1 < 564) AND (pcol2 < 564)) AND (pcol3 < 564)) AND (pcol4 < 564)) AND (pcol5 < 564)"
538 .to_string()
539 );
540
541 let predicate = Reference::new("col1")
543 .less_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
544 .and(
545 Reference::new("col2")
546 .less_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
547 )
548 .and(
549 Reference::new("col3")
550 .less_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
551 )
552 .and(
553 Reference::new("col4")
554 .less_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
555 )
556 .and(
557 Reference::new("col5")
558 .less_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
559 )
560 .bind(schema.clone(), false)
561 .unwrap();
562 let result = strict_projection.strict_project(&predicate).unwrap();
563 assert_eq!(
564 result.to_string(),
565 "((((pcol1 < 564) AND (pcol2 < 564)) AND (pcol3 < 564)) AND (pcol4 < 564)) AND (pcol5 < 564)"
566 .to_string()
567 );
568
569 let predicate = Reference::new("col1")
571 .greater_than(Datum::date_from_str("2017-01-01").unwrap())
572 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(1483228800000000)))
573 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(1483228800000000)))
574 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(1483228800000000000)))
575 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(1483228800000000000)))
576 .bind(schema.clone(), false)
577 .unwrap();
578 let result = strict_projection.strict_project(&predicate).unwrap();
579 assert_eq!(
580 result.to_string(),
581 "((((pcol1 > 564) AND (pcol2 > 564)) AND (pcol3 > 564)) AND (pcol4 > 564)) AND (pcol5 > 564)"
582 .to_string()
583 );
584
585 let predicate = Reference::new("col1")
587 .greater_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
588 .and(
589 Reference::new("col2")
590 .greater_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
591 )
592 .and(
593 Reference::new("col3")
594 .greater_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
595 )
596 .and(
597 Reference::new("col4")
598 .greater_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
599 )
600 .and(
601 Reference::new("col5")
602 .greater_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
603 )
604 .bind(schema.clone(), false)
605 .unwrap();
606 let result = strict_projection.strict_project(&predicate).unwrap();
607 assert_eq!(
608 result.to_string(),
609 "((((pcol1 > 563) AND (pcol2 > 563)) AND (pcol3 > 563)) AND (pcol4 > 563)) AND (pcol5 > 563)"
610 .to_string()
611 );
612
613 let predicate = Reference::new("col1")
615 .is_not_in(
616 vec![
617 Datum::date_from_str("2017-01-01").unwrap(),
618 Datum::date_from_str("2017-12-02").unwrap(),
619 ]
620 .into_iter(),
621 )
622 .and(
623 Reference::new("col2").is_not_in(
624 vec![
625 Datum::timestamp_micros(1483228800000000),
626 Datum::timestamp_micros(1512182400000000),
627 ]
628 .into_iter(),
629 ),
630 )
631 .and(
632 Reference::new("col3").is_not_in(
633 vec![
634 Datum::timestamptz_micros(1483228800000000),
635 Datum::timestamptz_micros(1512182400000000),
636 ]
637 .into_iter(),
638 ),
639 )
640 .and(
641 Reference::new("col4").is_not_in(
642 vec![
643 Datum::timestamp_nanos(1483228800000000000),
644 Datum::timestamp_nanos(1512182400000000000),
645 ]
646 .into_iter(),
647 ),
648 )
649 .and(
650 Reference::new("col5").is_not_in(
651 vec![
652 Datum::timestamptz_nanos(1483228800000000000),
653 Datum::timestamptz_nanos(1512182400000000000),
654 ]
655 .into_iter(),
656 ),
657 )
658 .bind(schema.clone(), false)
659 .unwrap();
660 let result = strict_projection.strict_project(&predicate).unwrap();
661 assert_eq!(result.to_string(), "((((pcol1 NOT IN (575, 564)) AND (pcol2 NOT IN (575, 564))) AND (pcol3 NOT IN (575, 564))) AND (pcol4 NOT IN (575, 564))) AND (pcol5 NOT IN (575, 564))".to_string());
662
663 let predicate = Reference::new("col1")
665 .is_in(
666 vec![
667 Datum::date_from_str("2017-01-01").unwrap(),
668 Datum::date_from_str("2017-01-02").unwrap(),
669 ]
670 .into_iter(),
671 )
672 .and(
673 Reference::new("col2").is_in(
674 vec![
675 Datum::timestamp_micros(1483228800000000),
676 Datum::timestamp_micros(1483315200000000),
677 ]
678 .into_iter(),
679 ),
680 )
681 .bind(schema.clone(), false)
682 .unwrap();
683 let result = strict_projection.strict_project(&predicate).unwrap();
684 assert_eq!(result.to_string(), "FALSE".to_string());
685 }
686
687 #[tokio::test]
688 async fn test_strict_projection_negative_month_lower_bound() {
689 let schema = Arc::new(
690 Schema::builder()
691 .with_fields(vec![
692 Arc::new(NestedField::required(
693 1,
694 "col1",
695 Type::Primitive(PrimitiveType::Date),
696 )),
697 Arc::new(NestedField::required(
698 2,
699 "col2",
700 Type::Primitive(PrimitiveType::Timestamp),
701 )),
702 Arc::new(NestedField::required(
703 3,
704 "col3",
705 Type::Primitive(PrimitiveType::Timestamptz),
706 )),
707 Arc::new(NestedField::required(
708 4,
709 "col4",
710 Type::Primitive(PrimitiveType::TimestampNs),
711 )),
712 Arc::new(NestedField::required(
713 5,
714 "col5",
715 Type::Primitive(PrimitiveType::TimestamptzNs),
716 )),
717 ])
718 .build()
719 .unwrap(),
720 );
721
722 let partition_spec = Arc::new(
723 PartitionSpec::builder(schema.clone())
724 .with_spec_id(1)
725 .add_partition_field("col1", "pcol1", Transform::Month)
726 .unwrap()
727 .add_partition_field("col2", "pcol2", Transform::Month)
728 .unwrap()
729 .add_partition_field("col3", "pcol3", Transform::Month)
730 .unwrap()
731 .add_partition_field("col4", "pcol4", Transform::Month)
732 .unwrap()
733 .add_partition_field("col5", "pcol5", Transform::Month)
734 .unwrap()
735 .build()
736 .unwrap(),
737 );
738
739 let mut strict_projection = StrictProjection::new(partition_spec.clone());
740
741 let predicate = Reference::new("col1")
743 .less_than(Datum::date_from_str("1969-01-01").unwrap())
744 .and(Reference::new("col2").less_than(Datum::timestamp_micros(-31536000000000)))
745 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(-31536000000000)))
746 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(-31536000000000000)))
747 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(-31536000000000000)))
748 .bind(schema.clone(), false)
749 .unwrap();
750 let result = strict_projection.strict_project(&predicate).unwrap();
751 assert_eq!(
752 result.to_string(),
753 "((((pcol1 < -12) AND (pcol2 < -12)) AND (pcol3 < -12)) AND (pcol4 < -12)) AND (pcol5 < -12)"
754 .to_string()
755 );
756
757 let predicate = Reference::new("col1")
759 .less_than_or_equal_to(Datum::date_from_str("1969-01-01").unwrap())
760 .and(
761 Reference::new("col2")
762 .less_than_or_equal_to(Datum::timestamp_micros(-31536000000000)),
763 )
764 .and(
765 Reference::new("col3")
766 .less_than_or_equal_to(Datum::timestamptz_micros(-31536000000000)),
767 )
768 .and(
769 Reference::new("col4")
770 .less_than_or_equal_to(Datum::timestamp_nanos(-31536000000000000)),
771 )
772 .and(
773 Reference::new("col5")
774 .less_than_or_equal_to(Datum::timestamptz_nanos(-31536000000000000)),
775 )
776 .bind(schema.clone(), false)
777 .unwrap();
778 let result = strict_projection.strict_project(&predicate).unwrap();
779 assert_eq!(
780 result.to_string(),
781 "((((pcol1 < -12) AND (pcol2 < -12)) AND (pcol3 < -12)) AND (pcol4 < -12)) AND (pcol5 < -12)"
782 .to_string()
783 );
784
785 let predicate = Reference::new("col1")
787 .greater_than(Datum::date_from_str("1969-01-01").unwrap())
788 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(-31536000000000)))
789 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(-31536000000000)))
790 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(-31536000000000000)))
791 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(-31536000000000000)))
792 .bind(schema.clone(), false)
793 .unwrap();
794 let result = strict_projection.strict_project(&predicate).unwrap();
795 assert_eq!(
796 result.to_string(),
797 "((((pcol1 > -12) AND (pcol2 > -12)) AND (pcol3 > -12)) AND (pcol4 > -12)) AND (pcol5 > -12)"
798 .to_string()
799 );
800
801 let predicate = Reference::new("col1")
803 .greater_than_or_equal_to(Datum::date_from_str("1969-01-01").unwrap())
804 .and(
805 Reference::new("col2")
806 .greater_than_or_equal_to(Datum::timestamp_micros(-31536000000000)),
807 )
808 .and(
809 Reference::new("col3")
810 .greater_than_or_equal_to(Datum::timestamptz_micros(-31536000000000)),
811 )
812 .and(
813 Reference::new("col4")
814 .greater_than_or_equal_to(Datum::timestamp_nanos(-31536000000000000)),
815 )
816 .and(
817 Reference::new("col5")
818 .greater_than_or_equal_to(Datum::timestamptz_nanos(-31536000000000000)),
819 )
820 .bind(schema.clone(), false)
821 .unwrap();
822 let result = strict_projection.strict_project(&predicate).unwrap();
823 assert_eq!(
824 result.to_string(),
825 "((((pcol1 > -13) AND (pcol2 > -13)) AND (pcol3 > -13)) AND (pcol4 > -13)) AND (pcol5 > -13)"
826 .to_string()
827 );
828
829 let predicate = Reference::new("col1")
831 .not_equal_to(Datum::date_from_str("1969-01-01").unwrap())
832 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(-31536000000000)))
833 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(-31536000000000)))
834 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(-31536000000000000)))
835 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(-31536000000000000)))
836 .bind(schema.clone(), false)
837 .unwrap();
838 let result = strict_projection.strict_project(&predicate).unwrap();
839 assert_eq!(result.to_string(), "((((pcol1 != -12) AND (pcol2 != -12)) AND (pcol3 != -12)) AND (pcol4 != -12)) AND (pcol5 != -12)".to_string());
840
841 let predicate = Reference::new("col1")
843 .is_not_in(
844 vec![
845 Datum::date_from_str("1969-01-01").unwrap(),
846 Datum::date_from_str("1969-12-31").unwrap(),
847 ]
848 .into_iter(),
849 )
850 .and(
851 Reference::new("col2").is_not_in(
852 vec![
853 Datum::timestamp_micros(-31536000000000),
854 Datum::timestamp_micros(-86400000000),
855 ]
856 .into_iter(),
857 ),
858 )
859 .and(
860 Reference::new("col3").is_not_in(
861 vec![
862 Datum::timestamptz_micros(-86400000000),
863 Datum::timestamptz_micros(-31536000000000),
864 ]
865 .into_iter(),
866 ),
867 )
868 .and(
869 Reference::new("col4").is_not_in(
870 vec![
871 Datum::timestamp_nanos(-86400000000000),
872 Datum::timestamp_nanos(-31536000000000000),
873 ]
874 .into_iter(),
875 ),
876 )
877 .and(
878 Reference::new("col5").is_not_in(
879 vec![
880 Datum::timestamptz_nanos(-86400000000000),
881 Datum::timestamptz_nanos(-31536000000000000),
882 ]
883 .into_iter(),
884 ),
885 )
886 .bind(schema.clone(), false)
887 .unwrap();
888 let result = strict_projection.strict_project(&predicate).unwrap();
889 assert_eq!(result.to_string(), "((((pcol1 NOT IN (-1, -12)) AND (pcol2 NOT IN (-1, -12))) AND (pcol3 NOT IN (-1, -12))) AND (pcol4 NOT IN (-1, -12))) AND (pcol5 NOT IN (-1, -12))".to_string());
890
891 let predicate = Reference::new("col1")
893 .is_in(
894 vec![
895 Datum::date_from_str("1969-01-01").unwrap(),
896 Datum::date_from_str("1969-12-31").unwrap(),
897 ]
898 .into_iter(),
899 )
900 .and(
901 Reference::new("col2").is_in(
902 vec![
903 Datum::timestamp_micros(-315619200000000),
904 Datum::timestamp_micros(-86400000000),
905 ]
906 .into_iter(),
907 ),
908 )
909 .bind(schema.clone(), false)
910 .unwrap();
911 let result = strict_projection.strict_project(&predicate).unwrap();
912 assert_eq!(result.to_string(), "FALSE".to_string());
913 }
914
915 #[tokio::test]
916 async fn test_strict_projection_month_upper_bound() {
917 let schema = Arc::new(
918 Schema::builder()
919 .with_fields(vec![
920 Arc::new(NestedField::required(
921 1,
922 "col1",
923 Type::Primitive(PrimitiveType::Date),
924 )),
925 Arc::new(NestedField::required(
926 2,
927 "col2",
928 Type::Primitive(PrimitiveType::Timestamp),
929 )),
930 Arc::new(NestedField::required(
931 3,
932 "col3",
933 Type::Primitive(PrimitiveType::Timestamptz),
934 )),
935 Arc::new(NestedField::required(
936 4,
937 "col4",
938 Type::Primitive(PrimitiveType::TimestampNs),
939 )),
940 Arc::new(NestedField::required(
941 5,
942 "col5",
943 Type::Primitive(PrimitiveType::TimestamptzNs),
944 )),
945 ])
946 .build()
947 .unwrap(),
948 );
949
950 let partition_spec = Arc::new(
951 PartitionSpec::builder(schema.clone())
952 .with_spec_id(1)
953 .add_partition_field("col1", "pcol1", Transform::Month)
954 .unwrap()
955 .add_partition_field("col2", "pcol2", Transform::Month)
956 .unwrap()
957 .add_partition_field("col3", "pcol3", Transform::Month)
958 .unwrap()
959 .add_partition_field("col4", "pcol4", Transform::Month)
960 .unwrap()
961 .add_partition_field("col5", "pcol5", Transform::Month)
962 .unwrap()
963 .build()
964 .unwrap(),
965 );
966
967 let mut strict_projection = StrictProjection::new(partition_spec.clone());
968
969 let predicate = Reference::new("col1")
971 .less_than(Datum::date_from_str("2017-12-31").unwrap())
972 .and(Reference::new("col2").less_than(Datum::timestamp_micros(1514764799000000)))
973 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(1514764799000000)))
974 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(1514764799000000000)))
975 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(1514764799000000000)))
976 .bind(schema.clone(), false)
977 .unwrap();
978 let result = strict_projection.strict_project(&predicate).unwrap();
979 assert_eq!(
980 result.to_string(),
981 "((((pcol1 < 575) AND (pcol2 < 575)) AND (pcol3 < 575)) AND (pcol4 < 575)) AND (pcol5 < 575)"
982 .to_string()
983 );
984
985 let predicate = Reference::new("col1")
987 .less_than_or_equal_to(Datum::date_from_str("2017-12-31").unwrap())
988 .and(
989 Reference::new("col2")
990 .less_than_or_equal_to(Datum::timestamp_micros(1514764799000000)),
991 )
992 .and(
993 Reference::new("col3")
994 .less_than_or_equal_to(Datum::timestamptz_micros(1514764799000000)),
995 )
996 .and(
997 Reference::new("col4")
998 .less_than_or_equal_to(Datum::timestamp_nanos(1514764799000000000)),
999 )
1000 .and(
1001 Reference::new("col5")
1002 .less_than_or_equal_to(Datum::timestamptz_nanos(1514764799000000000)),
1003 )
1004 .bind(schema.clone(), false)
1005 .unwrap();
1006 let result = strict_projection.strict_project(&predicate).unwrap();
1007 assert_eq!(
1008 result.to_string(),
1009 "((((pcol1 < 576) AND (pcol2 < 575)) AND (pcol3 < 575)) AND (pcol4 < 575)) AND (pcol5 < 575)"
1010 .to_string()
1011 );
1012
1013 let predicate = Reference::new("col1")
1015 .greater_than(Datum::date_from_str("2017-12-31").unwrap())
1016 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(1514764799000000)))
1017 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(1514764799000000)))
1018 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(1514764799000000000)))
1019 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(1514764799000000000)))
1020 .bind(schema.clone(), false)
1021 .unwrap();
1022 let result = strict_projection.strict_project(&predicate).unwrap();
1023 assert_eq!(
1024 result.to_string(),
1025 "((((pcol1 > 575) AND (pcol2 > 575)) AND (pcol3 > 575)) AND (pcol4 > 575)) AND (pcol5 > 575)"
1026 .to_string()
1027 );
1028
1029 let predicate = Reference::new("col1")
1031 .greater_than_or_equal_to(Datum::date_from_str("2017-12-31").unwrap())
1032 .and(
1033 Reference::new("col2")
1034 .greater_than_or_equal_to(Datum::timestamp_micros(1514764799000000)),
1035 )
1036 .and(
1037 Reference::new("col3")
1038 .greater_than_or_equal_to(Datum::timestamptz_micros(1514764799000000)),
1039 )
1040 .and(
1041 Reference::new("col4")
1042 .greater_than_or_equal_to(Datum::timestamp_nanos(1514764799000000000)),
1043 )
1044 .and(
1045 Reference::new("col5")
1046 .greater_than_or_equal_to(Datum::timestamptz_nanos(1514764799000000000)),
1047 )
1048 .bind(schema.clone(), false)
1049 .unwrap();
1050 let result = strict_projection.strict_project(&predicate).unwrap();
1051 assert_eq!(
1052 result.to_string(),
1053 "((((pcol1 > 575) AND (pcol2 > 575)) AND (pcol3 > 575)) AND (pcol4 > 575)) AND (pcol5 > 575)"
1054 .to_string()
1055 );
1056
1057 let predicate = Reference::new("col1")
1059 .not_equal_to(Datum::date_from_str("2017-12-31").unwrap())
1060 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(1514764799000000)))
1061 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(1514764799000000)))
1062 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(1514764799000000000)))
1063 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(1514764799000000000)))
1064 .bind(schema.clone(), false)
1065 .unwrap();
1066 let result = strict_projection.strict_project(&predicate).unwrap();
1067 assert_eq!(result.to_string(), "((((pcol1 != 575) AND (pcol2 != 575)) AND (pcol3 != 575)) AND (pcol4 != 575)) AND (pcol5 != 575)".to_string());
1068
1069 let predicate = Reference::new("col1")
1071 .is_not_in(
1072 vec![
1073 Datum::date_from_str("2017-12-31").unwrap(),
1074 Datum::date_from_str("2017-01-01").unwrap(),
1075 ]
1076 .into_iter(),
1077 )
1078 .and(
1079 Reference::new("col2").is_not_in(
1080 vec![
1081 Datum::timestamp_micros(1514764799000000),
1082 Datum::timestamp_micros(1483228800000000),
1083 ]
1084 .into_iter(),
1085 ),
1086 )
1087 .and(
1088 Reference::new("col3").is_not_in(
1089 vec![
1090 Datum::timestamptz_micros(1514764799000000),
1091 Datum::timestamptz_micros(1483228800000000),
1092 ]
1093 .into_iter(),
1094 ),
1095 )
1096 .and(
1097 Reference::new("col4").is_not_in(
1098 vec![
1099 Datum::timestamp_nanos(1514764799000000000),
1100 Datum::timestamp_nanos(1483228800000000000),
1101 ]
1102 .into_iter(),
1103 ),
1104 )
1105 .and(
1106 Reference::new("col5").is_not_in(
1107 vec![
1108 Datum::timestamptz_nanos(1514764799000000000),
1109 Datum::timestamptz_nanos(1483228800000000000),
1110 ]
1111 .into_iter(),
1112 ),
1113 )
1114 .bind(schema.clone(), false)
1115 .unwrap();
1116 let result = strict_projection.strict_project(&predicate).unwrap();
1117 assert_eq!(result.to_string(), "((((pcol1 NOT IN (575, 564)) AND (pcol2 NOT IN (575, 564))) AND (pcol3 NOT IN (575, 564))) AND (pcol4 NOT IN (575, 564))) AND (pcol5 NOT IN (575, 564))".to_string());
1118
1119 let predicate = Reference::new("col1")
1121 .is_in(
1122 vec![
1123 Datum::date_from_str("2017-12-31").unwrap(),
1124 Datum::date_from_str("2017-01-01").unwrap(),
1125 ]
1126 .into_iter(),
1127 )
1128 .and(
1129 Reference::new("col2").is_in(
1130 vec![
1131 Datum::timestamp_micros(1514764799000000),
1132 Datum::timestamp_micros(1483228800000000),
1133 ]
1134 .into_iter(),
1135 ),
1136 )
1137 .bind(schema.clone(), false)
1138 .unwrap();
1139 let result = strict_projection.strict_project(&predicate).unwrap();
1140 assert_eq!(result.to_string(), "FALSE".to_string());
1141 }
1142
1143 #[tokio::test]
1144 async fn test_strict_projection_negative_month_upper_bound() {
1145 let schema = Arc::new(
1146 Schema::builder()
1147 .with_fields(vec![
1148 Arc::new(NestedField::required(
1149 1,
1150 "col1",
1151 Type::Primitive(PrimitiveType::Date),
1152 )),
1153 Arc::new(NestedField::required(
1154 2,
1155 "col2",
1156 Type::Primitive(PrimitiveType::Timestamp),
1157 )),
1158 Arc::new(NestedField::required(
1159 3,
1160 "col3",
1161 Type::Primitive(PrimitiveType::Timestamptz),
1162 )),
1163 Arc::new(NestedField::required(
1164 4,
1165 "col4",
1166 Type::Primitive(PrimitiveType::TimestampNs),
1167 )),
1168 Arc::new(NestedField::required(
1169 5,
1170 "col5",
1171 Type::Primitive(PrimitiveType::TimestamptzNs),
1172 )),
1173 ])
1174 .build()
1175 .unwrap(),
1176 );
1177
1178 let partition_spec = Arc::new(
1179 PartitionSpec::builder(schema.clone())
1180 .with_spec_id(1)
1181 .add_partition_field("col1", "pcol1", Transform::Month)
1182 .unwrap()
1183 .add_partition_field("col2", "pcol2", Transform::Month)
1184 .unwrap()
1185 .add_partition_field("col3", "pcol3", Transform::Month)
1186 .unwrap()
1187 .add_partition_field("col4", "pcol4", Transform::Month)
1188 .unwrap()
1189 .add_partition_field("col5", "pcol5", Transform::Month)
1190 .unwrap()
1191 .build()
1192 .unwrap(),
1193 );
1194
1195 let mut strict_projection = StrictProjection::new(partition_spec.clone());
1196
1197 let predicate = Reference::new("col1")
1199 .less_than(Datum::date_from_str("1969-12-31").unwrap())
1200 .and(Reference::new("col2").less_than(Datum::timestamp_micros(-86400000000)))
1201 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(-86400000000)))
1202 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(-86400000000000)))
1203 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(-86400000000000)))
1204 .bind(schema.clone(), false)
1205 .unwrap();
1206 let result = strict_projection.strict_project(&predicate).unwrap();
1207 assert_eq!(
1208 result.to_string(),
1209 "((((pcol1 < -1) AND (pcol2 < -1)) AND (pcol3 < -1)) AND (pcol4 < -1)) AND (pcol5 < -1)"
1210 .to_string()
1211 );
1212
1213 let predicate = Reference::new("col1")
1215 .less_than_or_equal_to(Datum::date_from_str("1969-12-31").unwrap())
1216 .and(
1217 Reference::new("col2").less_than_or_equal_to(Datum::timestamp_micros(-86400000000)),
1218 )
1219 .and(
1220 Reference::new("col3")
1221 .less_than_or_equal_to(Datum::timestamptz_micros(-86400000000)),
1222 )
1223 .and(
1224 Reference::new("col4")
1225 .less_than_or_equal_to(Datum::timestamp_nanos(-86400000000000)),
1226 )
1227 .and(
1228 Reference::new("col5")
1229 .less_than_or_equal_to(Datum::timestamptz_nanos(-86400000000000)),
1230 )
1231 .bind(schema.clone(), false)
1232 .unwrap();
1233 let result = strict_projection.strict_project(&predicate).unwrap();
1234 assert_eq!(
1235 result.to_string(),
1236 "((((pcol1 < 0) AND (pcol2 < -1)) AND (pcol3 < -1)) AND (pcol4 < -1)) AND (pcol5 < -1)"
1237 .to_string()
1238 );
1239
1240 let predicate = Reference::new("col1")
1242 .greater_than(Datum::date_from_str("1969-12-31").unwrap())
1243 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(-86400000000)))
1244 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(-86400000000)))
1245 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(-86400000000000)))
1246 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(-86400000000000)))
1247 .bind(schema.clone(), false)
1248 .unwrap();
1249 let result = strict_projection.strict_project(&predicate).unwrap();
1250 assert_eq!(
1251 result.to_string(),
1252 "((((pcol1 > -1) AND (pcol2 > -1)) AND (pcol3 > -1)) AND (pcol4 > -1)) AND (pcol5 > -1)"
1253 .to_string()
1254 );
1255
1256 let predicate = Reference::new("col1")
1258 .greater_than_or_equal_to(Datum::date_from_str("1969-12-31").unwrap())
1259 .and(
1260 Reference::new("col2")
1261 .greater_than_or_equal_to(Datum::timestamp_micros(-86400000000)),
1262 )
1263 .and(
1264 Reference::new("col3")
1265 .greater_than_or_equal_to(Datum::timestamptz_micros(-86400000000)),
1266 )
1267 .and(
1268 Reference::new("col4")
1269 .greater_than_or_equal_to(Datum::timestamp_nanos(-86400000000000)),
1270 )
1271 .and(
1272 Reference::new("col5")
1273 .greater_than_or_equal_to(Datum::timestamptz_nanos(-86400000000000)),
1274 )
1275 .bind(schema.clone(), false)
1276 .unwrap();
1277 let result = strict_projection.strict_project(&predicate).unwrap();
1278 assert_eq!(
1279 result.to_string(),
1280 "((((pcol1 > -1) AND (pcol2 > -1)) AND (pcol3 > -1)) AND (pcol4 > -1)) AND (pcol5 > -1)"
1281 .to_string()
1282 );
1283
1284 let predicate = Reference::new("col1")
1286 .not_equal_to(Datum::date_from_str("1969-12-31").unwrap())
1287 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(-86400000000)))
1288 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(-86400000000)))
1289 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(-86400000000000)))
1290 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(-86400000000000)))
1291 .bind(schema.clone(), false)
1292 .unwrap();
1293 let result = strict_projection.strict_project(&predicate).unwrap();
1294 assert_eq!(result.to_string(), "((((pcol1 != -1) AND (pcol2 != -1)) AND (pcol3 != -1)) AND (pcol4 != -1)) AND (pcol5 != -1)".to_string());
1295 }
1296
1297 #[tokio::test]
1298 async fn test_strict_projection_day() {
1299 let schema = Arc::new(
1300 Schema::builder()
1301 .with_fields(vec![
1302 Arc::new(NestedField::required(
1303 1,
1304 "col1",
1305 Type::Primitive(PrimitiveType::Date),
1306 )),
1307 Arc::new(NestedField::required(
1308 2,
1309 "col2",
1310 Type::Primitive(PrimitiveType::Timestamp),
1311 )),
1312 Arc::new(NestedField::required(
1313 3,
1314 "col3",
1315 Type::Primitive(PrimitiveType::Timestamptz),
1316 )),
1317 Arc::new(NestedField::required(
1318 4,
1319 "col4",
1320 Type::Primitive(PrimitiveType::TimestampNs),
1321 )),
1322 Arc::new(NestedField::required(
1323 5,
1324 "col5",
1325 Type::Primitive(PrimitiveType::TimestamptzNs),
1326 )),
1327 ])
1328 .build()
1329 .unwrap(),
1330 );
1331
1332 let partition_spec = Arc::new(
1333 PartitionSpec::builder(schema.clone())
1334 .with_spec_id(1)
1335 .add_partition_field("col1", "pcol1", Transform::Day)
1336 .unwrap()
1337 .add_partition_field("col2", "pcol2", Transform::Day)
1338 .unwrap()
1339 .add_partition_field("col3", "pcol3", Transform::Day)
1340 .unwrap()
1341 .add_partition_field("col4", "pcol4", Transform::Day)
1342 .unwrap()
1343 .add_partition_field("col5", "pcol5", Transform::Day)
1344 .unwrap()
1345 .build()
1346 .unwrap(),
1347 );
1348
1349 let mut strict_projection = StrictProjection::new(partition_spec.clone());
1350
1351 let predicate = Reference::new("col1")
1353 .less_than(Datum::date_from_str("2017-01-01").unwrap())
1354 .and(Reference::new("col2").less_than(Datum::timestamp_micros(1483228800000000)))
1355 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(1483228800000000)))
1356 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(1483228800000000000)))
1357 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(1483228800000000000)))
1358 .bind(schema.clone(), false)
1359 .unwrap();
1360 let result = strict_projection.strict_project(&predicate).unwrap();
1361 assert_eq!(
1362 result.to_string(),
1363 "((((pcol1 < 2017-01-01) AND (pcol2 < 2017-01-01)) AND (pcol3 < 2017-01-01)) AND (pcol4 < 2017-01-01)) AND (pcol5 < 2017-01-01)"
1364 .to_string()
1365 );
1366
1367 let predicate = Reference::new("col1")
1369 .less_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1370 .and(
1371 Reference::new("col2")
1372 .less_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
1373 )
1374 .and(
1375 Reference::new("col3")
1376 .less_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
1377 )
1378 .and(
1379 Reference::new("col4")
1380 .less_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
1381 )
1382 .and(
1383 Reference::new("col5")
1384 .less_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
1385 )
1386 .bind(schema.clone(), false)
1387 .unwrap();
1388 let result = strict_projection.strict_project(&predicate).unwrap();
1389 assert_eq!(
1390 result.to_string(),
1391 "((((pcol1 < 2017-01-02) AND (pcol2 < 2017-01-01)) AND (pcol3 < 2017-01-01)) AND (pcol4 < 2017-01-01)) AND (pcol5 < 2017-01-01)"
1392 .to_string()
1393 );
1394
1395 let predicate = Reference::new("col1")
1397 .greater_than(Datum::date_from_str("2017-01-01").unwrap())
1398 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(1483228800000000)))
1399 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(1483228800000000)))
1400 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(1483228800000000000)))
1401 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(1483228800000000000)))
1402 .bind(schema.clone(), false)
1403 .unwrap();
1404 let result = strict_projection.strict_project(&predicate).unwrap();
1405 assert_eq!(
1406 result.to_string(),
1407 "((((pcol1 > 2017-01-01) AND (pcol2 > 2017-01-01)) AND (pcol3 > 2017-01-01)) AND (pcol4 > 2017-01-01)) AND (pcol5 > 2017-01-01)"
1408 .to_string()
1409 );
1410
1411 let predicate = Reference::new("col1")
1413 .greater_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1414 .and(
1415 Reference::new("col2")
1416 .greater_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
1417 )
1418 .and(
1419 Reference::new("col3")
1420 .greater_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
1421 )
1422 .and(
1423 Reference::new("col4")
1424 .greater_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
1425 )
1426 .and(
1427 Reference::new("col5")
1428 .greater_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
1429 )
1430 .bind(schema.clone(), false)
1431 .unwrap();
1432 let result = strict_projection.strict_project(&predicate).unwrap();
1433 assert_eq!(
1434 result.to_string(),
1435 "((((pcol1 > 2016-12-31) AND (pcol2 > 2016-12-31)) AND (pcol3 > 2016-12-31)) AND (pcol4 > 2016-12-31)) AND (pcol5 > 2016-12-31)"
1436 .to_string()
1437 );
1438
1439 let predicate = Reference::new("col1")
1441 .not_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1442 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(1483228800000000)))
1443 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(1483228800000000)))
1444 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(1483228800000000000)))
1445 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(1483228800000000000)))
1446 .bind(schema.clone(), false)
1447 .unwrap();
1448 let result = strict_projection.strict_project(&predicate).unwrap();
1449 assert_eq!(result.to_string(), "((((pcol1 != 2017-01-01) AND (pcol2 != 2017-01-01)) AND (pcol3 != 2017-01-01)) AND (pcol4 != 2017-01-01)) AND (pcol5 != 2017-01-01)".to_string());
1450
1451 let predicate = Reference::new("col1")
1453 .is_not_in(
1454 vec![
1455 Datum::date_from_str("2017-01-01").unwrap(),
1456 Datum::date_from_str("2017-12-31").unwrap(),
1457 ]
1458 .into_iter(),
1459 )
1460 .and(
1461 Reference::new("col2").is_not_in(
1462 vec![
1463 Datum::timestamp_micros(1483228800000000),
1464 Datum::timestamp_micros(1514764799000000),
1465 ]
1466 .into_iter(),
1467 ),
1468 )
1469 .and(
1470 Reference::new("col3").is_not_in(
1471 vec![
1472 Datum::timestamptz_micros(1483228800000000),
1473 Datum::timestamptz_micros(1514764799000000),
1474 ]
1475 .into_iter(),
1476 ),
1477 )
1478 .and(
1479 Reference::new("col4").is_not_in(
1480 vec![
1481 Datum::timestamp_nanos(1483228800000000000),
1482 Datum::timestamp_nanos(1514764799000000000),
1483 ]
1484 .into_iter(),
1485 ),
1486 )
1487 .and(
1488 Reference::new("col5").is_not_in(
1489 vec![
1490 Datum::timestamptz_nanos(1483228800000000000),
1491 Datum::timestamptz_nanos(1514764799000000000),
1492 ]
1493 .into_iter(),
1494 ),
1495 )
1496 .bind(schema.clone(), false)
1497 .unwrap();
1498 let result = strict_projection.strict_project(&predicate).unwrap();
1499 assert_eq!(result.to_string(), "((((pcol1 NOT IN (2017-01-01, 2017-12-31)) AND (pcol2 NOT IN (2017-01-01, 2017-12-31))) AND (pcol3 NOT IN (2017-01-01, 2017-12-31))) AND (pcol4 NOT IN (2017-01-01, 2017-12-31))) AND (pcol5 NOT IN (2017-01-01, 2017-12-31))".to_string());
1500
1501 let predicate = Reference::new("col1")
1503 .is_in(
1504 vec![
1505 Datum::date_from_str("2017-01-01").unwrap(),
1506 Datum::date_from_str("2017-12-31").unwrap(),
1507 ]
1508 .into_iter(),
1509 )
1510 .and(
1511 Reference::new("col2").is_in(
1512 vec![
1513 Datum::timestamp_micros(1483228800000000),
1514 Datum::timestamp_micros(1514764799000000),
1515 ]
1516 .into_iter(),
1517 ),
1518 )
1519 .bind(schema.clone(), false)
1520 .unwrap();
1521 let result = strict_projection.strict_project(&predicate).unwrap();
1522 assert_eq!(result.to_string(), "FALSE".to_string());
1523 }
1524
1525 #[tokio::test]
1526 async fn test_strict_projection_negative_day() {
1527 let schema = Arc::new(
1528 Schema::builder()
1529 .with_fields(vec![
1530 Arc::new(NestedField::required(
1531 1,
1532 "col1",
1533 Type::Primitive(PrimitiveType::Date),
1534 )),
1535 Arc::new(NestedField::required(
1536 2,
1537 "col2",
1538 Type::Primitive(PrimitiveType::Timestamp),
1539 )),
1540 Arc::new(NestedField::required(
1541 3,
1542 "col3",
1543 Type::Primitive(PrimitiveType::Timestamptz),
1544 )),
1545 Arc::new(NestedField::required(
1546 4,
1547 "col4",
1548 Type::Primitive(PrimitiveType::TimestampNs),
1549 )),
1550 Arc::new(NestedField::required(
1551 5,
1552 "col5",
1553 Type::Primitive(PrimitiveType::TimestamptzNs),
1554 )),
1555 ])
1556 .build()
1557 .unwrap(),
1558 );
1559
1560 let partition_spec = Arc::new(
1561 PartitionSpec::builder(schema.clone())
1562 .with_spec_id(1)
1563 .add_partition_field("col1", "pcol1", Transform::Day)
1564 .unwrap()
1565 .add_partition_field("col2", "pcol2", Transform::Day)
1566 .unwrap()
1567 .add_partition_field("col3", "pcol3", Transform::Day)
1568 .unwrap()
1569 .add_partition_field("col4", "pcol4", Transform::Day)
1570 .unwrap()
1571 .add_partition_field("col5", "pcol5", Transform::Day)
1572 .unwrap()
1573 .build()
1574 .unwrap(),
1575 );
1576
1577 let mut strict_projection = StrictProjection::new(partition_spec.clone());
1578
1579 let predicate = Reference::new("col1")
1581 .less_than(Datum::date_from_str("1969-12-30").unwrap())
1582 .and(Reference::new("col2").less_than(Datum::timestamp_micros(-172800000000)))
1583 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(-172800000000)))
1584 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(-172800000000000)))
1585 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(-172800000000000)))
1586 .bind(schema.clone(), false)
1587 .unwrap();
1588 let result = strict_projection.strict_project(&predicate).unwrap();
1589 assert_eq!(
1590 result.to_string(),
1591 "((((pcol1 < 1969-12-30) AND (pcol2 < 1969-12-30)) AND (pcol3 < 1969-12-30)) AND (pcol4 < 1969-12-30)) AND (pcol5 < 1969-12-30)"
1592 .to_string()
1593 );
1594
1595 let predicate = Reference::new("col1")
1597 .less_than_or_equal_to(Datum::date_from_str("1969-12-30").unwrap())
1598 .and(
1599 Reference::new("col2")
1600 .less_than_or_equal_to(Datum::timestamp_micros(-172800000000)),
1601 )
1602 .and(
1603 Reference::new("col3")
1604 .less_than_or_equal_to(Datum::timestamptz_micros(-172800000000)),
1605 )
1606 .and(
1607 Reference::new("col4")
1608 .less_than_or_equal_to(Datum::timestamp_nanos(-172800000000000)),
1609 )
1610 .and(
1611 Reference::new("col5")
1612 .less_than_or_equal_to(Datum::timestamptz_nanos(-172800000000000)),
1613 )
1614 .bind(schema.clone(), false)
1615 .unwrap();
1616 let result = strict_projection.strict_project(&predicate).unwrap();
1617 assert_eq!(
1618 result.to_string(),
1619 "((((pcol1 < 1969-12-31) AND (pcol2 < 1969-12-30)) AND (pcol3 < 1969-12-30)) AND (pcol4 < 1969-12-30)) AND (pcol5 < 1969-12-30)"
1620 .to_string()
1621 );
1622
1623 let predicate = Reference::new("col1")
1625 .greater_than(Datum::date_from_str("1969-12-30").unwrap())
1626 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(-172800000000)))
1627 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(-172800000000)))
1628 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(-172800000000000)))
1629 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(-172800000000000)))
1630 .bind(schema.clone(), false)
1631 .unwrap();
1632 let result = strict_projection.strict_project(&predicate).unwrap();
1633 assert_eq!(
1634 result.to_string(),
1635 "((((pcol1 > 1969-12-30) AND (pcol2 > 1969-12-30)) AND (pcol3 > 1969-12-30)) AND (pcol4 > 1969-12-30)) AND (pcol5 > 1969-12-30)"
1636 .to_string()
1637 );
1638
1639 let predicate = Reference::new("col1")
1641 .greater_than_or_equal_to(Datum::date_from_str("1969-12-30").unwrap())
1642 .and(
1643 Reference::new("col2")
1644 .greater_than_or_equal_to(Datum::timestamp_micros(-172800000000)),
1645 )
1646 .and(
1647 Reference::new("col3")
1648 .greater_than_or_equal_to(Datum::timestamptz_micros(-172800000000)),
1649 )
1650 .and(
1651 Reference::new("col4")
1652 .greater_than_or_equal_to(Datum::timestamp_nanos(-172800000000000)),
1653 )
1654 .and(
1655 Reference::new("col5")
1656 .greater_than_or_equal_to(Datum::timestamptz_nanos(-172800000000000)),
1657 )
1658 .bind(schema.clone(), false)
1659 .unwrap();
1660 let result = strict_projection.strict_project(&predicate).unwrap();
1661 assert_eq!(
1662 result.to_string(),
1663 "((((pcol1 > 1969-12-29) AND (pcol2 > 1969-12-29)) AND (pcol3 > 1969-12-29)) AND (pcol4 > 1969-12-29)) AND (pcol5 > 1969-12-29)"
1664 .to_string()
1665 );
1666
1667 let predicate = Reference::new("col1")
1669 .not_equal_to(Datum::date_from_str("1969-12-30").unwrap())
1670 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(-172800000000)))
1671 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(-172800000000)))
1672 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(-172800000000000)))
1673 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(-172800000000000)))
1674 .bind(schema.clone(), false)
1675 .unwrap();
1676 let result = strict_projection.strict_project(&predicate).unwrap();
1677 assert_eq!(result.to_string(), "((((pcol1 != 1969-12-30) AND (pcol2 != 1969-12-30)) AND (pcol3 != 1969-12-30)) AND (pcol4 != 1969-12-30)) AND (pcol5 != 1969-12-30)".to_string());
1678
1679 let predicate = Reference::new("col1")
1681 .is_not_in(
1682 vec![
1683 Datum::date_from_str("1969-12-30").unwrap(),
1684 Datum::date_from_str("1969-12-31").unwrap(),
1685 ]
1686 .into_iter(),
1687 )
1688 .and(
1689 Reference::new("col2").is_not_in(
1690 vec![
1691 Datum::timestamp_micros(-172800000000),
1692 Datum::timestamp_micros(-1),
1693 ]
1694 .into_iter(),
1695 ),
1696 )
1697 .and(
1698 Reference::new("col3").is_not_in(
1699 vec![
1700 Datum::timestamptz_micros(-172800000000),
1701 Datum::timestamptz_micros(-1),
1702 ]
1703 .into_iter(),
1704 ),
1705 )
1706 .and(
1707 Reference::new("col4").is_not_in(
1708 vec![
1709 Datum::timestamp_nanos(-172800000000000),
1710 Datum::timestamp_nanos(-1),
1711 ]
1712 .into_iter(),
1713 ),
1714 )
1715 .and(
1716 Reference::new("col5").is_not_in(
1717 vec![
1718 Datum::timestamptz_nanos(-172800000000000),
1719 Datum::timestamptz_nanos(-1),
1720 ]
1721 .into_iter(),
1722 ),
1723 )
1724 .bind(schema.clone(), false)
1725 .unwrap();
1726 let result = strict_projection.strict_project(&predicate).unwrap();
1727 assert_eq!(result.to_string(), "((((pcol1 NOT IN (1969-12-31, 1969-12-30)) AND (pcol2 NOT IN (1969-12-31, 1969-12-30))) AND (pcol3 NOT IN (1969-12-31, 1969-12-30))) AND (pcol4 NOT IN (1969-12-31, 1969-12-30))) AND (pcol5 NOT IN (1969-12-31, 1969-12-30))".to_string());
1728
1729 let predicate = Reference::new("col1")
1731 .is_in(
1732 vec![
1733 Datum::date_from_str("1969-12-30").unwrap(),
1734 Datum::date_from_str("1969-12-31").unwrap(),
1735 ]
1736 .into_iter(),
1737 )
1738 .and(
1739 Reference::new("col2").is_in(
1740 vec![
1741 Datum::timestamp_micros(-172800000000),
1742 Datum::timestamp_micros(-1),
1743 ]
1744 .into_iter(),
1745 ),
1746 )
1747 .bind(schema.clone(), false)
1748 .unwrap();
1749 let result = strict_projection.strict_project(&predicate).unwrap();
1750 assert_eq!(result.to_string(), "FALSE".to_string());
1751 }
1752
1753 #[tokio::test]
1754 async fn test_strict_projection_year_lower_bound() {
1755 let schema = Arc::new(
1756 Schema::builder()
1757 .with_fields(vec![
1758 Arc::new(NestedField::required(
1759 1,
1760 "col1",
1761 Type::Primitive(PrimitiveType::Date),
1762 )),
1763 Arc::new(NestedField::required(
1764 2,
1765 "col2",
1766 Type::Primitive(PrimitiveType::Timestamp),
1767 )),
1768 Arc::new(NestedField::required(
1769 3,
1770 "col3",
1771 Type::Primitive(PrimitiveType::Timestamptz),
1772 )),
1773 Arc::new(NestedField::required(
1774 4,
1775 "col4",
1776 Type::Primitive(PrimitiveType::TimestampNs),
1777 )),
1778 Arc::new(NestedField::required(
1779 5,
1780 "col5",
1781 Type::Primitive(PrimitiveType::TimestamptzNs),
1782 )),
1783 ])
1784 .build()
1785 .unwrap(),
1786 );
1787
1788 let partition_spec = Arc::new(
1789 PartitionSpec::builder(schema.clone())
1790 .with_spec_id(1)
1791 .add_partition_field("col1", "pcol1", Transform::Year)
1792 .unwrap()
1793 .add_partition_field("col2", "pcol2", Transform::Year)
1794 .unwrap()
1795 .add_partition_field("col3", "pcol3", Transform::Year)
1796 .unwrap()
1797 .add_partition_field("col4", "pcol4", Transform::Year)
1798 .unwrap()
1799 .add_partition_field("col5", "pcol5", Transform::Year)
1800 .unwrap()
1801 .build()
1802 .unwrap(),
1803 );
1804
1805 let mut strict_projection = StrictProjection::new(partition_spec.clone());
1806
1807 let predicate = Reference::new("col1")
1809 .less_than(Datum::date_from_str("2017-01-01").unwrap())
1810 .and(Reference::new("col2").less_than(Datum::timestamp_micros(1483228800000000)))
1811 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(1483228800000000)))
1812 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(1483228800000000000)))
1813 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(1483228800000000000)))
1814 .bind(schema.clone(), false)
1815 .unwrap();
1816 let result = strict_projection.strict_project(&predicate).unwrap();
1817 assert_eq!(
1818 result.to_string(),
1819 "((((pcol1 < 47) AND (pcol2 < 47)) AND (pcol3 < 47)) AND (pcol4 < 47)) AND (pcol5 < 47)"
1820 .to_string()
1821 );
1822
1823 let predicate = Reference::new("col1")
1825 .less_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1826 .and(
1827 Reference::new("col2")
1828 .less_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
1829 )
1830 .and(
1831 Reference::new("col3")
1832 .less_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
1833 )
1834 .and(
1835 Reference::new("col4")
1836 .less_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
1837 )
1838 .and(
1839 Reference::new("col5")
1840 .less_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
1841 )
1842 .bind(schema.clone(), false)
1843 .unwrap();
1844 let result = strict_projection.strict_project(&predicate).unwrap();
1845 assert_eq!(
1846 result.to_string(),
1847 "((((pcol1 < 47) AND (pcol2 < 47)) AND (pcol3 < 47)) AND (pcol4 < 47)) AND (pcol5 < 47)"
1848 .to_string()
1849 );
1850
1851 let predicate = Reference::new("col1")
1853 .greater_than(Datum::date_from_str("2017-01-01").unwrap())
1854 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(1483228800000000)))
1855 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(1483228800000000)))
1856 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(1483228800000000000)))
1857 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(1483228800000000000)))
1858 .bind(schema.clone(), false)
1859 .unwrap();
1860 let result = strict_projection.strict_project(&predicate).unwrap();
1861 assert_eq!(
1862 result.to_string(),
1863 "((((pcol1 > 47) AND (pcol2 > 47)) AND (pcol3 > 47)) AND (pcol4 > 47)) AND (pcol5 > 47)"
1864 .to_string()
1865 );
1866
1867 let predicate = Reference::new("col1")
1869 .greater_than_or_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1870 .and(
1871 Reference::new("col2")
1872 .greater_than_or_equal_to(Datum::timestamp_micros(1483228800000000)),
1873 )
1874 .and(
1875 Reference::new("col3")
1876 .greater_than_or_equal_to(Datum::timestamptz_micros(1483228800000000)),
1877 )
1878 .and(
1879 Reference::new("col4")
1880 .greater_than_or_equal_to(Datum::timestamp_nanos(1483228800000000000)),
1881 )
1882 .and(
1883 Reference::new("col5")
1884 .greater_than_or_equal_to(Datum::timestamptz_nanos(1483228800000000000)),
1885 )
1886 .bind(schema.clone(), false)
1887 .unwrap();
1888 let result = strict_projection.strict_project(&predicate).unwrap();
1889 assert_eq!(
1890 result.to_string(),
1891 "((((pcol1 > 46) AND (pcol2 > 46)) AND (pcol3 > 46)) AND (pcol4 > 46)) AND (pcol5 > 46)"
1892 .to_string()
1893 );
1894
1895 let predicate = Reference::new("col1")
1897 .not_equal_to(Datum::date_from_str("2017-01-01").unwrap())
1898 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(1483228800000000)))
1899 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(1483228800000000)))
1900 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(1483228800000000000)))
1901 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(1483228800000000000)))
1902 .bind(schema.clone(), false)
1903 .unwrap();
1904 let result = strict_projection.strict_project(&predicate).unwrap();
1905 assert_eq!(result.to_string(), "((((pcol1 != 47) AND (pcol2 != 47)) AND (pcol3 != 47)) AND (pcol4 != 47)) AND (pcol5 != 47)".to_string());
1906
1907 let predicate = Reference::new("col1")
1909 .is_not_in(
1910 vec![
1911 Datum::date_from_str("2017-01-01").unwrap(),
1912 Datum::date_from_str("2016-12-31").unwrap(),
1913 ]
1914 .into_iter(),
1915 )
1916 .and(
1917 Reference::new("col2").is_not_in(
1918 vec![
1919 Datum::timestamp_micros(1483228800000000),
1920 Datum::timestamp_micros(1483142400000000),
1921 ]
1922 .into_iter(),
1923 ),
1924 )
1925 .and(
1926 Reference::new("col3").is_not_in(
1927 vec![
1928 Datum::timestamptz_micros(1483228800000000),
1929 Datum::timestamptz_micros(1483142400000000),
1930 ]
1931 .into_iter(),
1932 ),
1933 )
1934 .and(
1935 Reference::new("col4").is_not_in(
1936 vec![
1937 Datum::timestamp_nanos(1483228800000000000),
1938 Datum::timestamp_nanos(1483142400000000000),
1939 ]
1940 .into_iter(),
1941 ),
1942 )
1943 .and(
1944 Reference::new("col5").is_not_in(
1945 vec![
1946 Datum::timestamptz_nanos(1483228800000000000),
1947 Datum::timestamptz_nanos(1483142400000000000),
1948 ]
1949 .into_iter(),
1950 ),
1951 )
1952 .bind(schema.clone(), false)
1953 .unwrap();
1954 let result = strict_projection.strict_project(&predicate).unwrap();
1955 assert_eq!(result.to_string(), "((((pcol1 NOT IN (47, 46)) AND (pcol2 NOT IN (47, 46))) AND (pcol3 NOT IN (47, 46))) AND (pcol4 NOT IN (47, 46))) AND (pcol5 NOT IN (47, 46))".to_string());
1956
1957 let predicate = Reference::new("col1")
1959 .is_in(
1960 vec![
1961 Datum::date_from_str("2017-01-01").unwrap(),
1962 Datum::date_from_str("2017-12-31").unwrap(),
1963 ]
1964 .into_iter(),
1965 )
1966 .and(
1967 Reference::new("col2").is_in(
1968 vec![
1969 Datum::timestamp_micros(1483228800000000),
1970 Datum::timestamp_micros(1514764799000000),
1971 ]
1972 .into_iter(),
1973 ),
1974 )
1975 .bind(schema.clone(), false)
1976 .unwrap();
1977 let result = strict_projection.strict_project(&predicate).unwrap();
1978 assert_eq!(result.to_string(), "FALSE".to_string());
1979 }
1980
1981 #[tokio::test]
1982 async fn test_strict_projection_year_negative_lower_bound() {
1983 let schema = Arc::new(
1984 Schema::builder()
1985 .with_fields(vec![
1986 Arc::new(NestedField::required(
1987 1,
1988 "col1",
1989 Type::Primitive(PrimitiveType::Date),
1990 )),
1991 Arc::new(NestedField::required(
1992 2,
1993 "col2",
1994 Type::Primitive(PrimitiveType::Timestamp),
1995 )),
1996 Arc::new(NestedField::required(
1997 3,
1998 "col3",
1999 Type::Primitive(PrimitiveType::Timestamptz),
2000 )),
2001 Arc::new(NestedField::required(
2002 4,
2003 "col4",
2004 Type::Primitive(PrimitiveType::TimestampNs),
2005 )),
2006 Arc::new(NestedField::required(
2007 5,
2008 "col5",
2009 Type::Primitive(PrimitiveType::TimestamptzNs),
2010 )),
2011 ])
2012 .build()
2013 .unwrap(),
2014 );
2015
2016 let partition_spec = Arc::new(
2017 PartitionSpec::builder(schema.clone())
2018 .with_spec_id(1)
2019 .add_partition_field("col1", "pcol1", Transform::Year)
2020 .unwrap()
2021 .add_partition_field("col2", "pcol2", Transform::Year)
2022 .unwrap()
2023 .add_partition_field("col3", "pcol3", Transform::Year)
2024 .unwrap()
2025 .add_partition_field("col4", "pcol4", Transform::Year)
2026 .unwrap()
2027 .add_partition_field("col5", "pcol5", Transform::Year)
2028 .unwrap()
2029 .build()
2030 .unwrap(),
2031 );
2032
2033 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2034
2035 let predicate = Reference::new("col1")
2037 .less_than(Datum::date_from_str("1970-01-01").unwrap())
2038 .and(Reference::new("col2").less_than(Datum::timestamp_micros(0)))
2039 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(0)))
2040 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(0)))
2041 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(0)))
2042 .bind(schema.clone(), false)
2043 .unwrap();
2044 let result = strict_projection.strict_project(&predicate).unwrap();
2045 assert_eq!(
2046 result.to_string(),
2047 "((((pcol1 < 0) AND (pcol2 < 0)) AND (pcol3 < 0)) AND (pcol4 < 0)) AND (pcol5 < 0)"
2048 .to_string()
2049 );
2050
2051 let predicate = Reference::new("col1")
2053 .less_than_or_equal_to(Datum::date_from_str("1970-01-01").unwrap())
2054 .and(Reference::new("col2").less_than_or_equal_to(Datum::timestamp_micros(0)))
2055 .and(Reference::new("col3").less_than_or_equal_to(Datum::timestamptz_micros(0)))
2056 .and(Reference::new("col4").less_than_or_equal_to(Datum::timestamp_nanos(0)))
2057 .and(Reference::new("col5").less_than_or_equal_to(Datum::timestamptz_nanos(0)))
2058 .bind(schema.clone(), false)
2059 .unwrap();
2060 let result = strict_projection.strict_project(&predicate).unwrap();
2061 assert_eq!(
2062 result.to_string(),
2063 "((((pcol1 < 0) AND (pcol2 < 0)) AND (pcol3 < 0)) AND (pcol4 < 0)) AND (pcol5 < 0)"
2064 .to_string()
2065 );
2066
2067 let predicate = Reference::new("col1")
2069 .greater_than(Datum::date_from_str("1970-01-01").unwrap())
2070 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(0)))
2071 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(0)))
2072 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(0)))
2073 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(0)))
2074 .bind(schema.clone(), false)
2075 .unwrap();
2076 let result = strict_projection.strict_project(&predicate).unwrap();
2077 assert_eq!(
2078 result.to_string(),
2079 "((((pcol1 > 0) AND (pcol2 > 0)) AND (pcol3 > 0)) AND (pcol4 > 0)) AND (pcol5 > 0)"
2080 .to_string()
2081 );
2082
2083 let predicate = Reference::new("col1")
2085 .greater_than_or_equal_to(Datum::date_from_str("1970-01-01").unwrap())
2086 .and(Reference::new("col2").greater_than_or_equal_to(Datum::timestamp_micros(0)))
2087 .and(Reference::new("col3").greater_than_or_equal_to(Datum::timestamptz_micros(0)))
2088 .and(Reference::new("col4").greater_than_or_equal_to(Datum::timestamp_nanos(0)))
2089 .and(Reference::new("col5").greater_than_or_equal_to(Datum::timestamptz_nanos(0)))
2090 .bind(schema.clone(), false)
2091 .unwrap();
2092 let result = strict_projection.strict_project(&predicate).unwrap();
2093 assert_eq!(
2094 result.to_string(),
2095 "((((pcol1 > -1) AND (pcol2 > -1)) AND (pcol3 > -1)) AND (pcol4 > -1)) AND (pcol5 > -1)"
2096 .to_string()
2097 );
2098
2099 let predicate = Reference::new("col1")
2101 .not_equal_to(Datum::date_from_str("1970-01-01").unwrap())
2102 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(0)))
2103 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(0)))
2104 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(0)))
2105 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(0)))
2106 .bind(schema.clone(), false)
2107 .unwrap();
2108 let result = strict_projection.strict_project(&predicate).unwrap();
2109 assert_eq!(result.to_string(), "((((pcol1 != 0) AND (pcol2 != 0)) AND (pcol3 != 0)) AND (pcol4 != 0)) AND (pcol5 != 0)".to_string());
2110
2111 let predicate = Reference::new("col1")
2113 .is_not_in(
2114 vec![
2115 Datum::date_from_str("1970-01-01").unwrap(),
2116 Datum::date_from_str("1970-12-31").unwrap(),
2117 ]
2118 .into_iter(),
2119 )
2120 .and(
2121 Reference::new("col2").is_not_in(
2122 vec![
2123 Datum::timestamp_micros(0),
2124 Datum::timestamp_micros(3153599999000000),
2125 ]
2126 .into_iter(),
2127 ),
2128 )
2129 .and(
2130 Reference::new("col3").is_not_in(
2131 vec![
2132 Datum::timestamptz_micros(0),
2133 Datum::timestamptz_micros(3153599999000000),
2134 ]
2135 .into_iter(),
2136 ),
2137 )
2138 .and(
2139 Reference::new("col4").is_not_in(
2140 vec![
2141 Datum::timestamp_nanos(0),
2142 Datum::timestamp_nanos(3153599999000000000),
2143 ]
2144 .into_iter(),
2145 ),
2146 )
2147 .and(
2148 Reference::new("col5").is_not_in(
2149 vec![
2150 Datum::timestamptz_nanos(0),
2151 Datum::timestamptz_nanos(3153599999000000000),
2152 ]
2153 .into_iter(),
2154 ),
2155 )
2156 .bind(schema.clone(), false)
2157 .unwrap();
2158 let result = strict_projection.strict_project(&predicate).unwrap();
2159 assert_eq!(result.to_string(), "((((pcol1 NOT IN (0)) AND (pcol2 NOT IN (0, 99))) AND (pcol3 NOT IN (0, 99))) AND (pcol4 NOT IN (0, 99))) AND (pcol5 NOT IN (0, 99))".to_string());
2160
2161 let predicate = Reference::new("col1")
2163 .is_in(
2164 vec![
2165 Datum::date_from_str("1970-01-01").unwrap(),
2166 Datum::date_from_str("1970-12-31").unwrap(),
2167 ]
2168 .into_iter(),
2169 )
2170 .and(
2171 Reference::new("col2").is_in(
2172 vec![
2173 Datum::timestamp_micros(0),
2174 Datum::timestamp_micros(3153599999000000),
2175 ]
2176 .into_iter(),
2177 ),
2178 )
2179 .bind(schema.clone(), false)
2180 .unwrap();
2181 let result = strict_projection.strict_project(&predicate).unwrap();
2182 assert_eq!(result.to_string(), "FALSE".to_string());
2183 }
2184
2185 #[tokio::test]
2186 async fn test_strict_projection_year_upper_bound() {
2187 let schema = Arc::new(
2188 Schema::builder()
2189 .with_fields(vec![
2190 Arc::new(NestedField::required(
2191 1,
2192 "col1",
2193 Type::Primitive(PrimitiveType::Date),
2194 )),
2195 Arc::new(NestedField::required(
2196 2,
2197 "col2",
2198 Type::Primitive(PrimitiveType::Timestamp),
2199 )),
2200 Arc::new(NestedField::required(
2201 3,
2202 "col3",
2203 Type::Primitive(PrimitiveType::Timestamptz),
2204 )),
2205 Arc::new(NestedField::required(
2206 4,
2207 "col4",
2208 Type::Primitive(PrimitiveType::TimestampNs),
2209 )),
2210 Arc::new(NestedField::required(
2211 5,
2212 "col5",
2213 Type::Primitive(PrimitiveType::TimestamptzNs),
2214 )),
2215 ])
2216 .build()
2217 .unwrap(),
2218 );
2219
2220 let partition_spec = Arc::new(
2221 PartitionSpec::builder(schema.clone())
2222 .with_spec_id(1)
2223 .add_partition_field("col1", "pcol1", Transform::Year)
2224 .unwrap()
2225 .add_partition_field("col2", "pcol2", Transform::Year)
2226 .unwrap()
2227 .add_partition_field("col3", "pcol3", Transform::Year)
2228 .unwrap()
2229 .add_partition_field("col4", "pcol4", Transform::Year)
2230 .unwrap()
2231 .add_partition_field("col5", "pcol5", Transform::Year)
2232 .unwrap()
2233 .build()
2234 .unwrap(),
2235 );
2236
2237 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2238
2239 let predicate = Reference::new("col1")
2241 .less_than(Datum::date_from_str("2017-12-31").unwrap())
2242 .and(Reference::new("col2").less_than(Datum::timestamp_micros(1514764799000000)))
2243 .and(Reference::new("col3").less_than(Datum::timestamptz_micros(1514764799000000)))
2244 .and(Reference::new("col4").less_than(Datum::timestamp_nanos(1514764799000000000)))
2245 .and(Reference::new("col5").less_than(Datum::timestamptz_nanos(1514764799000000000)))
2246 .bind(schema.clone(), false)
2247 .unwrap();
2248 let result = strict_projection.strict_project(&predicate).unwrap();
2249 assert_eq!(
2250 result.to_string(),
2251 "((((pcol1 < 47) AND (pcol2 < 47)) AND (pcol3 < 47)) AND (pcol4 < 47)) AND (pcol5 < 47)"
2252 .to_string()
2253 );
2254
2255 let predicate = Reference::new("col1")
2257 .less_than_or_equal_to(Datum::date_from_str("2017-12-31").unwrap())
2258 .and(
2259 Reference::new("col2")
2260 .less_than_or_equal_to(Datum::timestamp_micros(1514764799000000)),
2261 )
2262 .and(
2263 Reference::new("col3")
2264 .less_than_or_equal_to(Datum::timestamptz_micros(1514764799000000)),
2265 )
2266 .and(
2267 Reference::new("col4")
2268 .less_than_or_equal_to(Datum::timestamp_nanos(1514764799000000000)),
2269 )
2270 .and(
2271 Reference::new("col5")
2272 .less_than_or_equal_to(Datum::timestamptz_nanos(1514764799000000000)),
2273 )
2274 .bind(schema.clone(), false)
2275 .unwrap();
2276 let result = strict_projection.strict_project(&predicate).unwrap();
2277 assert_eq!(
2278 result.to_string(),
2279 "((((pcol1 < 48) AND (pcol2 < 47)) AND (pcol3 < 47)) AND (pcol4 < 47)) AND (pcol5 < 47)"
2280 .to_string()
2281 );
2282
2283 let predicate = Reference::new("col1")
2285 .greater_than(Datum::date_from_str("2017-12-31").unwrap())
2286 .and(Reference::new("col2").greater_than(Datum::timestamp_micros(1514764799000000)))
2287 .and(Reference::new("col3").greater_than(Datum::timestamptz_micros(1514764799000000)))
2288 .and(Reference::new("col4").greater_than(Datum::timestamp_nanos(1514764799000000000)))
2289 .and(Reference::new("col5").greater_than(Datum::timestamptz_nanos(1514764799000000000)))
2290 .bind(schema.clone(), false)
2291 .unwrap();
2292 let result = strict_projection.strict_project(&predicate).unwrap();
2293 assert_eq!(
2294 result.to_string(),
2295 "((((pcol1 > 47) AND (pcol2 > 47)) AND (pcol3 > 47)) AND (pcol4 > 47)) AND (pcol5 > 47)"
2296 .to_string()
2297 );
2298
2299 let predicate = Reference::new("col1")
2301 .greater_than_or_equal_to(Datum::date_from_str("2017-12-31").unwrap())
2302 .and(
2303 Reference::new("col2")
2304 .greater_than_or_equal_to(Datum::timestamp_micros(1514764799000000)),
2305 )
2306 .and(
2307 Reference::new("col3")
2308 .greater_than_or_equal_to(Datum::timestamptz_micros(1514764799000000)),
2309 )
2310 .and(
2311 Reference::new("col4")
2312 .greater_than_or_equal_to(Datum::timestamp_nanos(1514764799000000000)),
2313 )
2314 .and(
2315 Reference::new("col5")
2316 .greater_than_or_equal_to(Datum::timestamptz_nanos(1514764799000000000)),
2317 )
2318 .bind(schema.clone(), false)
2319 .unwrap();
2320 let result = strict_projection.strict_project(&predicate).unwrap();
2321 assert_eq!(
2322 result.to_string(),
2323 "((((pcol1 > 47) AND (pcol2 > 47)) AND (pcol3 > 47)) AND (pcol4 > 47)) AND (pcol5 > 47)"
2324 .to_string()
2325 );
2326
2327 let predicate = Reference::new("col1")
2329 .not_equal_to(Datum::date_from_str("2017-12-31").unwrap())
2330 .and(Reference::new("col2").not_equal_to(Datum::timestamp_micros(1514764799000000)))
2331 .and(Reference::new("col3").not_equal_to(Datum::timestamptz_micros(1514764799000000)))
2332 .and(Reference::new("col4").not_equal_to(Datum::timestamp_nanos(1514764799000000000)))
2333 .and(Reference::new("col5").not_equal_to(Datum::timestamptz_nanos(1514764799000000000)))
2334 .bind(schema.clone(), false)
2335 .unwrap();
2336 let result = strict_projection.strict_project(&predicate).unwrap();
2337 assert_eq!(result.to_string(), "((((pcol1 != 47) AND (pcol2 != 47)) AND (pcol3 != 47)) AND (pcol4 != 47)) AND (pcol5 != 47)".to_string());
2338
2339 let predicate = Reference::new("col1")
2341 .is_not_in(
2342 vec![
2343 Datum::date_from_str("2017-12-31").unwrap(),
2344 Datum::date_from_str("2016-01-01").unwrap(),
2345 ]
2346 .into_iter(),
2347 )
2348 .and(
2349 Reference::new("col2").is_not_in(
2350 vec![
2351 Datum::timestamp_micros(1514764799000000),
2352 Datum::timestamp_micros(1451606400000000),
2353 ]
2354 .into_iter(),
2355 ),
2356 )
2357 .and(
2358 Reference::new("col3").is_not_in(
2359 vec![
2360 Datum::timestamptz_micros(1514764799000000),
2361 Datum::timestamptz_micros(1451606400000000),
2362 ]
2363 .into_iter(),
2364 ),
2365 )
2366 .and(
2367 Reference::new("col4").is_not_in(
2368 vec![
2369 Datum::timestamp_nanos(1514764799000000000),
2370 Datum::timestamp_nanos(1451606400000000000),
2371 ]
2372 .into_iter(),
2373 ),
2374 )
2375 .and(
2376 Reference::new("col5").is_not_in(
2377 vec![
2378 Datum::timestamptz_nanos(1514764799000000000),
2379 Datum::timestamptz_nanos(1451606400000000000),
2380 ]
2381 .into_iter(),
2382 ),
2383 )
2384 .bind(schema.clone(), false)
2385 .unwrap();
2386 let result = strict_projection.strict_project(&predicate).unwrap();
2387 assert_eq!(result.to_string(), "((((pcol1 NOT IN (47, 46)) AND (pcol2 NOT IN (47, 46))) AND (pcol3 NOT IN (47, 46))) AND (pcol4 NOT IN (47, 46))) AND (pcol5 NOT IN (47, 46))".to_string());
2388
2389 let predicate = Reference::new("col1")
2391 .is_in(
2392 vec![
2393 Datum::date_from_str("2017-12-31").unwrap(),
2394 Datum::date_from_str("2017-01-01").unwrap(),
2395 ]
2396 .into_iter(),
2397 )
2398 .and(
2399 Reference::new("col2").is_in(
2400 vec![
2401 Datum::timestamp_micros(1514764799000000),
2402 Datum::timestamp_micros(1483228800000000),
2403 ]
2404 .into_iter(),
2405 ),
2406 )
2407 .bind(schema.clone(), false)
2408 .unwrap();
2409 let result = strict_projection.strict_project(&predicate).unwrap();
2410 assert_eq!(result.to_string(), "FALSE".to_string());
2411 }
2412
2413 #[tokio::test]
2414 async fn test_strict_projection_bucket() {
2415 let schema = Arc::new(
2417 Schema::builder()
2418 .with_fields(vec![
2419 Arc::new(NestedField::required(
2420 1,
2421 "col1",
2422 Type::Primitive(PrimitiveType::Int),
2423 )),
2424 Arc::new(NestedField::required(
2425 2,
2426 "col2",
2427 Type::Primitive(PrimitiveType::Long),
2428 )),
2429 Arc::new(NestedField::required(
2430 3,
2431 "col3",
2432 Type::Primitive(PrimitiveType::Decimal {
2433 precision: 9,
2434 scale: 2,
2435 }),
2436 )),
2437 Arc::new(NestedField::required(
2438 4,
2439 "col4",
2440 Type::Primitive(PrimitiveType::String),
2441 )),
2442 Arc::new(NestedField::required(
2443 5,
2444 "col5",
2445 Type::Primitive(PrimitiveType::Binary),
2446 )),
2447 Arc::new(NestedField::required(
2448 6,
2449 "col6",
2450 Type::Primitive(PrimitiveType::Uuid),
2451 )),
2452 ])
2453 .build()
2454 .unwrap(),
2455 );
2456
2457 let partition_spec = Arc::new(
2458 PartitionSpec::builder(schema.clone())
2459 .with_spec_id(1)
2460 .add_partition_field("col1", "pcol1", Transform::Bucket(10))
2461 .unwrap()
2462 .add_partition_field("col2", "pcol2", Transform::Bucket(10))
2463 .unwrap()
2464 .add_partition_field("col3", "pcol3", Transform::Bucket(10))
2465 .unwrap()
2466 .add_partition_field("col4", "pcol4", Transform::Bucket(10))
2467 .unwrap()
2468 .add_partition_field("col5", "pcol5", Transform::Bucket(10))
2469 .unwrap()
2470 .add_partition_field("col6", "pcol6", Transform::Bucket(10))
2471 .unwrap()
2472 .build()
2473 .unwrap(),
2474 );
2475
2476 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2477
2478 let predicate = Reference::new("col1")
2480 .not_equal_to(Datum::int(100))
2481 .and(Reference::new("col2").not_equal_to(Datum::long(100)))
2482 .and(Reference::new("col3").not_equal_to(Datum::new(
2483 PrimitiveType::Decimal {
2484 precision: 9,
2485 scale: 2,
2486 },
2487 PrimitiveLiteral::Int128(10000),
2488 )))
2489 .and(Reference::new("col4").not_equal_to(Datum::string("abcdefg")))
2490 .and(Reference::new("col5").not_equal_to(Datum::binary("abcdefg".as_bytes().to_vec())))
2491 .and(Reference::new("col6").not_equal_to(Datum::uuid(
2492 Uuid::parse_str("00000000-0000-007b-0000-0000000001c8").unwrap(),
2493 )))
2494 .bind(schema.clone(), false)
2495 .unwrap();
2496 let result = strict_projection.strict_project(&predicate).unwrap();
2497 assert_eq!(result.to_string(), "(((((pcol1 != 6) AND (pcol2 != 6)) AND (pcol3 != 2)) AND (pcol4 != 4)) AND (pcol5 != 4)) AND (pcol6 != 4)".to_string());
2498
2499 let predicate = Reference::new("col1")
2501 .equal_to(Datum::int(100))
2502 .and(Reference::new("col2").less_than(Datum::long(100)))
2503 .and(Reference::new("col3").less_than_or_equal_to(Datum::new(
2504 PrimitiveType::Decimal {
2505 precision: 9,
2506 scale: 2,
2507 },
2508 PrimitiveLiteral::Int128(10000),
2509 )))
2510 .and(Reference::new("col4").greater_than(Datum::string("abcdefg")))
2511 .and(
2512 Reference::new("col5")
2513 .greater_than_or_equal_to(Datum::binary("abcdefg".as_bytes().to_vec())),
2514 )
2515 .and(
2516 Reference::new("col6").is_in(
2517 vec![
2518 Datum::uuid(
2519 Uuid::parse_str("00000000-0000-007b-0000-0000000001c8").unwrap(),
2520 ),
2521 Datum::uuid(
2522 Uuid::parse_str("00000000-0000-007b-0000-0000000001c9").unwrap(),
2523 ),
2524 ]
2525 .into_iter(),
2526 ),
2527 )
2528 .bind(schema.clone(), false)
2529 .unwrap();
2530 let result = strict_projection.strict_project(&predicate).unwrap();
2531 assert_eq!(result.to_string(), "FALSE".to_string());
2532
2533 let predicate =
2535 Reference::new("col1")
2536 .is_not_in(vec![Datum::int(99), Datum::int(100), Datum::int(101)].into_iter())
2537 .and(Reference::new("col2").is_not_in(
2538 vec![Datum::long(99), Datum::long(100), Datum::long(101)].into_iter(),
2539 ))
2540 .and(
2541 Reference::new("col3").is_not_in(
2542 vec![
2543 Datum::new(
2544 PrimitiveType::Decimal {
2545 precision: 9,
2546 scale: 2,
2547 },
2548 PrimitiveLiteral::Int128(9900),
2549 ),
2550 Datum::new(
2551 PrimitiveType::Decimal {
2552 precision: 9,
2553 scale: 2,
2554 },
2555 PrimitiveLiteral::Int128(10000),
2556 ),
2557 Datum::new(
2558 PrimitiveType::Decimal {
2559 precision: 9,
2560 scale: 2,
2561 },
2562 PrimitiveLiteral::Int128(10100),
2563 ),
2564 ]
2565 .into_iter(),
2566 ),
2567 )
2568 .and(Reference::new("col4").is_not_in(
2569 vec![Datum::string("abcdefg"), Datum::string("abcdefgabc")].into_iter(),
2570 ))
2571 .and(
2572 Reference::new("col5").is_not_in(
2573 vec![
2574 Datum::binary("abcdefg".as_bytes().to_vec()),
2575 Datum::binary("abcdehij".as_bytes().to_vec()),
2576 ]
2577 .into_iter(),
2578 ),
2579 )
2580 .and(
2581 Reference::new("col6").is_not_in(
2582 vec![
2583 Datum::uuid(
2584 Uuid::parse_str("00000000-0000-007b-0000-0000000001c8").unwrap(),
2585 ),
2586 Datum::uuid(
2587 Uuid::parse_str("00000000-0000-01c8-0000-00000000007b").unwrap(),
2588 ),
2589 ]
2590 .into_iter(),
2591 ),
2592 )
2593 .bind(schema.clone(), false)
2594 .unwrap();
2595 let result = strict_projection.strict_project(&predicate).unwrap();
2596 assert_eq!(result.to_string(), "(((((pcol1 NOT IN (8, 7, 6)) AND (pcol2 NOT IN (8, 7, 6))) AND (pcol3 NOT IN (6, 2))) AND (pcol4 NOT IN (9, 4))) AND (pcol5 NOT IN (4, 6))) AND (pcol6 NOT IN (4, 6))".to_string());
2597 }
2598
2599 #[tokio::test]
2600 async fn test_strict_projection_identity() {
2601 let schema = Arc::new(
2602 Schema::builder()
2603 .with_fields(vec![Arc::new(NestedField::optional(
2604 1,
2605 "col1",
2606 Type::Primitive(PrimitiveType::Long),
2607 ))])
2608 .build()
2609 .unwrap(),
2610 );
2611
2612 let partition_spec = Arc::new(
2613 PartitionSpec::builder(schema.clone())
2614 .with_spec_id(1)
2615 .add_partition_field("col1", "pcol1", Transform::Identity)
2616 .unwrap()
2617 .build()
2618 .unwrap(),
2619 );
2620
2621 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2622
2623 let predicate = Reference::new("col1")
2625 .is_not_null()
2626 .bind(schema.clone(), false)
2627 .unwrap();
2628 let result = strict_projection.strict_project(&predicate).unwrap();
2629 assert_eq!(result.to_string(), "pcol1 IS NOT NULL".to_string());
2630
2631 let predicate = Reference::new("col1")
2633 .is_null()
2634 .bind(schema.clone(), false)
2635 .unwrap();
2636 let result = strict_projection.strict_project(&predicate).unwrap();
2637 assert_eq!(result.to_string(), "pcol1 IS NULL".to_string());
2638
2639 let predicate = Reference::new("col1")
2641 .less_than(Datum::long(100))
2642 .bind(schema.clone(), false)
2643 .unwrap();
2644 let result = strict_projection.strict_project(&predicate).unwrap();
2645 assert_eq!(result.to_string(), "pcol1 < 100".to_string());
2646
2647 let predicate = Reference::new("col1")
2649 .less_than_or_equal_to(Datum::long(100))
2650 .bind(schema.clone(), false)
2651 .unwrap();
2652 let result = strict_projection.strict_project(&predicate).unwrap();
2653 assert_eq!(result.to_string(), "pcol1 <= 100".to_string());
2654
2655 let predicate = Reference::new("col1")
2657 .greater_than(Datum::long(100))
2658 .bind(schema.clone(), false)
2659 .unwrap();
2660 let result = strict_projection.strict_project(&predicate).unwrap();
2661 assert_eq!(result.to_string(), "pcol1 > 100".to_string());
2662
2663 let predicate = Reference::new("col1")
2665 .greater_than_or_equal_to(Datum::long(100))
2666 .bind(schema.clone(), false)
2667 .unwrap();
2668 let result = strict_projection.strict_project(&predicate).unwrap();
2669 assert_eq!(result.to_string(), "pcol1 >= 100".to_string());
2670
2671 let predicate = Reference::new("col1")
2673 .equal_to(Datum::long(100))
2674 .bind(schema.clone(), false)
2675 .unwrap();
2676 let result = strict_projection.strict_project(&predicate).unwrap();
2677 assert_eq!(result.to_string(), "pcol1 = 100".to_string());
2678
2679 let predicate = Reference::new("col1")
2681 .not_equal_to(Datum::long(100))
2682 .bind(schema.clone(), false)
2683 .unwrap();
2684 let result = strict_projection.strict_project(&predicate).unwrap();
2685 assert_eq!(result.to_string(), "pcol1 != 100".to_string());
2686
2687 let predicate = Reference::new("col1")
2689 .is_in(vec![Datum::long(100), Datum::long(101)].into_iter())
2690 .bind(schema.clone(), false)
2691 .unwrap();
2692 let result = strict_projection.strict_project(&predicate).unwrap();
2693 assert_eq!(result.to_string(), "pcol1 IN (101, 100)".to_string());
2694
2695 let predicate = Reference::new("col1")
2697 .is_not_in(vec![Datum::long(100), Datum::long(101)].into_iter())
2698 .bind(schema.clone(), false)
2699 .unwrap();
2700 let result = strict_projection.strict_project(&predicate).unwrap();
2701 assert_eq!(result.to_string(), "pcol1 NOT IN (101, 100)".to_string());
2702 }
2703
2704 #[tokio::test]
2705 async fn test_strict_projection_truncate_lower_bound() {
2706 let schema = Arc::new(
2708 Schema::builder()
2709 .with_fields(vec![
2710 Arc::new(NestedField::required(
2711 1,
2712 "col1",
2713 Type::Primitive(PrimitiveType::Int),
2714 )),
2715 Arc::new(NestedField::required(
2716 2,
2717 "col2",
2718 Type::Primitive(PrimitiveType::Long),
2719 )),
2720 Arc::new(NestedField::required(
2721 3,
2722 "col3",
2723 Type::Primitive(PrimitiveType::Decimal {
2724 precision: 9,
2725 scale: 2,
2726 }),
2727 )),
2728 ])
2729 .build()
2730 .unwrap(),
2731 );
2732
2733 let partition_spec = Arc::new(
2734 PartitionSpec::builder(schema.clone())
2735 .with_spec_id(1)
2736 .add_partition_field("col1", "pcol1", Transform::Truncate(10))
2737 .unwrap()
2738 .add_partition_field("col2", "pcol2", Transform::Truncate(10))
2739 .unwrap()
2740 .add_partition_field("col3", "pcol3", Transform::Truncate(10))
2741 .unwrap()
2742 .build()
2743 .unwrap(),
2744 );
2745
2746 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2747
2748 let predicate = Reference::new("col1")
2750 .less_than(Datum::int(100))
2751 .and(Reference::new("col2").less_than(Datum::long(100)))
2752 .and(Reference::new("col3").less_than(Datum::new(
2753 PrimitiveType::Decimal {
2754 precision: 9,
2755 scale: 2,
2756 },
2757 PrimitiveLiteral::Int128(10000),
2758 )))
2759 .bind(schema.clone(), false)
2760 .unwrap();
2761 let result = strict_projection.strict_project(&predicate).unwrap();
2762 assert_eq!(
2763 result.to_string(),
2764 "((pcol1 < 100) AND (pcol2 < 100)) AND (pcol3 < 10000)".to_string()
2765 );
2766
2767 let predicate = Reference::new("col1")
2769 .less_than_or_equal_to(Datum::int(100))
2770 .and(Reference::new("col2").less_than_or_equal_to(Datum::long(100)))
2771 .and(Reference::new("col3").less_than_or_equal_to(Datum::new(
2772 PrimitiveType::Decimal {
2773 precision: 9,
2774 scale: 2,
2775 },
2776 PrimitiveLiteral::Int128(10000),
2777 )))
2778 .bind(schema.clone(), false)
2779 .unwrap();
2780 let result = strict_projection.strict_project(&predicate).unwrap();
2781 assert_eq!(
2782 result.to_string(),
2783 "((pcol1 < 100) AND (pcol2 < 100)) AND (pcol3 < 10000)".to_string()
2784 );
2785
2786 let predicate = Reference::new("col1")
2788 .greater_than(Datum::int(100))
2789 .and(Reference::new("col2").greater_than(Datum::long(100)))
2790 .and(Reference::new("col3").greater_than(Datum::new(
2791 PrimitiveType::Decimal {
2792 precision: 9,
2793 scale: 2,
2794 },
2795 PrimitiveLiteral::Int128(10000),
2796 )))
2797 .bind(schema.clone(), false)
2798 .unwrap();
2799 let result = strict_projection.strict_project(&predicate).unwrap();
2800 assert_eq!(
2801 result.to_string(),
2802 "((pcol1 > 100) AND (pcol2 > 100)) AND (pcol3 > 10000)".to_string()
2803 );
2804
2805 let predicate = Reference::new("col1")
2807 .greater_than_or_equal_to(Datum::int(100))
2808 .and(Reference::new("col2").greater_than_or_equal_to(Datum::long(100)))
2809 .and(Reference::new("col3").greater_than_or_equal_to(Datum::new(
2810 PrimitiveType::Decimal {
2811 precision: 9,
2812 scale: 2,
2813 },
2814 PrimitiveLiteral::Int128(10000),
2815 )))
2816 .bind(schema.clone(), false)
2817 .unwrap();
2818 let result = strict_projection.strict_project(&predicate).unwrap();
2819 assert_eq!(
2820 result.to_string(),
2821 "((pcol1 > 90) AND (pcol2 > 90)) AND (pcol3 > 9990)".to_string()
2822 );
2823
2824 let predicate = Reference::new("col1")
2826 .not_equal_to(Datum::int(100))
2827 .and(Reference::new("col2").not_equal_to(Datum::long(100)))
2828 .and(Reference::new("col3").not_equal_to(Datum::new(
2829 PrimitiveType::Decimal {
2830 precision: 9,
2831 scale: 2,
2832 },
2833 PrimitiveLiteral::Int128(10000),
2834 )))
2835 .bind(schema.clone(), false)
2836 .unwrap();
2837 let result = strict_projection.strict_project(&predicate).unwrap();
2838 assert_eq!(
2839 result.to_string(),
2840 "((pcol1 != 100) AND (pcol2 != 100)) AND (pcol3 != 10000)".to_string()
2841 );
2842
2843 let predicate =
2845 Reference::new("col1")
2846 .is_not_in(vec![Datum::int(99), Datum::int(100), Datum::int(101)].into_iter())
2847 .and(Reference::new("col2").is_not_in(
2848 vec![Datum::long(99), Datum::long(100), Datum::long(101)].into_iter(),
2849 ))
2850 .and(
2851 Reference::new("col3").is_not_in(
2852 vec![
2853 Datum::new(
2854 PrimitiveType::Decimal {
2855 precision: 9,
2856 scale: 2,
2857 },
2858 PrimitiveLiteral::Int128(9900),
2859 ),
2860 Datum::new(
2861 PrimitiveType::Decimal {
2862 precision: 9,
2863 scale: 2,
2864 },
2865 PrimitiveLiteral::Int128(10000),
2866 ),
2867 Datum::new(
2868 PrimitiveType::Decimal {
2869 precision: 9,
2870 scale: 2,
2871 },
2872 PrimitiveLiteral::Int128(10100),
2873 ),
2874 ]
2875 .into_iter(),
2876 ),
2877 )
2878 .bind(schema.clone(), false)
2879 .unwrap();
2880 let result = strict_projection.strict_project(&predicate).unwrap();
2881 assert_eq!(
2882 result.to_string(),
2883 "((pcol1 NOT IN (100, 90)) AND (pcol2 NOT IN (100, 90))) AND (pcol3 NOT IN (10000, 10100, 9900))"
2884 .to_string()
2885 );
2886
2887 let predicate = Reference::new("col1")
2889 .is_in(vec![Datum::int(99), Datum::int(100), Datum::int(101)].into_iter())
2890 .and(
2891 Reference::new("col2")
2892 .is_in(vec![Datum::long(99), Datum::long(100), Datum::long(101)].into_iter()),
2893 )
2894 .and(
2895 Reference::new("col3").is_in(
2896 vec![
2897 Datum::new(
2898 PrimitiveType::Decimal {
2899 precision: 9,
2900 scale: 2,
2901 },
2902 PrimitiveLiteral::Int128(9900),
2903 ),
2904 Datum::new(
2905 PrimitiveType::Decimal {
2906 precision: 9,
2907 scale: 2,
2908 },
2909 PrimitiveLiteral::Int128(10000),
2910 ),
2911 Datum::new(
2912 PrimitiveType::Decimal {
2913 precision: 9,
2914 scale: 2,
2915 },
2916 PrimitiveLiteral::Int128(10100),
2917 ),
2918 ]
2919 .into_iter(),
2920 ),
2921 )
2922 .bind(schema.clone(), false)
2923 .unwrap();
2924 let result = strict_projection.strict_project(&predicate).unwrap();
2925 assert_eq!(result.to_string(), "FALSE".to_string());
2926 }
2927
2928 #[tokio::test]
2929 async fn test_strict_projection_truncate_upper_bound() {
2930 let schema = Arc::new(
2931 Schema::builder()
2932 .with_fields(vec![
2933 Arc::new(NestedField::required(
2934 1,
2935 "col1",
2936 Type::Primitive(PrimitiveType::Int),
2937 )),
2938 Arc::new(NestedField::required(
2939 2,
2940 "col2",
2941 Type::Primitive(PrimitiveType::Long),
2942 )),
2943 Arc::new(NestedField::required(
2944 3,
2945 "col3",
2946 Type::Primitive(PrimitiveType::Decimal {
2947 precision: 9,
2948 scale: 2,
2949 }),
2950 )),
2951 ])
2952 .build()
2953 .unwrap(),
2954 );
2955
2956 let partition_spec = Arc::new(
2957 PartitionSpec::builder(schema.clone())
2958 .with_spec_id(1)
2959 .add_partition_field("col1", "pcol1", Transform::Truncate(10))
2960 .unwrap()
2961 .add_partition_field("col2", "pcol2", Transform::Truncate(10))
2962 .unwrap()
2963 .add_partition_field("col3", "pcol3", Transform::Truncate(10))
2964 .unwrap()
2965 .build()
2966 .unwrap(),
2967 );
2968
2969 let mut strict_projection = StrictProjection::new(partition_spec.clone());
2970
2971 let predicate = Reference::new("col1")
2973 .less_than(Datum::int(99))
2974 .and(Reference::new("col2").less_than(Datum::long(99)))
2975 .and(Reference::new("col3").less_than(Datum::new(
2976 PrimitiveType::Decimal {
2977 precision: 9,
2978 scale: 2,
2979 },
2980 PrimitiveLiteral::Int128(9999),
2981 )))
2982 .bind(schema.clone(), false)
2983 .unwrap();
2984 let result = strict_projection.strict_project(&predicate).unwrap();
2985 assert_eq!(
2986 result.to_string(),
2987 "((pcol1 < 90) AND (pcol2 < 90)) AND (pcol3 < 9990)".to_string()
2988 );
2989
2990 let predicate = Reference::new("col1")
2992 .less_than_or_equal_to(Datum::int(99))
2993 .and(Reference::new("col2").less_than_or_equal_to(Datum::long(99)))
2994 .and(Reference::new("col3").less_than_or_equal_to(Datum::new(
2995 PrimitiveType::Decimal {
2996 precision: 9,
2997 scale: 2,
2998 },
2999 PrimitiveLiteral::Int128(9999),
3000 )))
3001 .bind(schema.clone(), false)
3002 .unwrap();
3003 let result = strict_projection.strict_project(&predicate).unwrap();
3004 assert_eq!(
3005 result.to_string(),
3006 "((pcol1 < 100) AND (pcol2 < 100)) AND (pcol3 < 10000)".to_string()
3007 );
3008
3009 let predicate = Reference::new("col1")
3011 .greater_than(Datum::int(99))
3012 .and(Reference::new("col2").greater_than(Datum::long(99)))
3013 .and(Reference::new("col3").greater_than(Datum::new(
3014 PrimitiveType::Decimal {
3015 precision: 9,
3016 scale: 2,
3017 },
3018 PrimitiveLiteral::Int128(9999),
3019 )))
3020 .bind(schema.clone(), false)
3021 .unwrap();
3022 let result = strict_projection.strict_project(&predicate).unwrap();
3023 assert_eq!(
3024 result.to_string(),
3025 "((pcol1 > 90) AND (pcol2 > 90)) AND (pcol3 > 9990)".to_string()
3026 );
3027
3028 let predicate = Reference::new("col1")
3030 .greater_than_or_equal_to(Datum::int(99))
3031 .and(Reference::new("col2").greater_than_or_equal_to(Datum::long(99)))
3032 .and(Reference::new("col3").greater_than_or_equal_to(Datum::new(
3033 PrimitiveType::Decimal {
3034 precision: 9,
3035 scale: 2,
3036 },
3037 PrimitiveLiteral::Int128(9999),
3038 )))
3039 .bind(schema.clone(), false)
3040 .unwrap();
3041 let result = strict_projection.strict_project(&predicate).unwrap();
3042 assert_eq!(
3043 result.to_string(),
3044 "((pcol1 > 90) AND (pcol2 > 90)) AND (pcol3 > 9990)".to_string()
3045 );
3046
3047 let predicate = Reference::new("col1")
3049 .not_equal_to(Datum::int(99))
3050 .and(Reference::new("col2").not_equal_to(Datum::long(99)))
3051 .and(Reference::new("col3").not_equal_to(Datum::new(
3052 PrimitiveType::Decimal {
3053 precision: 9,
3054 scale: 2,
3055 },
3056 PrimitiveLiteral::Int128(9999),
3057 )))
3058 .bind(schema.clone(), false)
3059 .unwrap();
3060 let result = strict_projection.strict_project(&predicate).unwrap();
3061 assert_eq!(
3062 result.to_string(),
3063 "((pcol1 != 90) AND (pcol2 != 90)) AND (pcol3 != 9990)".to_string()
3064 );
3065
3066 let predicate =
3068 Reference::new("col1")
3069 .is_not_in(vec![Datum::int(99), Datum::int(100), Datum::int(98)].into_iter())
3070 .and(Reference::new("col2").is_not_in(
3071 vec![Datum::long(99), Datum::long(100), Datum::long(98)].into_iter(),
3072 ))
3073 .and(
3074 Reference::new("col3").is_not_in(
3075 vec![
3076 Datum::new(
3077 PrimitiveType::Decimal {
3078 precision: 9,
3079 scale: 2,
3080 },
3081 PrimitiveLiteral::Int128(9999),
3082 ),
3083 Datum::new(
3084 PrimitiveType::Decimal {
3085 precision: 9,
3086 scale: 2,
3087 },
3088 PrimitiveLiteral::Int128(9899),
3089 ),
3090 Datum::new(
3091 PrimitiveType::Decimal {
3092 precision: 9,
3093 scale: 2,
3094 },
3095 PrimitiveLiteral::Int128(10099),
3096 ),
3097 ]
3098 .into_iter(),
3099 ),
3100 )
3101 .bind(schema.clone(), false)
3102 .unwrap();
3103 let result = strict_projection.strict_project(&predicate).unwrap();
3104 assert_eq!(
3105 result.to_string(),
3106 "((pcol1 NOT IN (100, 90)) AND (pcol2 NOT IN (100, 90))) AND (pcol3 NOT IN (9890, 9990, 10090))"
3107 .to_string()
3108 );
3109
3110 let predicate = Reference::new("col1")
3112 .is_in(vec![Datum::int(99), Datum::int(100), Datum::int(98)].into_iter())
3113 .and(
3114 Reference::new("col2")
3115 .is_in(vec![Datum::long(99), Datum::long(100), Datum::long(98)].into_iter()),
3116 )
3117 .and(
3118 Reference::new("col3").is_in(
3119 vec![
3120 Datum::new(
3121 PrimitiveType::Decimal {
3122 precision: 9,
3123 scale: 2,
3124 },
3125 PrimitiveLiteral::Int128(9999),
3126 ),
3127 Datum::new(
3128 PrimitiveType::Decimal {
3129 precision: 9,
3130 scale: 2,
3131 },
3132 PrimitiveLiteral::Int128(9899),
3133 ),
3134 Datum::new(
3135 PrimitiveType::Decimal {
3136 precision: 9,
3137 scale: 2,
3138 },
3139 PrimitiveLiteral::Int128(10099),
3140 ),
3141 ]
3142 .into_iter(),
3143 ),
3144 )
3145 .bind(schema.clone(), false)
3146 .unwrap();
3147 let result = strict_projection.strict_project(&predicate).unwrap();
3148 assert_eq!(result.to_string(), "FALSE".to_string());
3149 }
3150
3151 #[tokio::test]
3152 async fn test_strict_projection_truncate_string() {
3153 let schema = Arc::new(
3154 Schema::builder()
3155 .with_fields(vec![Arc::new(NestedField::required(
3156 1,
3157 "col1",
3158 Type::Primitive(PrimitiveType::String),
3159 ))])
3160 .build()
3161 .unwrap(),
3162 );
3163
3164 let partition_spec = Arc::new(
3165 PartitionSpec::builder(schema.clone())
3166 .with_spec_id(1)
3167 .add_partition_field("col1", "pcol1", Transform::Truncate(5))
3168 .unwrap()
3169 .build()
3170 .unwrap(),
3171 );
3172
3173 let mut strict_projection = StrictProjection::new(partition_spec.clone());
3174
3175 let predicate = Reference::new("col1")
3177 .less_than(Datum::string("abcdefg"))
3178 .bind(schema.clone(), false)
3179 .unwrap();
3180 let result = strict_projection.strict_project(&predicate).unwrap();
3181 assert_eq!(result.to_string(), "pcol1 < \"abcde\"".to_string());
3182
3183 let predicate = Reference::new("col1")
3185 .less_than_or_equal_to(Datum::string("abcdefg"))
3186 .bind(schema.clone(), false)
3187 .unwrap();
3188 let result = strict_projection.strict_project(&predicate).unwrap();
3189 assert_eq!(result.to_string(), "pcol1 < \"abcde\"".to_string());
3190
3191 let predicate = Reference::new("col1")
3193 .greater_than(Datum::string("abcdefg"))
3194 .bind(schema.clone(), false)
3195 .unwrap();
3196 let result = strict_projection.strict_project(&predicate).unwrap();
3197 assert_eq!(result.to_string(), "pcol1 > \"abcde\"".to_string());
3198
3199 let predicate = Reference::new("col1")
3201 .greater_than_or_equal_to(Datum::string("abcdefg"))
3202 .bind(schema.clone(), false)
3203 .unwrap();
3204 let result = strict_projection.strict_project(&predicate).unwrap();
3205 assert_eq!(result.to_string(), "pcol1 > \"abcde\"".to_string());
3206
3207 let predicate = Reference::new("col1")
3209 .not_equal_to(Datum::string("abcdefg"))
3210 .bind(schema.clone(), false)
3211 .unwrap();
3212 let result = strict_projection.strict_project(&predicate).unwrap();
3213 assert_eq!(result.to_string(), "pcol1 != \"abcde\"".to_string());
3214
3215 let predicate = Reference::new("col1")
3217 .is_not_in(vec![Datum::string("abcdefg"), Datum::string("abcdefgabc")].into_iter())
3218 .bind(schema.clone(), false)
3219 .unwrap();
3220 let result = strict_projection.strict_project(&predicate).unwrap();
3221 assert_eq!(result.to_string(), "pcol1 NOT IN (\"abcde\")".to_string());
3222
3223 let predicate = Reference::new("col1")
3225 .is_in(vec![Datum::string("abcdefg"), Datum::string("abcdefgabc")].into_iter())
3226 .bind(schema.clone(), false)
3227 .unwrap();
3228 let result = strict_projection.strict_project(&predicate).unwrap();
3229 assert_eq!(result.to_string(), "FALSE".to_string());
3230 }
3231
3232 }