iceberg/transform/
temporal.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::sync::Arc;
19
20use arrow_arith::arity::binary;
21use arrow_arith::temporal::{DatePart, date_part};
22use arrow_array::types::Date32Type;
23use arrow_array::{
24    Array, ArrayRef, Date32Array, Int32Array, TimestampMicrosecondArray, TimestampNanosecondArray,
25};
26use arrow_schema::{DataType, TimeUnit};
27use chrono::{DateTime, Datelike, Duration};
28
29use super::TransformFunction;
30use crate::spec::{Datum, PrimitiveLiteral, PrimitiveType};
31use crate::{Error, ErrorKind, Result};
32
33/// Microseconds in one hour.
34const MICROSECONDS_PER_HOUR: i64 = 3_600_000_000;
35/// Nanoseconds in one hour.
36const NANOSECONDS_PER_HOUR: i64 = 3_600_000_000_000;
37/// Year of unix epoch.
38const UNIX_EPOCH_YEAR: i32 = 1970;
39/// One second in micros.
40const MICROS_PER_SECOND: i64 = 1_000_000;
41/// One second in nanos.
42const NANOS_PER_SECOND: i64 = 1_000_000_000;
43
44/// Extract a date or timestamp year, as years from 1970
45#[derive(Debug)]
46pub struct Year;
47
48impl Year {
49    #[inline]
50    fn timestamp_to_year_micros(timestamp: i64) -> Result<i32> {
51        Ok(DateTime::from_timestamp_micros(timestamp)
52            .ok_or_else(|| {
53                Error::new(
54                    ErrorKind::DataInvalid,
55                    "Fail to convert timestamp to date in year transform",
56                )
57            })?
58            .year()
59            - UNIX_EPOCH_YEAR)
60    }
61
62    #[inline]
63    fn timestamp_to_year_nanos(timestamp: i64) -> Result<i32> {
64        Ok(DateTime::from_timestamp_nanos(timestamp).year() - UNIX_EPOCH_YEAR)
65    }
66}
67
68impl TransformFunction for Year {
69    fn transform(&self, input: ArrayRef) -> Result<ArrayRef> {
70        let array = date_part(&input, DatePart::Year)
71            .map_err(|err| Error::new(ErrorKind::Unexpected, format!("{err}")))?;
72        Ok(Arc::<Int32Array>::new(
73            array
74                .as_any()
75                .downcast_ref::<Int32Array>()
76                .unwrap()
77                .unary(|v| v - UNIX_EPOCH_YEAR),
78        ))
79    }
80
81    fn transform_literal(&self, input: &crate::spec::Datum) -> Result<Option<crate::spec::Datum>> {
82        let val = match (input.data_type(), input.literal()) {
83            (PrimitiveType::Date, PrimitiveLiteral::Int(v)) => {
84                Date32Type::to_naive_date(*v).year() - UNIX_EPOCH_YEAR
85            }
86            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(v)) => {
87                Self::timestamp_to_year_micros(*v)?
88            }
89            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(v)) => {
90                Self::timestamp_to_year_micros(*v)?
91            }
92            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(v)) => {
93                Self::timestamp_to_year_nanos(*v)?
94            }
95            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(v)) => {
96                Self::timestamp_to_year_nanos(*v)?
97            }
98            _ => {
99                return Err(crate::Error::new(
100                    crate::ErrorKind::FeatureUnsupported,
101                    format!(
102                        "Unsupported data type for year transform: {:?}",
103                        input.data_type()
104                    ),
105                ));
106            }
107        };
108        Ok(Some(Datum::int(val)))
109    }
110}
111
112/// Extract a date or timestamp month, as months from 1970-01-01
113#[derive(Debug)]
114pub struct Month;
115
116impl Month {
117    #[inline]
118    fn timestamp_to_month_micros(timestamp: i64) -> Result<i32> {
119        // date: aaaa-aa-aa
120        // unix epoch date: 1970-01-01
121        // if date > unix epoch date, delta month = (aa - 1) + 12 * (aaaa-1970)
122        // if date < unix epoch date, delta month = (12 - (aa - 1)) + 12 * (1970-aaaa-1)
123        let date = DateTime::from_timestamp_micros(timestamp).ok_or_else(|| {
124            Error::new(
125                ErrorKind::DataInvalid,
126                "Fail to convert timestamp to date in month transform",
127            )
128        })?;
129        let unix_epoch_date = DateTime::from_timestamp_micros(0)
130            .expect("0 timestamp from unix epoch should be valid");
131        if date > unix_epoch_date {
132            Ok((date.month0() as i32) + 12 * (date.year() - UNIX_EPOCH_YEAR))
133        } else {
134            let delta = (12 - date.month0() as i32) + 12 * (UNIX_EPOCH_YEAR - date.year() - 1);
135            Ok(-delta)
136        }
137    }
138
139    #[inline]
140    fn timestamp_to_month_nanos(timestamp: i64) -> Result<i32> {
141        // date: aaaa-aa-aa
142        // unix epoch date: 1970-01-01
143        // if date > unix epoch date, delta month = (aa - 1) + 12 * (aaaa-1970)
144        // if date < unix epoch date, delta month = (12 - (aa - 1)) + 12 * (1970-aaaa-1)
145        let date = DateTime::from_timestamp_nanos(timestamp);
146        let unix_epoch_date = DateTime::from_timestamp_nanos(0);
147        if date > unix_epoch_date {
148            Ok((date.month0() as i32) + 12 * (date.year() - UNIX_EPOCH_YEAR))
149        } else {
150            let delta = (12 - date.month0() as i32) + 12 * (UNIX_EPOCH_YEAR - date.year() - 1);
151            Ok(-delta)
152        }
153    }
154}
155
156impl TransformFunction for Month {
157    fn transform(&self, input: ArrayRef) -> Result<ArrayRef> {
158        let year_array = date_part(&input, DatePart::Year)
159            .map_err(|err| Error::new(ErrorKind::Unexpected, format!("{err}")))?;
160        let year_array: Int32Array = year_array
161            .as_any()
162            .downcast_ref::<Int32Array>()
163            .unwrap()
164            .unary(|v| 12 * (v - UNIX_EPOCH_YEAR));
165        let month_array = date_part(&input, DatePart::Month)
166            .map_err(|err| Error::new(ErrorKind::Unexpected, format!("{err}")))?;
167        Ok(Arc::<Int32Array>::new(
168            binary(
169                month_array.as_any().downcast_ref::<Int32Array>().unwrap(),
170                year_array.as_any().downcast_ref::<Int32Array>().unwrap(),
171                // Compute month from 1970-01-01, so minus 1 here.
172                |a, b| a + b - 1,
173            )
174            .unwrap(),
175        ))
176    }
177
178    fn transform_literal(&self, input: &crate::spec::Datum) -> Result<Option<crate::spec::Datum>> {
179        let val = match (input.data_type(), input.literal()) {
180            (PrimitiveType::Date, PrimitiveLiteral::Int(v)) => {
181                (Date32Type::to_naive_date(*v).year() - UNIX_EPOCH_YEAR) * 12
182                    + Date32Type::to_naive_date(*v).month0() as i32
183            }
184            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(v)) => {
185                Self::timestamp_to_month_micros(*v)?
186            }
187            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(v)) => {
188                Self::timestamp_to_month_micros(*v)?
189            }
190            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(v)) => {
191                Self::timestamp_to_month_nanos(*v)?
192            }
193            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(v)) => {
194                Self::timestamp_to_month_nanos(*v)?
195            }
196            _ => {
197                return Err(crate::Error::new(
198                    crate::ErrorKind::FeatureUnsupported,
199                    format!(
200                        "Unsupported data type for month transform: {:?}",
201                        input.data_type()
202                    ),
203                ));
204            }
205        };
206        Ok(Some(Datum::int(val)))
207    }
208}
209
210/// Extract a date or timestamp day, as days from 1970-01-01
211#[derive(Debug)]
212pub struct Day;
213
214impl Day {
215    #[inline]
216    fn day_timestamp_micro(v: i64) -> Result<i32> {
217        let secs = v / MICROS_PER_SECOND;
218
219        let (nanos, offset) = if v >= 0 {
220            let nanos = (v.rem_euclid(MICROS_PER_SECOND) * 1_000) as u32;
221            let offset = 0i64;
222            (nanos, offset)
223        } else {
224            let v = v + 1;
225            let nanos = (v.rem_euclid(MICROS_PER_SECOND) * 1_000) as u32;
226            let offset = 1i64;
227            (nanos, offset)
228        };
229
230        let delta = Duration::new(secs, nanos).ok_or_else(|| {
231            Error::new(
232                ErrorKind::DataInvalid,
233                format!("Failed to create 'TimeDelta' from seconds {secs} and nanos {nanos}"),
234            )
235        })?;
236
237        let days = (delta.num_days() - offset) as i32;
238
239        Ok(days)
240    }
241
242    fn day_timestamp_nano(v: i64) -> Result<i32> {
243        let secs = v / NANOS_PER_SECOND;
244
245        let (nanos, offset) = if v >= 0 {
246            let nanos = (v.rem_euclid(NANOS_PER_SECOND)) as u32;
247            let offset = 0i64;
248            (nanos, offset)
249        } else {
250            let v = v + 1;
251            let nanos = (v.rem_euclid(NANOS_PER_SECOND)) as u32;
252            let offset = 1i64;
253            (nanos, offset)
254        };
255
256        let delta = Duration::new(secs, nanos).ok_or_else(|| {
257            Error::new(
258                ErrorKind::DataInvalid,
259                format!("Failed to create 'TimeDelta' from seconds {secs} and nanos {nanos}"),
260            )
261        })?;
262
263        let days = (delta.num_days() - offset) as i32;
264
265        Ok(days)
266    }
267}
268
269impl TransformFunction for Day {
270    fn transform(&self, input: ArrayRef) -> Result<ArrayRef> {
271        let res: Date32Array = match input.data_type() {
272            DataType::Timestamp(TimeUnit::Microsecond, _) => input
273                .as_any()
274                .downcast_ref::<TimestampMicrosecondArray>()
275                .unwrap()
276                .try_unary(|v| -> Result<i32> { Self::day_timestamp_micro(v) })?,
277            DataType::Timestamp(TimeUnit::Nanosecond, _) => input
278                .as_any()
279                .downcast_ref::<TimestampNanosecondArray>()
280                .unwrap()
281                .try_unary(|v| -> Result<i32> { Self::day_timestamp_nano(v) })?,
282            DataType::Date32 => input
283                .as_any()
284                .downcast_ref::<Date32Array>()
285                .unwrap()
286                .unary(|v| -> i32 { v }),
287            _ => {
288                return Err(Error::new(
289                    ErrorKind::Unexpected,
290                    format!(
291                        "Should not call internally for unsupported data type {:?}",
292                        input.data_type()
293                    ),
294                ));
295            }
296        };
297        Ok(Arc::new(res))
298    }
299
300    fn transform_literal(&self, input: &crate::spec::Datum) -> Result<Option<crate::spec::Datum>> {
301        let val = match (input.data_type(), input.literal()) {
302            (PrimitiveType::Date, PrimitiveLiteral::Int(v)) => *v,
303            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(v)) => Self::day_timestamp_micro(*v)?,
304            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(v)) => {
305                Self::day_timestamp_micro(*v)?
306            }
307            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(v)) => {
308                Self::day_timestamp_nano(*v)?
309            }
310            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(v)) => {
311                Self::day_timestamp_nano(*v)?
312            }
313            _ => {
314                return Err(crate::Error::new(
315                    crate::ErrorKind::FeatureUnsupported,
316                    format!(
317                        "Unsupported data type for day transform: {:?}",
318                        input.data_type()
319                    ),
320                ));
321            }
322        };
323        Ok(Some(Datum::date(val)))
324    }
325}
326
327/// Extract a timestamp hour, as hours from 1970-01-01 00:00:00
328#[derive(Debug)]
329pub struct Hour;
330
331impl Hour {
332    #[inline]
333    fn hour_timestamp_micro(v: i64) -> i32 {
334        v.div_euclid(MICROSECONDS_PER_HOUR) as i32
335    }
336
337    #[inline]
338    fn hour_timestamp_nano(v: i64) -> i32 {
339        v.div_euclid(NANOSECONDS_PER_HOUR) as i32
340    }
341}
342
343impl TransformFunction for Hour {
344    fn transform(&self, input: ArrayRef) -> Result<ArrayRef> {
345        let res: Int32Array = match input.data_type() {
346            DataType::Timestamp(TimeUnit::Microsecond, _) => input
347                .as_any()
348                .downcast_ref::<TimestampMicrosecondArray>()
349                .unwrap()
350                .unary(|v| -> i32 { Self::hour_timestamp_micro(v) }),
351            _ => {
352                return Err(crate::Error::new(
353                    crate::ErrorKind::FeatureUnsupported,
354                    format!(
355                        "Unsupported data type for hour transform: {:?}",
356                        input.data_type()
357                    ),
358                ));
359            }
360        };
361        Ok(Arc::new(res))
362    }
363
364    fn transform_literal(&self, input: &crate::spec::Datum) -> Result<Option<crate::spec::Datum>> {
365        let val = match (input.data_type(), input.literal()) {
366            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(v)) => Self::hour_timestamp_micro(*v),
367            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(v)) => {
368                Self::hour_timestamp_micro(*v)
369            }
370            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(v)) => {
371                Self::hour_timestamp_nano(*v)
372            }
373            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(v)) => {
374                Self::hour_timestamp_nano(*v)
375            }
376            _ => {
377                return Err(crate::Error::new(
378                    crate::ErrorKind::FeatureUnsupported,
379                    format!(
380                        "Unsupported data type for hour transform: {:?}",
381                        input.data_type()
382                    ),
383                ));
384            }
385        };
386        Ok(Some(Datum::int(val)))
387    }
388}
389
390#[cfg(test)]
391mod test {
392    use std::sync::Arc;
393
394    use arrow_array::{ArrayRef, Date32Array, Int32Array, TimestampMicrosecondArray};
395    use chrono::{NaiveDate, NaiveDateTime};
396
397    use crate::Result;
398    use crate::expr::PredicateOperator;
399    use crate::spec::PrimitiveType::{
400        Binary, Date, Decimal, Fixed, Int, Long, String as StringType, Time, Timestamp,
401        TimestampNs, Timestamptz, TimestamptzNs, Uuid,
402    };
403    use crate::spec::Type::{Primitive, Struct};
404    use crate::spec::{Datum, NestedField, PrimitiveType, StructType, Transform, Type};
405    use crate::transform::test::{TestProjectionFixture, TestTransformFixture};
406    use crate::transform::{BoxedTransformFunction, TransformFunction};
407
408    #[test]
409    fn test_year_transform() {
410        let trans = Transform::Year;
411
412        let fixture = TestTransformFixture {
413            display: "year".to_string(),
414            json: r#""year""#.to_string(),
415            dedup_name: "time".to_string(),
416            preserves_order: true,
417            satisfies_order_of: vec![
418                (Transform::Year, true),
419                (Transform::Month, false),
420                (Transform::Day, false),
421                (Transform::Hour, false),
422                (Transform::Void, false),
423                (Transform::Identity, false),
424            ],
425            trans_types: vec![
426                (Primitive(Binary), None),
427                (Primitive(Date), Some(Primitive(Int))),
428                (
429                    Primitive(Decimal {
430                        precision: 8,
431                        scale: 5,
432                    }),
433                    None,
434                ),
435                (Primitive(Fixed(8)), None),
436                (Primitive(Int), None),
437                (Primitive(Long), None),
438                (Primitive(StringType), None),
439                (Primitive(Uuid), None),
440                (Primitive(Time), None),
441                (Primitive(Timestamp), Some(Primitive(Int))),
442                (Primitive(Timestamptz), Some(Primitive(Int))),
443                (Primitive(TimestampNs), Some(Primitive(Int))),
444                (Primitive(TimestamptzNs), Some(Primitive(Int))),
445                (
446                    Struct(StructType::new(vec![
447                        NestedField::optional(1, "a", Primitive(Timestamp)).into(),
448                    ])),
449                    None,
450                ),
451            ],
452        };
453
454        fixture.assert_transform(trans);
455    }
456
457    #[test]
458    fn test_month_transform() {
459        let trans = Transform::Month;
460
461        let fixture = TestTransformFixture {
462            display: "month".to_string(),
463            json: r#""month""#.to_string(),
464            dedup_name: "time".to_string(),
465            preserves_order: true,
466            satisfies_order_of: vec![
467                (Transform::Year, true),
468                (Transform::Month, true),
469                (Transform::Day, false),
470                (Transform::Hour, false),
471                (Transform::Void, false),
472                (Transform::Identity, false),
473            ],
474            trans_types: vec![
475                (Primitive(Binary), None),
476                (Primitive(Date), Some(Primitive(Int))),
477                (
478                    Primitive(Decimal {
479                        precision: 8,
480                        scale: 5,
481                    }),
482                    None,
483                ),
484                (Primitive(Fixed(8)), None),
485                (Primitive(Int), None),
486                (Primitive(Long), None),
487                (Primitive(StringType), None),
488                (Primitive(Uuid), None),
489                (Primitive(Time), None),
490                (Primitive(Timestamp), Some(Primitive(Int))),
491                (Primitive(Timestamptz), Some(Primitive(Int))),
492                (Primitive(TimestampNs), Some(Primitive(Int))),
493                (Primitive(TimestamptzNs), Some(Primitive(Int))),
494                (
495                    Struct(StructType::new(vec![
496                        NestedField::optional(1, "a", Primitive(Timestamp)).into(),
497                    ])),
498                    None,
499                ),
500            ],
501        };
502
503        fixture.assert_transform(trans);
504    }
505
506    #[test]
507    fn test_day_transform() {
508        let trans = Transform::Day;
509
510        let fixture = TestTransformFixture {
511            display: "day".to_string(),
512            json: r#""day""#.to_string(),
513            dedup_name: "time".to_string(),
514            preserves_order: true,
515            satisfies_order_of: vec![
516                (Transform::Year, true),
517                (Transform::Month, true),
518                (Transform::Day, true),
519                (Transform::Hour, false),
520                (Transform::Void, false),
521                (Transform::Identity, false),
522            ],
523            trans_types: vec![
524                (Primitive(Binary), None),
525                (Primitive(Date), Some(Primitive(Date))),
526                (
527                    Primitive(Decimal {
528                        precision: 8,
529                        scale: 5,
530                    }),
531                    None,
532                ),
533                (Primitive(Fixed(8)), None),
534                (Primitive(Int), None),
535                (Primitive(Long), None),
536                (Primitive(StringType), None),
537                (Primitive(Uuid), None),
538                (Primitive(Time), None),
539                (Primitive(Timestamp), Some(Primitive(Date))),
540                (Primitive(Timestamptz), Some(Primitive(Date))),
541                (Primitive(TimestampNs), Some(Primitive(Date))),
542                (Primitive(TimestamptzNs), Some(Primitive(Date))),
543                (
544                    Struct(StructType::new(vec![
545                        NestedField::optional(1, "a", Primitive(Timestamp)).into(),
546                    ])),
547                    None,
548                ),
549            ],
550        };
551
552        fixture.assert_transform(trans);
553    }
554
555    #[test]
556    fn test_hour_transform() {
557        let trans = Transform::Hour;
558
559        let fixture = TestTransformFixture {
560            display: "hour".to_string(),
561            json: r#""hour""#.to_string(),
562            dedup_name: "time".to_string(),
563            preserves_order: true,
564            satisfies_order_of: vec![
565                (Transform::Year, true),
566                (Transform::Month, true),
567                (Transform::Day, true),
568                (Transform::Hour, true),
569                (Transform::Void, false),
570                (Transform::Identity, false),
571            ],
572            trans_types: vec![
573                (Primitive(Binary), None),
574                (Primitive(Date), None),
575                (
576                    Primitive(Decimal {
577                        precision: 8,
578                        scale: 5,
579                    }),
580                    None,
581                ),
582                (Primitive(Fixed(8)), None),
583                (Primitive(Int), None),
584                (Primitive(Long), None),
585                (Primitive(StringType), None),
586                (Primitive(Uuid), None),
587                (Primitive(Time), None),
588                (Primitive(Timestamp), Some(Primitive(Int))),
589                (Primitive(Timestamptz), Some(Primitive(Int))),
590                (Primitive(TimestampNs), Some(Primitive(Int))),
591                (Primitive(TimestamptzNs), Some(Primitive(Int))),
592                (
593                    Struct(StructType::new(vec![
594                        NestedField::optional(1, "a", Primitive(Timestamp)).into(),
595                    ])),
596                    None,
597                ),
598            ],
599        };
600
601        fixture.assert_transform(trans);
602    }
603
604    #[test]
605    fn test_projection_timestamp_hour_upper_bound() -> Result<()> {
606        // 420034
607        let value = "2017-12-01T10:59:59.999999";
608        // 412007
609        let another = "2016-12-31T23:59:59.999999";
610
611        let fixture = TestProjectionFixture::new(
612            Transform::Hour,
613            "name",
614            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
615        );
616
617        fixture.assert_projection(
618            &fixture.binary_predicate(
619                PredicateOperator::LessThan,
620                Datum::timestamp_from_str(value)?,
621            ),
622            Some("name <= 420034"),
623        )?;
624
625        fixture.assert_projection(
626            &fixture.binary_predicate(
627                PredicateOperator::LessThanOrEq,
628                Datum::timestamp_from_str(value)?,
629            ),
630            Some("name <= 420034"),
631        )?;
632
633        fixture.assert_projection(
634            &fixture.binary_predicate(
635                PredicateOperator::GreaterThan,
636                Datum::timestamp_from_str(value)?,
637            ),
638            Some("name >= 420035"),
639        )?;
640
641        fixture.assert_projection(
642            &fixture.binary_predicate(
643                PredicateOperator::GreaterThanOrEq,
644                Datum::timestamp_from_str(value)?,
645            ),
646            Some("name >= 420034"),
647        )?;
648
649        fixture.assert_projection(
650            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
651            Some("name = 420034"),
652        )?;
653
654        fixture.assert_projection(
655            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
656            None,
657        )?;
658
659        fixture.assert_projection(
660            &fixture.set_predicate(PredicateOperator::In, vec![
661                Datum::timestamp_from_str(value)?,
662                Datum::timestamp_from_str(another)?,
663            ]),
664            Some("name IN (420034, 412007)"),
665        )?;
666
667        fixture.assert_projection(
668            &fixture.set_predicate(PredicateOperator::NotIn, vec![
669                Datum::timestamp_from_str(value)?,
670                Datum::timestamp_from_str(another)?,
671            ]),
672            None,
673        )?;
674
675        Ok(())
676    }
677
678    #[test]
679    fn test_projection_timestamp_hour_lower_bound() -> Result<()> {
680        // 420034
681        let value = "2017-12-01T10:00:00.000000";
682        // 411288
683        let another = "2016-12-02T00:00:00.000000";
684
685        let fixture = TestProjectionFixture::new(
686            Transform::Hour,
687            "name",
688            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
689        );
690
691        fixture.assert_projection(
692            &fixture.binary_predicate(
693                PredicateOperator::LessThan,
694                Datum::timestamp_from_str(value)?,
695            ),
696            Some("name <= 420033"),
697        )?;
698
699        fixture.assert_projection(
700            &fixture.binary_predicate(
701                PredicateOperator::LessThanOrEq,
702                Datum::timestamp_from_str(value)?,
703            ),
704            Some("name <= 420034"),
705        )?;
706
707        fixture.assert_projection(
708            &fixture.binary_predicate(
709                PredicateOperator::GreaterThan,
710                Datum::timestamp_from_str(value)?,
711            ),
712            Some("name >= 420034"),
713        )?;
714
715        fixture.assert_projection(
716            &fixture.binary_predicate(
717                PredicateOperator::GreaterThanOrEq,
718                Datum::timestamp_from_str(value)?,
719            ),
720            Some("name >= 420034"),
721        )?;
722
723        fixture.assert_projection(
724            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
725            Some("name = 420034"),
726        )?;
727
728        fixture.assert_projection(
729            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
730            None,
731        )?;
732
733        fixture.assert_projection(
734            &fixture.set_predicate(PredicateOperator::In, vec![
735                Datum::timestamp_from_str(value)?,
736                Datum::timestamp_from_str(another)?,
737            ]),
738            Some("name IN (411288, 420034)"),
739        )?;
740
741        fixture.assert_projection(
742            &fixture.set_predicate(PredicateOperator::NotIn, vec![
743                Datum::timestamp_from_str(value)?,
744                Datum::timestamp_from_str(another)?,
745            ]),
746            None,
747        )?;
748
749        Ok(())
750    }
751
752    #[test]
753    fn test_projection_timestamp_year_upper_bound() -> Result<()> {
754        let value = "2017-12-31T23:59:59.999999";
755        let another = "2016-12-31T23:59:59.999999";
756
757        let fixture = TestProjectionFixture::new(
758            Transform::Year,
759            "name",
760            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
761        );
762
763        fixture.assert_projection(
764            &fixture.binary_predicate(
765                PredicateOperator::LessThan,
766                Datum::timestamp_from_str(value)?,
767            ),
768            Some("name <= 47"),
769        )?;
770
771        fixture.assert_projection(
772            &fixture.binary_predicate(
773                PredicateOperator::LessThanOrEq,
774                Datum::timestamp_from_str(value)?,
775            ),
776            Some("name <= 47"),
777        )?;
778
779        fixture.assert_projection(
780            &fixture.binary_predicate(
781                PredicateOperator::GreaterThan,
782                Datum::timestamp_from_str(value)?,
783            ),
784            Some("name >= 48"),
785        )?;
786
787        fixture.assert_projection(
788            &fixture.binary_predicate(
789                PredicateOperator::GreaterThanOrEq,
790                Datum::timestamp_from_str(value)?,
791            ),
792            Some("name >= 47"),
793        )?;
794
795        fixture.assert_projection(
796            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
797            Some("name = 47"),
798        )?;
799
800        fixture.assert_projection(
801            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
802            None,
803        )?;
804
805        fixture.assert_projection(
806            &fixture.set_predicate(PredicateOperator::In, vec![
807                Datum::timestamp_from_str(value)?,
808                Datum::timestamp_from_str(another)?,
809            ]),
810            Some("name IN (47, 46)"),
811        )?;
812
813        fixture.assert_projection(
814            &fixture.set_predicate(PredicateOperator::NotIn, vec![
815                Datum::timestamp_from_str(value)?,
816                Datum::timestamp_from_str(another)?,
817            ]),
818            None,
819        )?;
820
821        Ok(())
822    }
823
824    #[test]
825    fn test_projection_timestamp_year_lower_bound() -> Result<()> {
826        let value = "2017-01-01T00:00:00.000000";
827        let another = "2016-12-02T00:00:00.000000";
828
829        let fixture = TestProjectionFixture::new(
830            Transform::Year,
831            "name",
832            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
833        );
834
835        fixture.assert_projection(
836            &fixture.binary_predicate(
837                PredicateOperator::LessThan,
838                Datum::timestamp_from_str(value)?,
839            ),
840            Some("name <= 46"),
841        )?;
842
843        fixture.assert_projection(
844            &fixture.binary_predicate(
845                PredicateOperator::LessThanOrEq,
846                Datum::timestamp_from_str(value)?,
847            ),
848            Some("name <= 47"),
849        )?;
850
851        fixture.assert_projection(
852            &fixture.binary_predicate(
853                PredicateOperator::GreaterThan,
854                Datum::timestamp_from_str(value)?,
855            ),
856            Some("name >= 47"),
857        )?;
858
859        fixture.assert_projection(
860            &fixture.binary_predicate(
861                PredicateOperator::GreaterThanOrEq,
862                Datum::timestamp_from_str(value)?,
863            ),
864            Some("name >= 47"),
865        )?;
866
867        fixture.assert_projection(
868            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
869            Some("name = 47"),
870        )?;
871
872        fixture.assert_projection(
873            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
874            None,
875        )?;
876
877        fixture.assert_projection(
878            &fixture.set_predicate(PredicateOperator::In, vec![
879                Datum::timestamp_from_str(value)?,
880                Datum::timestamp_from_str(another)?,
881            ]),
882            Some("name IN (47, 46)"),
883        )?;
884
885        fixture.assert_projection(
886            &fixture.set_predicate(PredicateOperator::NotIn, vec![
887                Datum::timestamp_from_str(value)?,
888                Datum::timestamp_from_str(another)?,
889            ]),
890            None,
891        )?;
892
893        Ok(())
894    }
895
896    #[test]
897    fn test_projection_timestamp_month_negative_upper_bound() -> Result<()> {
898        let value = "1969-12-31T23:59:59.999999";
899        let another = "1970-01-01T00:00:00.000000";
900
901        let fixture = TestProjectionFixture::new(
902            Transform::Month,
903            "name",
904            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
905        );
906
907        fixture.assert_projection(
908            &fixture.binary_predicate(
909                PredicateOperator::LessThan,
910                Datum::timestamp_from_str(value)?,
911            ),
912            Some("name <= 0"),
913        )?;
914
915        fixture.assert_projection(
916            &fixture.binary_predicate(
917                PredicateOperator::LessThanOrEq,
918                Datum::timestamp_from_str(value)?,
919            ),
920            Some("name <= 0"),
921        )?;
922
923        fixture.assert_projection(
924            &fixture.binary_predicate(
925                PredicateOperator::GreaterThan,
926                Datum::timestamp_from_str(value)?,
927            ),
928            Some("name >= 0"),
929        )?;
930
931        fixture.assert_projection(
932            &fixture.binary_predicate(
933                PredicateOperator::GreaterThanOrEq,
934                Datum::timestamp_from_str(value)?,
935            ),
936            Some("name >= -1"),
937        )?;
938
939        fixture.assert_projection(
940            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
941            Some("name IN (-1, 0)"),
942        )?;
943
944        fixture.assert_projection(
945            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
946            None,
947        )?;
948
949        fixture.assert_projection(
950            &fixture.set_predicate(PredicateOperator::In, vec![
951                Datum::timestamp_from_str(value)?,
952                Datum::timestamp_from_str(another)?,
953            ]),
954            Some("name IN (0, -1)"),
955        )?;
956
957        fixture.assert_projection(
958            &fixture.set_predicate(PredicateOperator::NotIn, vec![
959                Datum::timestamp_from_str(value)?,
960                Datum::timestamp_from_str(another)?,
961            ]),
962            None,
963        )?;
964
965        Ok(())
966    }
967
968    #[test]
969    fn test_projection_timestamp_month_upper_bound() -> Result<()> {
970        let value = "2017-12-01T23:59:59.999999";
971        let another = "2017-11-02T00:00:00.000000";
972
973        let fixture = TestProjectionFixture::new(
974            Transform::Month,
975            "name",
976            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
977        );
978
979        fixture.assert_projection(
980            &fixture.binary_predicate(
981                PredicateOperator::LessThan,
982                Datum::timestamp_from_str(value)?,
983            ),
984            Some("name <= 575"),
985        )?;
986
987        fixture.assert_projection(
988            &fixture.binary_predicate(
989                PredicateOperator::LessThanOrEq,
990                Datum::timestamp_from_str(value)?,
991            ),
992            Some("name <= 575"),
993        )?;
994
995        fixture.assert_projection(
996            &fixture.binary_predicate(
997                PredicateOperator::GreaterThan,
998                Datum::timestamp_from_str(value)?,
999            ),
1000            Some("name >= 575"),
1001        )?;
1002
1003        fixture.assert_projection(
1004            &fixture.binary_predicate(
1005                PredicateOperator::GreaterThanOrEq,
1006                Datum::timestamp_from_str(value)?,
1007            ),
1008            Some("name >= 575"),
1009        )?;
1010
1011        fixture.assert_projection(
1012            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1013            Some("name = 575"),
1014        )?;
1015
1016        fixture.assert_projection(
1017            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1018            None,
1019        )?;
1020
1021        fixture.assert_projection(
1022            &fixture.set_predicate(PredicateOperator::In, vec![
1023                Datum::timestamp_from_str(value)?,
1024                Datum::timestamp_from_str(another)?,
1025            ]),
1026            Some("name IN (575, 574)"),
1027        )?;
1028
1029        fixture.assert_projection(
1030            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1031                Datum::timestamp_from_str(value)?,
1032                Datum::timestamp_from_str(another)?,
1033            ]),
1034            None,
1035        )?;
1036        Ok(())
1037    }
1038
1039    #[test]
1040    fn test_projection_timestamp_month_negative_lower_bound() -> Result<()> {
1041        let value = "1969-01-01T00:00:00.000000";
1042        let another = "1969-03-01T00:00:00.000000";
1043
1044        let fixture = TestProjectionFixture::new(
1045            Transform::Month,
1046            "name",
1047            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1048        );
1049
1050        fixture.assert_projection(
1051            &fixture.binary_predicate(
1052                PredicateOperator::LessThan,
1053                Datum::timestamp_from_str(value)?,
1054            ),
1055            Some("name <= -12"),
1056        )?;
1057
1058        fixture.assert_projection(
1059            &fixture.binary_predicate(
1060                PredicateOperator::LessThanOrEq,
1061                Datum::timestamp_from_str(value)?,
1062            ),
1063            Some("name <= -11"),
1064        )?;
1065
1066        fixture.assert_projection(
1067            &fixture.binary_predicate(
1068                PredicateOperator::GreaterThan,
1069                Datum::timestamp_from_str(value)?,
1070            ),
1071            Some("name >= -12"),
1072        )?;
1073
1074        fixture.assert_projection(
1075            &fixture.binary_predicate(
1076                PredicateOperator::GreaterThanOrEq,
1077                Datum::timestamp_from_str(value)?,
1078            ),
1079            Some("name >= -12"),
1080        )?;
1081
1082        fixture.assert_projection(
1083            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1084            Some("name IN (-12, -11)"),
1085        )?;
1086
1087        fixture.assert_projection(
1088            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1089            None,
1090        )?;
1091
1092        fixture.assert_projection(
1093            &fixture.set_predicate(PredicateOperator::In, vec![
1094                Datum::timestamp_from_str(value)?,
1095                Datum::timestamp_from_str(another)?,
1096            ]),
1097            Some("name IN (-10, -9, -12, -11)"),
1098        )?;
1099
1100        fixture.assert_projection(
1101            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1102                Datum::timestamp_from_str(value)?,
1103                Datum::timestamp_from_str(another)?,
1104            ]),
1105            None,
1106        )?;
1107
1108        Ok(())
1109    }
1110
1111    #[test]
1112    fn test_projection_timestamp_month_lower_bound() -> Result<()> {
1113        let value = "2017-12-01T00:00:00.000000";
1114        let another = "2017-12-02T00:00:00.000000";
1115
1116        let fixture = TestProjectionFixture::new(
1117            Transform::Month,
1118            "name",
1119            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1120        );
1121
1122        fixture.assert_projection(
1123            &fixture.binary_predicate(
1124                PredicateOperator::LessThan,
1125                Datum::timestamp_from_str(value)?,
1126            ),
1127            Some("name <= 574"),
1128        )?;
1129
1130        fixture.assert_projection(
1131            &fixture.binary_predicate(
1132                PredicateOperator::LessThanOrEq,
1133                Datum::timestamp_from_str(value)?,
1134            ),
1135            Some("name <= 575"),
1136        )?;
1137
1138        fixture.assert_projection(
1139            &fixture.binary_predicate(
1140                PredicateOperator::GreaterThan,
1141                Datum::timestamp_from_str(value)?,
1142            ),
1143            Some("name >= 575"),
1144        )?;
1145
1146        fixture.assert_projection(
1147            &fixture.binary_predicate(
1148                PredicateOperator::GreaterThanOrEq,
1149                Datum::timestamp_from_str(value)?,
1150            ),
1151            Some("name >= 575"),
1152        )?;
1153
1154        fixture.assert_projection(
1155            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1156            Some("name = 575"),
1157        )?;
1158
1159        fixture.assert_projection(
1160            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1161            None,
1162        )?;
1163
1164        fixture.assert_projection(
1165            &fixture.set_predicate(PredicateOperator::In, vec![
1166                Datum::timestamp_from_str(value)?,
1167                Datum::timestamp_from_str(another)?,
1168            ]),
1169            Some("name IN (575)"),
1170        )?;
1171
1172        fixture.assert_projection(
1173            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1174                Datum::timestamp_from_str(value)?,
1175                Datum::timestamp_from_str(another)?,
1176            ]),
1177            None,
1178        )?;
1179
1180        Ok(())
1181    }
1182
1183    #[test]
1184    fn test_projection_timestamp_day_negative_upper_bound() -> Result<()> {
1185        // -1
1186        let value = "1969-12-31T23:59:59.999999";
1187        // 0
1188        let another = "1970-01-01T00:00:00.000000";
1189
1190        let fixture = TestProjectionFixture::new(
1191            Transform::Day,
1192            "name",
1193            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1194        );
1195
1196        fixture.assert_projection(
1197            &fixture.binary_predicate(
1198                PredicateOperator::LessThan,
1199                Datum::timestamp_from_str(value)?,
1200            ),
1201            Some("name <= 1970-01-01"),
1202        )?;
1203
1204        fixture.assert_projection(
1205            &fixture.binary_predicate(
1206                PredicateOperator::LessThanOrEq,
1207                Datum::timestamp_from_str(value)?,
1208            ),
1209            Some("name <= 1970-01-01"),
1210        )?;
1211
1212        fixture.assert_projection(
1213            &fixture.binary_predicate(
1214                PredicateOperator::GreaterThan,
1215                Datum::timestamp_from_str(value)?,
1216            ),
1217            Some("name >= 1970-01-01"),
1218        )?;
1219
1220        fixture.assert_projection(
1221            &fixture.binary_predicate(
1222                PredicateOperator::GreaterThanOrEq,
1223                Datum::timestamp_from_str(value)?,
1224            ),
1225            Some("name >= 1969-12-31"),
1226        )?;
1227
1228        fixture.assert_projection(
1229            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1230            Some("name IN (1969-12-31, 1970-01-01)"),
1231        )?;
1232
1233        fixture.assert_projection(
1234            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1235            None,
1236        )?;
1237
1238        fixture.assert_projection(
1239            &fixture.set_predicate(PredicateOperator::In, vec![
1240                Datum::timestamp_from_str(value)?,
1241                Datum::timestamp_from_str(another)?,
1242            ]),
1243            Some("name IN (1970-01-01, 1969-12-31)"),
1244        )?;
1245
1246        fixture.assert_projection(
1247            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1248                Datum::timestamp_from_str(value)?,
1249                Datum::timestamp_from_str(another)?,
1250            ]),
1251            None,
1252        )?;
1253
1254        Ok(())
1255    }
1256
1257    #[test]
1258    fn test_projection_timestamp_day_upper_bound() -> Result<()> {
1259        // 17501
1260        let value = "2017-12-01T23:59:59.999999";
1261        // 17502
1262        let another = "2017-12-02T00:00:00.000000";
1263
1264        let fixture = TestProjectionFixture::new(
1265            Transform::Day,
1266            "name",
1267            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1268        );
1269
1270        fixture.assert_projection(
1271            &fixture.binary_predicate(
1272                PredicateOperator::LessThan,
1273                Datum::timestamp_from_str(value)?,
1274            ),
1275            Some("name <= 2017-12-01"),
1276        )?;
1277
1278        fixture.assert_projection(
1279            &fixture.binary_predicate(
1280                PredicateOperator::LessThanOrEq,
1281                Datum::timestamp_from_str(value)?,
1282            ),
1283            Some("name <= 2017-12-01"),
1284        )?;
1285
1286        fixture.assert_projection(
1287            &fixture.binary_predicate(
1288                PredicateOperator::GreaterThan,
1289                Datum::timestamp_from_str(value)?,
1290            ),
1291            Some("name >= 2017-12-02"),
1292        )?;
1293
1294        fixture.assert_projection(
1295            &fixture.binary_predicate(
1296                PredicateOperator::GreaterThanOrEq,
1297                Datum::timestamp_from_str(value)?,
1298            ),
1299            Some("name >= 2017-12-01"),
1300        )?;
1301
1302        fixture.assert_projection(
1303            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1304            Some("name = 2017-12-01"),
1305        )?;
1306
1307        fixture.assert_projection(
1308            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1309            None,
1310        )?;
1311
1312        fixture.assert_projection(
1313            &fixture.set_predicate(PredicateOperator::In, vec![
1314                Datum::timestamp_from_str(value)?,
1315                Datum::timestamp_from_str(another)?,
1316            ]),
1317            Some("name IN (2017-12-02, 2017-12-01)"),
1318        )?;
1319
1320        fixture.assert_projection(
1321            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1322                Datum::timestamp_from_str(value)?,
1323                Datum::timestamp_from_str(another)?,
1324            ]),
1325            None,
1326        )?;
1327
1328        Ok(())
1329    }
1330
1331    #[test]
1332    fn test_projection_timestamp_day_negative_lower_bound() -> Result<()> {
1333        // -365
1334        let value = "1969-01-01T00:00:00.000000";
1335        // -364
1336        let another = "1969-01-02T00:00:00.000000";
1337
1338        let fixture = TestProjectionFixture::new(
1339            Transform::Day,
1340            "name",
1341            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1342        );
1343
1344        fixture.assert_projection(
1345            &fixture.binary_predicate(
1346                PredicateOperator::LessThan,
1347                Datum::timestamp_from_str(value)?,
1348            ),
1349            Some("name <= 1969-01-01"),
1350        )?;
1351
1352        fixture.assert_projection(
1353            &fixture.binary_predicate(
1354                PredicateOperator::LessThanOrEq,
1355                Datum::timestamp_from_str(value)?,
1356            ),
1357            Some("name <= 1969-01-02"),
1358        )?;
1359
1360        fixture.assert_projection(
1361            &fixture.binary_predicate(
1362                PredicateOperator::GreaterThan,
1363                Datum::timestamp_from_str(value)?,
1364            ),
1365            Some("name >= 1969-01-01"),
1366        )?;
1367
1368        fixture.assert_projection(
1369            &fixture.binary_predicate(
1370                PredicateOperator::GreaterThanOrEq,
1371                Datum::timestamp_from_str(value)?,
1372            ),
1373            Some("name >= 1969-01-01"),
1374        )?;
1375
1376        fixture.assert_projection(
1377            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1378            Some("name IN (1969-01-01, 1969-01-02)"),
1379        )?;
1380
1381        fixture.assert_projection(
1382            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1383            None,
1384        )?;
1385
1386        fixture.assert_projection(
1387            &fixture.set_predicate(PredicateOperator::In, vec![
1388                Datum::timestamp_from_str(value)?,
1389                Datum::timestamp_from_str(another)?,
1390            ]),
1391            Some("name IN (1969-01-02, 1969-01-01, 1969-01-03)"),
1392        )?;
1393
1394        fixture.assert_projection(
1395            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1396                Datum::timestamp_from_str(value)?,
1397                Datum::timestamp_from_str(another)?,
1398            ]),
1399            None,
1400        )?;
1401
1402        Ok(())
1403    }
1404
1405    #[test]
1406    fn test_projection_timestamp_day_lower_bound() -> Result<()> {
1407        // 17501
1408        let value = "2017-12-01T00:00:00.000000";
1409        // 17502
1410        let another = "2017-12-02T00:00:00.000000";
1411
1412        let fixture = TestProjectionFixture::new(
1413            Transform::Day,
1414            "name",
1415            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1416        );
1417
1418        fixture.assert_projection(
1419            &fixture.binary_predicate(
1420                PredicateOperator::LessThan,
1421                Datum::timestamp_from_str(value)?,
1422            ),
1423            Some("name <= 2017-11-30"),
1424        )?;
1425
1426        fixture.assert_projection(
1427            &fixture.binary_predicate(
1428                PredicateOperator::LessThanOrEq,
1429                Datum::timestamp_from_str(value)?,
1430            ),
1431            Some("name <= 2017-12-01"),
1432        )?;
1433
1434        fixture.assert_projection(
1435            &fixture.binary_predicate(
1436                PredicateOperator::GreaterThan,
1437                Datum::timestamp_from_str(value)?,
1438            ),
1439            Some("name >= 2017-12-01"),
1440        )?;
1441
1442        fixture.assert_projection(
1443            &fixture.binary_predicate(
1444                PredicateOperator::GreaterThanOrEq,
1445                Datum::timestamp_from_str(value)?,
1446            ),
1447            Some("name >= 2017-12-01"),
1448        )?;
1449
1450        fixture.assert_projection(
1451            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1452            Some("name = 2017-12-01"),
1453        )?;
1454
1455        fixture.assert_projection(
1456            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1457            None,
1458        )?;
1459
1460        fixture.assert_projection(
1461            &fixture.set_predicate(PredicateOperator::In, vec![
1462                Datum::timestamp_from_str(value)?,
1463                Datum::timestamp_from_str(another)?,
1464            ]),
1465            Some("name IN (2017-12-02, 2017-12-01)"),
1466        )?;
1467
1468        fixture.assert_projection(
1469            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1470                Datum::timestamp_from_str(value)?,
1471                Datum::timestamp_from_str(another)?,
1472            ]),
1473            None,
1474        )?;
1475
1476        Ok(())
1477    }
1478
1479    #[test]
1480    fn test_projection_timestamp_day_epoch() -> Result<()> {
1481        // 0
1482        let value = "1970-01-01T00:00:00.00000";
1483        // 1
1484        let another = "1970-01-02T00:00:00.00000";
1485
1486        let fixture = TestProjectionFixture::new(
1487            Transform::Day,
1488            "name",
1489            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Timestamp)),
1490        );
1491
1492        fixture.assert_projection(
1493            &fixture.binary_predicate(
1494                PredicateOperator::LessThan,
1495                Datum::timestamp_from_str(value)?,
1496            ),
1497            Some("name <= 1970-01-01"),
1498        )?;
1499
1500        fixture.assert_projection(
1501            &fixture.binary_predicate(
1502                PredicateOperator::LessThanOrEq,
1503                Datum::timestamp_from_str(value)?,
1504            ),
1505            Some("name <= 1970-01-01"),
1506        )?;
1507
1508        fixture.assert_projection(
1509            &fixture.binary_predicate(
1510                PredicateOperator::GreaterThan,
1511                Datum::timestamp_from_str(value)?,
1512            ),
1513            Some("name >= 1970-01-01"),
1514        )?;
1515
1516        fixture.assert_projection(
1517            &fixture.binary_predicate(
1518                PredicateOperator::GreaterThanOrEq,
1519                Datum::timestamp_from_str(value)?,
1520            ),
1521            Some("name >= 1970-01-01"),
1522        )?;
1523
1524        fixture.assert_projection(
1525            &fixture.binary_predicate(PredicateOperator::Eq, Datum::timestamp_from_str(value)?),
1526            Some("name = 1970-01-01"),
1527        )?;
1528
1529        fixture.assert_projection(
1530            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::timestamp_from_str(value)?),
1531            None,
1532        )?;
1533
1534        fixture.assert_projection(
1535            &fixture.set_predicate(PredicateOperator::In, vec![
1536                Datum::timestamp_from_str(value)?,
1537                Datum::timestamp_from_str(another)?,
1538            ]),
1539            Some("name IN (1970-01-01, 1970-01-02)"),
1540        )?;
1541
1542        fixture.assert_projection(
1543            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1544                Datum::timestamp_from_str(value)?,
1545                Datum::timestamp_from_str(another)?,
1546            ]),
1547            None,
1548        )?;
1549
1550        Ok(())
1551    }
1552
1553    #[test]
1554    fn test_projection_date_day_negative() -> Result<()> {
1555        // -2
1556        let value = "1969-12-30";
1557        // -4
1558        let another = "1969-12-28";
1559
1560        let fixture = TestProjectionFixture::new(
1561            Transform::Day,
1562            "name",
1563            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1564        );
1565
1566        fixture.assert_projection(
1567            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1568            Some("name <= 1969-12-29"),
1569        )?;
1570
1571        fixture.assert_projection(
1572            &fixture.binary_predicate(
1573                PredicateOperator::LessThanOrEq,
1574                Datum::date_from_str(value)?,
1575            ),
1576            Some("name <= 1969-12-30"),
1577        )?;
1578
1579        fixture.assert_projection(
1580            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1581            Some("name >= 1969-12-31"),
1582        )?;
1583
1584        fixture.assert_projection(
1585            &fixture.binary_predicate(
1586                PredicateOperator::GreaterThanOrEq,
1587                Datum::date_from_str(value)?,
1588            ),
1589            Some("name >= 1969-12-30"),
1590        )?;
1591
1592        fixture.assert_projection(
1593            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1594            Some("name = 1969-12-30"),
1595        )?;
1596
1597        fixture.assert_projection(
1598            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1599            None,
1600        )?;
1601
1602        fixture.assert_projection(
1603            &fixture.set_predicate(PredicateOperator::In, vec![
1604                Datum::date_from_str(value)?,
1605                Datum::date_from_str(another)?,
1606            ]),
1607            Some("name IN (1969-12-28, 1969-12-30)"),
1608        )?;
1609
1610        fixture.assert_projection(
1611            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1612                Datum::date_from_str(value)?,
1613                Datum::date_from_str(another)?,
1614            ]),
1615            None,
1616        )?;
1617
1618        Ok(())
1619    }
1620
1621    #[test]
1622    fn test_projection_date_day() -> Result<()> {
1623        // 17167
1624        let value = "2017-01-01";
1625        // 17531
1626        let another = "2017-12-31";
1627
1628        let fixture = TestProjectionFixture::new(
1629            Transform::Day,
1630            "name",
1631            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1632        );
1633
1634        fixture.assert_projection(
1635            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1636            Some("name <= 2016-12-31"),
1637        )?;
1638
1639        fixture.assert_projection(
1640            &fixture.binary_predicate(
1641                PredicateOperator::LessThanOrEq,
1642                Datum::date_from_str(value)?,
1643            ),
1644            Some("name <= 2017-01-01"),
1645        )?;
1646
1647        fixture.assert_projection(
1648            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1649            Some("name >= 2017-01-02"),
1650        )?;
1651
1652        fixture.assert_projection(
1653            &fixture.binary_predicate(
1654                PredicateOperator::GreaterThanOrEq,
1655                Datum::date_from_str(value)?,
1656            ),
1657            Some("name >= 2017-01-01"),
1658        )?;
1659
1660        fixture.assert_projection(
1661            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1662            Some("name = 2017-01-01"),
1663        )?;
1664
1665        fixture.assert_projection(
1666            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1667            None,
1668        )?;
1669
1670        fixture.assert_projection(
1671            &fixture.set_predicate(PredicateOperator::In, vec![
1672                Datum::date_from_str(value)?,
1673                Datum::date_from_str(another)?,
1674            ]),
1675            Some("name IN (2017-01-01, 2017-12-31)"),
1676        )?;
1677
1678        fixture.assert_projection(
1679            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1680                Datum::date_from_str(value)?,
1681                Datum::date_from_str(another)?,
1682            ]),
1683            None,
1684        )?;
1685
1686        Ok(())
1687    }
1688
1689    #[test]
1690    fn test_projection_date_month_negative_upper_bound() -> Result<()> {
1691        // -1 => 1969-12
1692        let value = "1969-12-31";
1693        // -12 => 1969-01
1694        let another = "1969-01-01";
1695
1696        let fixture = TestProjectionFixture::new(
1697            Transform::Month,
1698            "name",
1699            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1700        );
1701
1702        fixture.assert_projection(
1703            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1704            Some("name <= 0"),
1705        )?;
1706
1707        fixture.assert_projection(
1708            &fixture.binary_predicate(
1709                PredicateOperator::LessThanOrEq,
1710                Datum::date_from_str(value)?,
1711            ),
1712            Some("name <= 0"),
1713        )?;
1714
1715        fixture.assert_projection(
1716            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1717            Some("name >= 0"),
1718        )?;
1719
1720        fixture.assert_projection(
1721            &fixture.binary_predicate(
1722                PredicateOperator::GreaterThanOrEq,
1723                Datum::date_from_str(value)?,
1724            ),
1725            Some("name >= -1"),
1726        )?;
1727
1728        fixture.assert_projection(
1729            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1730            Some("name IN (-1, 0)"),
1731        )?;
1732
1733        fixture.assert_projection(
1734            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1735            None,
1736        )?;
1737
1738        fixture.assert_projection(
1739            &fixture.set_predicate(PredicateOperator::In, vec![
1740                Datum::date_from_str(value)?,
1741                Datum::date_from_str(another)?,
1742            ]),
1743            Some("name IN (-1, -12, -11, 0)"),
1744        )?;
1745
1746        fixture.assert_projection(
1747            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1748                Datum::date_from_str(value)?,
1749                Datum::date_from_str(another)?,
1750            ]),
1751            None,
1752        )?;
1753
1754        Ok(())
1755    }
1756
1757    #[test]
1758    fn test_projection_date_month_upper_bound() -> Result<()> {
1759        // 575 => 2017-12
1760        let value = "2017-12-31";
1761        // 564 => 2017-01
1762        let another = "2017-01-01";
1763
1764        let fixture = TestProjectionFixture::new(
1765            Transform::Month,
1766            "name",
1767            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1768        );
1769
1770        fixture.assert_projection(
1771            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1772            Some("name <= 575"),
1773        )?;
1774
1775        fixture.assert_projection(
1776            &fixture.binary_predicate(
1777                PredicateOperator::LessThanOrEq,
1778                Datum::date_from_str(value)?,
1779            ),
1780            Some("name <= 575"),
1781        )?;
1782
1783        fixture.assert_projection(
1784            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1785            Some("name >= 576"),
1786        )?;
1787
1788        fixture.assert_projection(
1789            &fixture.binary_predicate(
1790                PredicateOperator::GreaterThanOrEq,
1791                Datum::date_from_str(value)?,
1792            ),
1793            Some("name >= 575"),
1794        )?;
1795
1796        fixture.assert_projection(
1797            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1798            Some("name = 575"),
1799        )?;
1800
1801        fixture.assert_projection(
1802            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1803            None,
1804        )?;
1805
1806        fixture.assert_projection(
1807            &fixture.set_predicate(PredicateOperator::In, vec![
1808                Datum::date_from_str(value)?,
1809                Datum::date_from_str(another)?,
1810            ]),
1811            Some("name IN (575, 564)"),
1812        )?;
1813
1814        fixture.assert_projection(
1815            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1816                Datum::date_from_str(value)?,
1817                Datum::date_from_str(another)?,
1818            ]),
1819            None,
1820        )?;
1821
1822        Ok(())
1823    }
1824
1825    #[test]
1826    fn test_projection_date_month_negative_lower_bound() -> Result<()> {
1827        // -12 => 1969-01
1828        let value = "1969-01-01";
1829        // -1 => 1969-12
1830        let another = "1969-12-31";
1831
1832        let fixture = TestProjectionFixture::new(
1833            Transform::Month,
1834            "name",
1835            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1836        );
1837
1838        fixture.assert_projection(
1839            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1840            Some("name <= -12"),
1841        )?;
1842
1843        fixture.assert_projection(
1844            &fixture.binary_predicate(
1845                PredicateOperator::LessThanOrEq,
1846                Datum::date_from_str(value)?,
1847            ),
1848            Some("name <= -11"),
1849        )?;
1850
1851        fixture.assert_projection(
1852            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1853            Some("name >= -12"),
1854        )?;
1855
1856        fixture.assert_projection(
1857            &fixture.binary_predicate(
1858                PredicateOperator::GreaterThanOrEq,
1859                Datum::date_from_str(value)?,
1860            ),
1861            Some("name >= -12"),
1862        )?;
1863
1864        fixture.assert_projection(
1865            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1866            Some("name IN (-12, -11)"),
1867        )?;
1868
1869        fixture.assert_projection(
1870            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1871            None,
1872        )?;
1873
1874        fixture.assert_projection(
1875            &fixture.set_predicate(PredicateOperator::In, vec![
1876                Datum::date_from_str(value)?,
1877                Datum::date_from_str(another)?,
1878            ]),
1879            Some("name IN (-1, -12, -11, 0)"),
1880        )?;
1881
1882        fixture.assert_projection(
1883            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1884                Datum::date_from_str(value)?,
1885                Datum::date_from_str(another)?,
1886            ]),
1887            None,
1888        )?;
1889
1890        Ok(())
1891    }
1892
1893    #[test]
1894    fn test_projection_date_month_lower_bound() -> Result<()> {
1895        // 575 => 2017-12
1896        let value = "2017-12-01";
1897        // 564 => 2017-01
1898        let another = "2017-01-01";
1899
1900        let fixture = TestProjectionFixture::new(
1901            Transform::Month,
1902            "name",
1903            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1904        );
1905
1906        fixture.assert_projection(
1907            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1908            Some("name <= 574"),
1909        )?;
1910
1911        fixture.assert_projection(
1912            &fixture.binary_predicate(
1913                PredicateOperator::LessThanOrEq,
1914                Datum::date_from_str(value)?,
1915            ),
1916            Some("name <= 575"),
1917        )?;
1918
1919        fixture.assert_projection(
1920            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1921            Some("name >= 575"),
1922        )?;
1923
1924        fixture.assert_projection(
1925            &fixture.binary_predicate(
1926                PredicateOperator::GreaterThanOrEq,
1927                Datum::date_from_str(value)?,
1928            ),
1929            Some("name >= 575"),
1930        )?;
1931
1932        fixture.assert_projection(
1933            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
1934            Some("name = 575"),
1935        )?;
1936
1937        fixture.assert_projection(
1938            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
1939            None,
1940        )?;
1941
1942        fixture.assert_projection(
1943            &fixture.set_predicate(PredicateOperator::In, vec![
1944                Datum::date_from_str(value)?,
1945                Datum::date_from_str(another)?,
1946            ]),
1947            Some("name IN (575, 564)"),
1948        )?;
1949
1950        fixture.assert_projection(
1951            &fixture.set_predicate(PredicateOperator::NotIn, vec![
1952                Datum::date_from_str(value)?,
1953                Datum::date_from_str(another)?,
1954            ]),
1955            None,
1956        )?;
1957
1958        Ok(())
1959    }
1960
1961    #[test]
1962    fn test_projection_date_month_epoch() -> Result<()> {
1963        // 0 => 1970-01
1964        let value = "1970-01-01";
1965        // -1 => 1969-12
1966        let another = "1969-12-31";
1967
1968        let fixture = TestProjectionFixture::new(
1969            Transform::Month,
1970            "name",
1971            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
1972        );
1973
1974        fixture.assert_projection(
1975            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
1976            Some("name <= 0"),
1977        )?;
1978
1979        fixture.assert_projection(
1980            &fixture.binary_predicate(
1981                PredicateOperator::LessThanOrEq,
1982                Datum::date_from_str(value)?,
1983            ),
1984            Some("name <= 0"),
1985        )?;
1986
1987        fixture.assert_projection(
1988            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
1989            Some("name >= 0"),
1990        )?;
1991
1992        fixture.assert_projection(
1993            &fixture.binary_predicate(
1994                PredicateOperator::GreaterThanOrEq,
1995                Datum::date_from_str(value)?,
1996            ),
1997            Some("name >= 0"),
1998        )?;
1999
2000        fixture.assert_projection(
2001            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
2002            Some("name = 0"),
2003        )?;
2004
2005        fixture.assert_projection(
2006            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
2007            None,
2008        )?;
2009
2010        fixture.assert_projection(
2011            &fixture.set_predicate(PredicateOperator::In, vec![
2012                Datum::date_from_str(value)?,
2013                Datum::date_from_str(another)?,
2014            ]),
2015            Some("name IN (0, -1)"),
2016        )?;
2017
2018        fixture.assert_projection(
2019            &fixture.set_predicate(PredicateOperator::NotIn, vec![
2020                Datum::date_from_str(value)?,
2021                Datum::date_from_str(another)?,
2022            ]),
2023            None,
2024        )?;
2025
2026        Ok(())
2027    }
2028
2029    #[test]
2030    fn test_projection_date_year_negative_upper_bound() -> Result<()> {
2031        // -1 => 1969
2032        let value = "1969-12-31";
2033        let another = "1969-01-01";
2034
2035        let fixture = TestProjectionFixture::new(
2036            Transform::Year,
2037            "name",
2038            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
2039        );
2040
2041        fixture.assert_projection(
2042            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
2043            Some("name <= 0"),
2044        )?;
2045
2046        fixture.assert_projection(
2047            &fixture.binary_predicate(
2048                PredicateOperator::LessThanOrEq,
2049                Datum::date_from_str(value)?,
2050            ),
2051            Some("name <= 0"),
2052        )?;
2053
2054        fixture.assert_projection(
2055            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
2056            Some("name >= 0"),
2057        )?;
2058
2059        fixture.assert_projection(
2060            &fixture.binary_predicate(
2061                PredicateOperator::GreaterThanOrEq,
2062                Datum::date_from_str(value)?,
2063            ),
2064            Some("name >= -1"),
2065        )?;
2066
2067        fixture.assert_projection(
2068            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
2069            Some("name IN (-1, 0)"),
2070        )?;
2071
2072        fixture.assert_projection(
2073            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
2074            None,
2075        )?;
2076
2077        fixture.assert_projection(
2078            &fixture.set_predicate(PredicateOperator::In, vec![
2079                Datum::date_from_str(value)?,
2080                Datum::date_from_str(another)?,
2081            ]),
2082            Some("name IN (0, -1)"),
2083        )?;
2084
2085        fixture.assert_projection(
2086            &fixture.set_predicate(PredicateOperator::NotIn, vec![
2087                Datum::date_from_str(value)?,
2088                Datum::date_from_str(another)?,
2089            ]),
2090            None,
2091        )?;
2092
2093        Ok(())
2094    }
2095
2096    #[test]
2097    fn test_projection_date_year_upper_bound() -> Result<()> {
2098        // 47 => 2017
2099        let value = "2017-12-31";
2100        // 46 => 2016
2101        let another = "2016-01-01";
2102
2103        let fixture = TestProjectionFixture::new(
2104            Transform::Year,
2105            "name",
2106            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
2107        );
2108
2109        fixture.assert_projection(
2110            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
2111            Some("name <= 47"),
2112        )?;
2113
2114        fixture.assert_projection(
2115            &fixture.binary_predicate(
2116                PredicateOperator::LessThanOrEq,
2117                Datum::date_from_str(value)?,
2118            ),
2119            Some("name <= 47"),
2120        )?;
2121
2122        fixture.assert_projection(
2123            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
2124            Some("name >= 48"),
2125        )?;
2126
2127        fixture.assert_projection(
2128            &fixture.binary_predicate(
2129                PredicateOperator::GreaterThanOrEq,
2130                Datum::date_from_str(value)?,
2131            ),
2132            Some("name >= 47"),
2133        )?;
2134
2135        fixture.assert_projection(
2136            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
2137            Some("name = 47"),
2138        )?;
2139
2140        fixture.assert_projection(
2141            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
2142            None,
2143        )?;
2144
2145        fixture.assert_projection(
2146            &fixture.set_predicate(PredicateOperator::In, vec![
2147                Datum::date_from_str(value)?,
2148                Datum::date_from_str(another)?,
2149            ]),
2150            Some("name IN (47, 46)"),
2151        )?;
2152
2153        fixture.assert_projection(
2154            &fixture.set_predicate(PredicateOperator::NotIn, vec![
2155                Datum::date_from_str(value)?,
2156                Datum::date_from_str(another)?,
2157            ]),
2158            None,
2159        )?;
2160
2161        Ok(())
2162    }
2163
2164    #[test]
2165    fn test_projection_date_year_negative_lower_bound() -> Result<()> {
2166        // 0 => 1970
2167        let value = "1970-01-01";
2168        // -1 => 1969
2169        let another = "1969-12-31";
2170
2171        let fixture = TestProjectionFixture::new(
2172            Transform::Year,
2173            "name",
2174            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
2175        );
2176
2177        fixture.assert_projection(
2178            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
2179            Some("name <= 0"),
2180        )?;
2181
2182        fixture.assert_projection(
2183            &fixture.binary_predicate(
2184                PredicateOperator::LessThanOrEq,
2185                Datum::date_from_str(value)?,
2186            ),
2187            Some("name <= 0"),
2188        )?;
2189
2190        fixture.assert_projection(
2191            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
2192            Some("name >= 0"),
2193        )?;
2194
2195        fixture.assert_projection(
2196            &fixture.binary_predicate(
2197                PredicateOperator::GreaterThanOrEq,
2198                Datum::date_from_str(value)?,
2199            ),
2200            Some("name >= 0"),
2201        )?;
2202
2203        fixture.assert_projection(
2204            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
2205            Some("name = 0"),
2206        )?;
2207
2208        fixture.assert_projection(
2209            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
2210            None,
2211        )?;
2212
2213        fixture.assert_projection(
2214            &fixture.set_predicate(PredicateOperator::In, vec![
2215                Datum::date_from_str(value)?,
2216                Datum::date_from_str(another)?,
2217            ]),
2218            Some("name IN (0, -1)"),
2219        )?;
2220
2221        fixture.assert_projection(
2222            &fixture.set_predicate(PredicateOperator::NotIn, vec![
2223                Datum::date_from_str(value)?,
2224                Datum::date_from_str(another)?,
2225            ]),
2226            None,
2227        )?;
2228
2229        Ok(())
2230    }
2231
2232    #[test]
2233    fn test_projection_date_year_lower_bound() -> Result<()> {
2234        // 47 => 2017
2235        let value = "2017-01-01";
2236        // 46 => 2016
2237        let another = "2016-12-31";
2238
2239        let fixture = TestProjectionFixture::new(
2240            Transform::Year,
2241            "name",
2242            NestedField::required(1, "value", Type::Primitive(PrimitiveType::Date)),
2243        );
2244
2245        fixture.assert_projection(
2246            &fixture.binary_predicate(PredicateOperator::LessThan, Datum::date_from_str(value)?),
2247            Some("name <= 46"),
2248        )?;
2249
2250        fixture.assert_projection(
2251            &fixture.binary_predicate(
2252                PredicateOperator::LessThanOrEq,
2253                Datum::date_from_str(value)?,
2254            ),
2255            Some("name <= 47"),
2256        )?;
2257
2258        fixture.assert_projection(
2259            &fixture.binary_predicate(PredicateOperator::GreaterThan, Datum::date_from_str(value)?),
2260            Some("name >= 47"),
2261        )?;
2262
2263        fixture.assert_projection(
2264            &fixture.binary_predicate(
2265                PredicateOperator::GreaterThanOrEq,
2266                Datum::date_from_str(value)?,
2267            ),
2268            Some("name >= 47"),
2269        )?;
2270
2271        fixture.assert_projection(
2272            &fixture.binary_predicate(PredicateOperator::Eq, Datum::date_from_str(value)?),
2273            Some("name = 47"),
2274        )?;
2275
2276        fixture.assert_projection(
2277            &fixture.binary_predicate(PredicateOperator::NotEq, Datum::date_from_str(value)?),
2278            None,
2279        )?;
2280
2281        fixture.assert_projection(
2282            &fixture.set_predicate(PredicateOperator::In, vec![
2283                Datum::date_from_str(value)?,
2284                Datum::date_from_str(another)?,
2285            ]),
2286            Some("name IN (47, 46)"),
2287        )?;
2288
2289        fixture.assert_projection(
2290            &fixture.set_predicate(PredicateOperator::NotIn, vec![
2291                Datum::date_from_str(value)?,
2292                Datum::date_from_str(another)?,
2293            ]),
2294            None,
2295        )?;
2296
2297        Ok(())
2298    }
2299
2300    #[test]
2301    fn test_transform_years() {
2302        let year = super::Year;
2303
2304        // Test Date32
2305        let ori_date = vec![
2306            NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
2307            NaiveDate::from_ymd_opt(2000, 1, 1).unwrap(),
2308            NaiveDate::from_ymd_opt(2030, 1, 1).unwrap(),
2309            NaiveDate::from_ymd_opt(2060, 1, 1).unwrap(),
2310            NaiveDate::from_ymd_opt(1969, 1, 1).unwrap(),
2311        ];
2312        let date_array: ArrayRef = Arc::new(Date32Array::from(
2313            ori_date
2314                .into_iter()
2315                .map(|date| {
2316                    date.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())
2317                        .num_days() as i32
2318                })
2319                .collect::<Vec<i32>>(),
2320        ));
2321        let res = year.transform(date_array).unwrap();
2322        let res = res.as_any().downcast_ref::<Int32Array>().unwrap();
2323        assert_eq!(res.len(), 5);
2324        assert_eq!(res.value(0), 0);
2325        assert_eq!(res.value(1), 30);
2326        assert_eq!(res.value(2), 60);
2327        assert_eq!(res.value(3), 90);
2328        assert_eq!(res.value(4), -1);
2329
2330        // Test TimestampMicrosecond
2331        let ori_timestamp = vec![
2332            NaiveDateTime::parse_from_str("1970-01-01 12:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2333                .unwrap(),
2334            NaiveDateTime::parse_from_str("2000-01-01 19:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2335                .unwrap(),
2336            NaiveDateTime::parse_from_str("2030-01-01 10:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2337                .unwrap(),
2338            NaiveDateTime::parse_from_str("2060-01-01 11:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2339                .unwrap(),
2340            NaiveDateTime::parse_from_str("1969-01-01 00:00:00.00", "%Y-%m-%d %H:%M:%S.%f")
2341                .unwrap(),
2342        ];
2343        let date_array: ArrayRef = Arc::new(TimestampMicrosecondArray::from(
2344            ori_timestamp
2345                .into_iter()
2346                .map(|timestamp| {
2347                    timestamp
2348                        .signed_duration_since(
2349                            NaiveDateTime::parse_from_str(
2350                                "1970-01-01 00:00:00.0",
2351                                "%Y-%m-%d %H:%M:%S.%f",
2352                            )
2353                            .unwrap(),
2354                        )
2355                        .num_microseconds()
2356                        .unwrap()
2357                })
2358                .collect::<Vec<i64>>(),
2359        ));
2360        let res = year.transform(date_array).unwrap();
2361        let res = res.as_any().downcast_ref::<Int32Array>().unwrap();
2362        assert_eq!(res.len(), 5);
2363        assert_eq!(res.value(0), 0);
2364        assert_eq!(res.value(1), 30);
2365        assert_eq!(res.value(2), 60);
2366        assert_eq!(res.value(3), 90);
2367        assert_eq!(res.value(4), -1);
2368    }
2369
2370    fn test_timestamp_and_tz_transform(
2371        time: &str,
2372        transform: &BoxedTransformFunction,
2373        expect: Datum,
2374    ) {
2375        let timestamp = Datum::timestamp_from_str(time).unwrap();
2376        let timestamp_tz = Datum::timestamptz_from_str(time.to_owned() + " +00:00").unwrap();
2377        let res = transform.transform_literal(&timestamp).unwrap().unwrap();
2378        assert_eq!(res, expect);
2379        let res = transform.transform_literal(&timestamp_tz).unwrap().unwrap();
2380        assert_eq!(res, expect);
2381    }
2382
2383    fn test_timestamp_and_tz_transform_using_i64(
2384        time: i64,
2385        transform: &BoxedTransformFunction,
2386        expect: Datum,
2387    ) {
2388        let timestamp = Datum::timestamp_micros(time);
2389        let timestamp_tz = Datum::timestamptz_micros(time);
2390        let res = transform.transform_literal(&timestamp).unwrap().unwrap();
2391        assert_eq!(res, expect);
2392        let res = transform.transform_literal(&timestamp_tz).unwrap().unwrap();
2393        assert_eq!(res, expect);
2394    }
2395
2396    fn test_date(date: i32, transform: &BoxedTransformFunction, expect: Datum) {
2397        let date = Datum::date(date);
2398        let res = transform.transform_literal(&date).unwrap().unwrap();
2399        assert_eq!(res, expect);
2400    }
2401
2402    fn test_timestamp_ns_and_tz_transform(
2403        time: &str,
2404        transform: &BoxedTransformFunction,
2405        expect: Datum,
2406    ) {
2407        let timestamp_ns = Datum::timestamp_from_str(time).unwrap();
2408        let timestamptz_ns = Datum::timestamptz_from_str(time.to_owned() + " +00:00").unwrap();
2409        let res = transform.transform_literal(&timestamp_ns).unwrap().unwrap();
2410        assert_eq!(res, expect);
2411        let res = transform
2412            .transform_literal(&timestamptz_ns)
2413            .unwrap()
2414            .unwrap();
2415        assert_eq!(res, expect);
2416    }
2417
2418    fn test_timestamp_ns_and_tz_transform_using_i64(
2419        time: i64,
2420        transform: &BoxedTransformFunction,
2421        expect: Datum,
2422    ) {
2423        let timestamp_ns = Datum::timestamp_nanos(time);
2424        let timestamptz_ns = Datum::timestamptz_nanos(time);
2425        let res = transform.transform_literal(&timestamp_ns).unwrap().unwrap();
2426        assert_eq!(res, expect);
2427        let res = transform
2428            .transform_literal(&timestamptz_ns)
2429            .unwrap()
2430            .unwrap();
2431        assert_eq!(res, expect);
2432    }
2433
2434    #[test]
2435    fn test_transform_year_literal() {
2436        let year = Box::new(super::Year) as BoxedTransformFunction;
2437
2438        // Test Date32
2439        test_date(18628, &year, Datum::int(2021 - super::UNIX_EPOCH_YEAR));
2440        test_date(-365, &year, Datum::int(-1));
2441
2442        // Test TimestampMicrosecond
2443        test_timestamp_and_tz_transform_using_i64(
2444            186280000000,
2445            &year,
2446            Datum::int(1970 - super::UNIX_EPOCH_YEAR),
2447        );
2448        test_timestamp_and_tz_transform("1969-01-01T00:00:00.000000", &year, Datum::int(-1));
2449
2450        // Test TimestampNanosecond
2451        test_timestamp_ns_and_tz_transform_using_i64(
2452            186280000000,
2453            &year,
2454            Datum::int(1970 - super::UNIX_EPOCH_YEAR),
2455        );
2456        test_timestamp_ns_and_tz_transform("1969-01-01T00:00:00.000000", &year, Datum::int(-1));
2457    }
2458
2459    #[test]
2460    fn test_transform_months() {
2461        let month = super::Month;
2462
2463        // Test Date32
2464        let ori_date = vec![
2465            NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
2466            NaiveDate::from_ymd_opt(2000, 4, 1).unwrap(),
2467            NaiveDate::from_ymd_opt(2030, 7, 1).unwrap(),
2468            NaiveDate::from_ymd_opt(2060, 10, 1).unwrap(),
2469            NaiveDate::from_ymd_opt(1969, 12, 1).unwrap(),
2470        ];
2471        let date_array: ArrayRef = Arc::new(Date32Array::from(
2472            ori_date
2473                .into_iter()
2474                .map(|date| {
2475                    date.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())
2476                        .num_days() as i32
2477                })
2478                .collect::<Vec<i32>>(),
2479        ));
2480        let res = month.transform(date_array).unwrap();
2481        let res = res.as_any().downcast_ref::<Int32Array>().unwrap();
2482        assert_eq!(res.len(), 5);
2483        assert_eq!(res.value(0), 0);
2484        assert_eq!(res.value(1), 30 * 12 + 3);
2485        assert_eq!(res.value(2), 60 * 12 + 6);
2486        assert_eq!(res.value(3), 90 * 12 + 9);
2487        assert_eq!(res.value(4), -1);
2488
2489        // Test TimestampMicrosecond
2490        let ori_timestamp = vec![
2491            NaiveDateTime::parse_from_str("1970-01-01 12:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2492                .unwrap(),
2493            NaiveDateTime::parse_from_str("2000-04-01 19:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2494                .unwrap(),
2495            NaiveDateTime::parse_from_str("2030-07-01 10:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2496                .unwrap(),
2497            NaiveDateTime::parse_from_str("2060-10-01 11:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2498                .unwrap(),
2499            NaiveDateTime::parse_from_str("1969-12-01 00:00:00.00", "%Y-%m-%d %H:%M:%S.%f")
2500                .unwrap(),
2501        ];
2502        let date_array: ArrayRef = Arc::new(TimestampMicrosecondArray::from(
2503            ori_timestamp
2504                .into_iter()
2505                .map(|timestamp| {
2506                    timestamp
2507                        .signed_duration_since(
2508                            NaiveDateTime::parse_from_str(
2509                                "1970-01-01 00:00:00.0",
2510                                "%Y-%m-%d %H:%M:%S.%f",
2511                            )
2512                            .unwrap(),
2513                        )
2514                        .num_microseconds()
2515                        .unwrap()
2516                })
2517                .collect::<Vec<i64>>(),
2518        ));
2519        let res = month.transform(date_array).unwrap();
2520        let res = res.as_any().downcast_ref::<Int32Array>().unwrap();
2521        assert_eq!(res.len(), 5);
2522        assert_eq!(res.value(0), 0);
2523        assert_eq!(res.value(1), 30 * 12 + 3);
2524        assert_eq!(res.value(2), 60 * 12 + 6);
2525        assert_eq!(res.value(3), 90 * 12 + 9);
2526        assert_eq!(res.value(4), -1);
2527    }
2528
2529    #[test]
2530    fn test_transform_month_literal() {
2531        let month = Box::new(super::Month) as BoxedTransformFunction;
2532
2533        // Test Date32
2534        test_date(
2535            18628,
2536            &month,
2537            Datum::int((2021 - super::UNIX_EPOCH_YEAR) * 12),
2538        );
2539        test_date(-31, &month, Datum::int(-1));
2540
2541        // Test TimestampMicrosecond
2542        test_timestamp_and_tz_transform_using_i64(
2543            186280000000,
2544            &month,
2545            Datum::int((1970 - super::UNIX_EPOCH_YEAR) * 12),
2546        );
2547        test_timestamp_and_tz_transform("1969-12-01T23:00:00.000000", &month, Datum::int(-1));
2548        test_timestamp_and_tz_transform("2017-12-01T00:00:00.000000", &month, Datum::int(575));
2549        test_timestamp_and_tz_transform("1970-01-01T00:00:00.000000", &month, Datum::int(0));
2550        test_timestamp_and_tz_transform("1969-12-31T00:00:00.000000", &month, Datum::int(-1));
2551
2552        // Test TimestampNanosecond
2553        test_timestamp_ns_and_tz_transform_using_i64(
2554            186280000000,
2555            &month,
2556            Datum::int((1970 - super::UNIX_EPOCH_YEAR) * 12),
2557        );
2558        test_timestamp_ns_and_tz_transform("1969-12-01T23:00:00.000000", &month, Datum::int(-1));
2559        test_timestamp_ns_and_tz_transform("2017-12-01T00:00:00.000000", &month, Datum::int(575));
2560        test_timestamp_ns_and_tz_transform("1970-01-01T00:00:00.000000", &month, Datum::int(0));
2561        test_timestamp_ns_and_tz_transform("1969-12-31T00:00:00.000000", &month, Datum::int(-1));
2562    }
2563
2564    #[test]
2565    fn test_transform_days() {
2566        let day = super::Day;
2567        let ori_date = vec![
2568            NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
2569            NaiveDate::from_ymd_opt(2000, 4, 1).unwrap(),
2570            NaiveDate::from_ymd_opt(2030, 7, 1).unwrap(),
2571            NaiveDate::from_ymd_opt(2060, 10, 1).unwrap(),
2572            NaiveDate::from_ymd_opt(1969, 12, 31).unwrap(),
2573        ];
2574        let expect_day = ori_date
2575            .clone()
2576            .into_iter()
2577            .map(|data| {
2578                data.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())
2579                    .num_days() as i32
2580            })
2581            .collect::<Vec<i32>>();
2582
2583        // Test Date32
2584        let date_array: ArrayRef = Arc::new(Date32Array::from(
2585            ori_date
2586                .into_iter()
2587                .map(|date| {
2588                    date.signed_duration_since(NaiveDate::from_ymd_opt(1970, 1, 1).unwrap())
2589                        .num_days() as i32
2590                })
2591                .collect::<Vec<i32>>(),
2592        ));
2593        let res = day.transform(date_array).unwrap();
2594        let res = res.as_any().downcast_ref::<Date32Array>().unwrap();
2595        assert_eq!(res.len(), 5);
2596        assert_eq!(res.value(0), expect_day[0]);
2597        assert_eq!(res.value(1), expect_day[1]);
2598        assert_eq!(res.value(2), expect_day[2]);
2599        assert_eq!(res.value(3), expect_day[3]);
2600        assert_eq!(res.value(4), -1);
2601
2602        // Test TimestampMicrosecond
2603        let ori_timestamp = vec![
2604            NaiveDateTime::parse_from_str("1970-01-01 12:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2605                .unwrap(),
2606            NaiveDateTime::parse_from_str("2000-04-01 19:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2607                .unwrap(),
2608            NaiveDateTime::parse_from_str("2030-07-01 10:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2609                .unwrap(),
2610            NaiveDateTime::parse_from_str("2060-10-01 11:30:42.123", "%Y-%m-%d %H:%M:%S.%f")
2611                .unwrap(),
2612            NaiveDateTime::parse_from_str("1969-12-31 00:00:00.00", "%Y-%m-%d %H:%M:%S.%f")
2613                .unwrap(),
2614        ];
2615        let date_array: ArrayRef = Arc::new(TimestampMicrosecondArray::from(
2616            ori_timestamp
2617                .into_iter()
2618                .map(|timestamp| {
2619                    timestamp
2620                        .signed_duration_since(
2621                            NaiveDateTime::parse_from_str(
2622                                "1970-01-01 00:00:00.0",
2623                                "%Y-%m-%d %H:%M:%S.%f",
2624                            )
2625                            .unwrap(),
2626                        )
2627                        .num_microseconds()
2628                        .unwrap()
2629                })
2630                .collect::<Vec<i64>>(),
2631        ));
2632        let res = day.transform(date_array).unwrap();
2633        let res = res.as_any().downcast_ref::<Date32Array>().unwrap();
2634        assert_eq!(res.len(), 5);
2635        assert_eq!(res.value(0), expect_day[0]);
2636        assert_eq!(res.value(1), expect_day[1]);
2637        assert_eq!(res.value(2), expect_day[2]);
2638        assert_eq!(res.value(3), expect_day[3]);
2639        assert_eq!(res.value(4), -1);
2640    }
2641
2642    #[test]
2643    fn test_transform_days_literal() {
2644        let day = Box::new(super::Day) as BoxedTransformFunction;
2645        // Test Date32
2646        test_date(18628, &day, Datum::date(18628));
2647        test_date(-31, &day, Datum::date(-31));
2648
2649        // Test TimestampMicrosecond
2650        test_timestamp_and_tz_transform_using_i64(1512151975038194, &day, Datum::date(17501));
2651        test_timestamp_and_tz_transform_using_i64(-115200000000, &day, Datum::date(-2));
2652        test_timestamp_and_tz_transform("2017-12-01T10:30:42.123000", &day, Datum::date(17501));
2653
2654        // Test TimestampNanosecond
2655        test_timestamp_ns_and_tz_transform_using_i64(1512151975038194, &day, Datum::date(17));
2656        test_timestamp_ns_and_tz_transform_using_i64(-115200000000, &day, Datum::date(-1));
2657        test_timestamp_ns_and_tz_transform("2017-12-01T10:30:42.123000", &day, Datum::date(17501));
2658    }
2659
2660    #[test]
2661    fn test_transform_hours() {
2662        let hour = super::Hour;
2663        let ori_timestamp = vec![
2664            NaiveDateTime::parse_from_str("1970-01-01 19:01:23.123", "%Y-%m-%d %H:%M:%S.%f")
2665                .unwrap(),
2666            NaiveDateTime::parse_from_str("2000-03-01 12:01:23.123", "%Y-%m-%d %H:%M:%S.%f")
2667                .unwrap(),
2668            NaiveDateTime::parse_from_str("2030-10-02 10:01:23.123", "%Y-%m-%d %H:%M:%S.%f")
2669                .unwrap(),
2670            NaiveDateTime::parse_from_str("2060-09-01 05:03:23.123", "%Y-%m-%d %H:%M:%S.%f")
2671                .unwrap(),
2672            NaiveDateTime::parse_from_str("1969-12-31 23:00:00.00", "%Y-%m-%d %H:%M:%S.%f")
2673                .unwrap(),
2674        ];
2675        let expect_hour = ori_timestamp
2676            .clone()
2677            .into_iter()
2678            .map(|timestamp| {
2679                timestamp
2680                    .signed_duration_since(
2681                        NaiveDateTime::parse_from_str(
2682                            "1970-01-01 00:00:0.0",
2683                            "%Y-%m-%d %H:%M:%S.%f",
2684                        )
2685                        .unwrap(),
2686                    )
2687                    .num_hours() as i32
2688            })
2689            .collect::<Vec<i32>>();
2690
2691        // Test TimestampMicrosecond
2692        let date_array: ArrayRef = Arc::new(TimestampMicrosecondArray::from(
2693            ori_timestamp
2694                .into_iter()
2695                .map(|timestamp| {
2696                    timestamp
2697                        .signed_duration_since(
2698                            NaiveDateTime::parse_from_str(
2699                                "1970-01-01 00:00:0.0",
2700                                "%Y-%m-%d %H:%M:%S.%f",
2701                            )
2702                            .unwrap(),
2703                        )
2704                        .num_microseconds()
2705                        .unwrap()
2706                })
2707                .collect::<Vec<i64>>(),
2708        ));
2709        let res = hour.transform(date_array).unwrap();
2710        let res = res.as_any().downcast_ref::<Int32Array>().unwrap();
2711        assert_eq!(res.len(), 5);
2712        assert_eq!(res.value(0), expect_hour[0]);
2713        assert_eq!(res.value(1), expect_hour[1]);
2714        assert_eq!(res.value(2), expect_hour[2]);
2715        assert_eq!(res.value(3), expect_hour[3]);
2716        assert_eq!(res.value(4), -1);
2717    }
2718
2719    #[test]
2720    fn test_transform_hours_literal() {
2721        let hour = Box::new(super::Hour) as BoxedTransformFunction;
2722
2723        test_timestamp_and_tz_transform("2017-12-01T18:00:00.000000", &hour, Datum::int(420042));
2724        test_timestamp_and_tz_transform("1970-01-01T22:01:01.000000", &hour, Datum::int(22));
2725        test_timestamp_and_tz_transform("1969-12-31T23:00:00.000000", &hour, Datum::int(-1));
2726        test_timestamp_and_tz_transform("1969-12-31T22:01:01.000000", &hour, Datum::int(-2));
2727        test_timestamp_and_tz_transform("0022-05-01T22:01:01.000000", &hour, Datum::int(-17072906));
2728
2729        // Test TimestampNanosecond
2730        test_timestamp_ns_and_tz_transform(
2731            "2017-12-01T18:00:00.0000000000",
2732            &hour,
2733            Datum::int(420042),
2734        );
2735        test_timestamp_ns_and_tz_transform("1969-12-31T23:00:00.0000000000", &hour, Datum::int(-1));
2736        test_timestamp_ns_and_tz_transform(
2737            "1900-05-01T22:01:01.0000000000",
2738            &hour,
2739            Datum::int(-610706),
2740        );
2741    }
2742}