From 2fafd9ec4fc5de8461a71f2c9adeca1b919c11ca Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Wed, 1 Feb 2023 23:02:39 +0100 Subject: [PATCH 1/6] Use `assert_eq!` in `test_type` for better error messages. --- src/impls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 19615e1..f130dd6 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -152,11 +152,11 @@ mod test { let stmt = conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); let result = conn.query(&stmt, &[]).unwrap().iter().next().unwrap().get(0); - assert!(val == &result); + assert_eq!(val, &result); let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap(); let result = conn.query(&stmt, &[val]).unwrap().iter().next().unwrap().get(0); - assert!(val == &result); + assert_eq!(val, &result); } } From f450f85cbf004acd3c91b62a1a594d4a0c443354 Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Wed, 1 Feb 2023 23:03:22 +0100 Subject: [PATCH 2/6] with_chrono_0_4: Use NaiveDateTime directly. This fixes one tests for non-UTC systems. --- src/impls.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index f130dd6..4f61298 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -173,15 +173,15 @@ mod test { #[test] #[cfg(feature = "with-chrono-0_4")] fn test_tsrange_params() { - let low = Utc.timestamp(0, 0); + let low = NaiveDateTime::from_timestamp_opt(0, 0).unwrap(); let high = low + Duration::days(10); - test_range!("TSRANGE", NaiveDateTime, low.naive_utc(), "1970-01-01", high.naive_utc(), "1970-01-11"); + test_range!("TSRANGE", NaiveDateTime, low, "1970-01-01", high, "1970-01-11"); } #[test] #[cfg(feature = "with-chrono-0_4")] fn test_tstzrange_params() { - let low = Utc.timestamp(0, 0); + let low = Utc.timestamp_opt(0, 0).unwrap(); let high = low + Duration::days(10); test_range!("TSTZRANGE", DateTime, low, "1970-01-01", high, "1970-01-11"); } From f4e7b0e788e56e9e6092a130e7d61f38635e86cf Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Wed, 1 Feb 2023 23:20:12 +0100 Subject: [PATCH 3/6] Test representations of TSRANGE and TZRANGE with time & date --- src/impls.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 4f61298..6a71a7f 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -118,7 +118,7 @@ mod test { use postgres::{Client, NoTls}; use postgres::types::{FromSql, ToSql}; #[cfg(feature = "with-chrono-0_4")] - use chrono_04::{TimeZone, Utc, Duration}; + use chrono_04::{NaiveDate, NaiveTime, NaiveDateTime, TimeZone, Utc, Duration}; macro_rules! test_range { ($name:expr, $t:ty, $low:expr, $low_str:expr, $high:expr, $high_str:expr) => ({ @@ -173,16 +173,19 @@ mod test { #[test] #[cfg(feature = "with-chrono-0_4")] fn test_tsrange_params() { - let low = NaiveDateTime::from_timestamp_opt(0, 0).unwrap(); + let d = NaiveDate::from_ymd_opt(2015, 6, 3).unwrap(); + let t = NaiveTime::from_hms_milli_opt(12, 34, 56, 789).unwrap(); + + let low = NaiveDateTime::new(d, t); let high = low + Duration::days(10); - test_range!("TSRANGE", NaiveDateTime, low, "1970-01-01", high, "1970-01-11"); + test_range!("TSRANGE", NaiveDateTime, low, "2015-06-03T12:34:56.789", high, "2015-06-13T12:34:56.789"); } #[test] #[cfg(feature = "with-chrono-0_4")] fn test_tstzrange_params() { - let low = Utc.timestamp_opt(0, 0).unwrap(); + let low = Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(); let high = low + Duration::days(10); - test_range!("TSTZRANGE", DateTime, low, "1970-01-01", high, "1970-01-11"); + test_range!("TSTZRANGE", DateTime<_>, low, "2014-07-08T09:10:11Z", high, "2014-07-18T09:10:11Z"); } } From c221b2b9fda69b3af7b98868e90d1bfeb97c658d Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Wed, 1 Feb 2023 23:41:47 +0100 Subject: [PATCH 4/6] chrono: Add implementations for daterange --- src/chrono_04.rs | 23 ++++++++++++++++++++++- src/impls.rs | 10 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/chrono_04.rs b/src/chrono_04.rs index be9a741..cf59fb8 100644 --- a/src/chrono_04.rs +++ b/src/chrono_04.rs @@ -1,4 +1,4 @@ -use chrono_04::{DateTime, NaiveDateTime, TimeZone}; +use chrono_04::{DateTime, NaiveDateTime, TimeZone, NaiveDate, NaiveTime}; use crate::{Normalizable, RangeBound, BoundSided}; @@ -20,4 +20,25 @@ impl Normalizable for NaiveDateTime { bound } +} + + +impl Normalizable for NaiveDate +{ + fn normalize(bound: RangeBound) -> RangeBound + where + S: BoundSided, + { + bound + } +} + +impl Normalizable for NaiveTime +{ + fn normalize(bound: RangeBound) -> RangeBound + where + S: BoundSided, + { + bound + } } \ No newline at end of file diff --git a/src/impls.rs b/src/impls.rs index 6a71a7f..a2ce2fe 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -188,4 +188,14 @@ mod test { let high = low + Duration::days(10); test_range!("TSTZRANGE", DateTime<_>, low, "2014-07-08T09:10:11Z", high, "2014-07-18T09:10:11Z"); } + + + #[test] + #[cfg(feature = "with-chrono-0_4")] + #[ignore = "Exclusive starts will be converted to next-day + inclusive"] + fn test_daterange_params() { + let low = NaiveDate::from_ymd_opt(2015, 6, 4).unwrap(); + let high = low + Duration::days(10); + test_range!("DATERANGE", NaiveDate, low, "2015-06-04", high, "2015-06-14"); + } } From 804a557528f4da7b7e2ee83b68fad34b3862fd81 Mon Sep 17 00:00:00 2001 From: Moritz Ulrich Date: Thu, 2 Feb 2023 00:02:08 +0100 Subject: [PATCH 5/6] chrono: Don't implement Normalizable for NaiveTime This makes no sense as there is no default 'timerange' type. --- src/chrono_04.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/chrono_04.rs b/src/chrono_04.rs index cf59fb8..a96a87d 100644 --- a/src/chrono_04.rs +++ b/src/chrono_04.rs @@ -1,4 +1,4 @@ -use chrono_04::{DateTime, NaiveDateTime, TimeZone, NaiveDate, NaiveTime}; +use chrono_04::{DateTime, NaiveDateTime, TimeZone, NaiveDate}; use crate::{Normalizable, RangeBound, BoundSided}; @@ -32,13 +32,3 @@ impl Normalizable for NaiveDate bound } } - -impl Normalizable for NaiveTime -{ - fn normalize(bound: RangeBound) -> RangeBound - where - S: BoundSided, - { - bound - } -} \ No newline at end of file From 8431270f64b21d6247508d67a374cbe1e5f9a34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20von=20G=C3=B6wels?= Date: Fri, 8 Mar 2024 12:31:43 +0100 Subject: [PATCH 6/6] with_chrono_0_4: Implement Normalize for NaiveDate correctly. > The built-in range types int4range, int8range, > and daterange all use a canonical form that > includes the lower bound and excludes the upper > bound; that is, [). https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-DISCRETE This is implemented by modifying the `bounded_normalize` macro to take a `$delta` expression (`1` for `i32` and `i64`, `Duration::days(1)` for `NaiveDate`). --- src/chrono_04.rs | 11 +---------- src/impls.rs | 7 +++---- src/lib.rs | 22 ++++++++++++---------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/chrono_04.rs b/src/chrono_04.rs index a96a87d..cbfb821 100644 --- a/src/chrono_04.rs +++ b/src/chrono_04.rs @@ -22,13 +22,4 @@ impl Normalizable for NaiveDateTime } } - -impl Normalizable for NaiveDate -{ - fn normalize(bound: RangeBound) -> RangeBound - where - S: BoundSided, - { - bound - } -} +bounded_normalizable!(NaiveDate, ::chrono_04::Duration::days(1)); diff --git a/src/impls.rs b/src/impls.rs index a2ce2fe..92d3ff2 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -144,7 +144,7 @@ mod test { fn test_type(sql_type: &str, checks: &[(T, S)]) where for<'a> - T: Sync + PartialEq + FromSql<'a> + ToSql, + T: Sync + PartialEq + FromSql<'a> + ToSql + fmt::Debug, S: fmt::Display { let mut conn = Client::connect("postgres://postgres@localhost", NoTls).unwrap(); @@ -152,11 +152,11 @@ mod test { let stmt = conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); let result = conn.query(&stmt, &[]).unwrap().iter().next().unwrap().get(0); - assert_eq!(val, &result); + assert_eq!(val, &result, "'SELECT {repr}::{sql_type}'"); let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap(); let result = conn.query(&stmt, &[val]).unwrap().iter().next().unwrap().get(0); - assert_eq!(val, &result); + assert_eq!(val, &result, "'SELECT $1::{sql_type}'"); } } @@ -192,7 +192,6 @@ mod test { #[test] #[cfg(feature = "with-chrono-0_4")] - #[ignore = "Exclusive starts will be converted to next-day + inclusive"] fn test_daterange_params() { let low = NaiveDate::from_ymd_opt(2015, 6, 4).unwrap(); let high = low + Duration::days(10); diff --git a/src/lib.rs b/src/lib.rs index a1d68a5..4bbf283 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,6 @@ #[macro_use(to_sql_checked)] extern crate postgres_types; -#[cfg(feature = "with-chrono-0_4")] -mod chrono_04; - use std::cmp::Ordering; use std::fmt; use std::i32; @@ -106,8 +103,6 @@ macro_rules! range { ) } -mod impls; - /// A trait that normalizes a range bound for a type pub trait Normalizable: Sized { /// Given a range bound, returns the normalized version of that bound. For @@ -124,17 +119,19 @@ pub trait Normalizable: Sized { } macro_rules! bounded_normalizable { - ($t:ident) => ( + ($t:ident, $delta:expr) => ( impl Normalizable for $t { fn normalize(bound: RangeBound) -> RangeBound where S: BoundSided { + use $crate::{BoundSide::*, BoundType::*}; + match (::side(), bound.type_) { (Upper, Inclusive) => { assert!(bound.value != $t::MAX); - RangeBound::new(bound.value + 1, Exclusive) + RangeBound::new(bound.value + ($delta), Exclusive) } (Lower, Exclusive) => { assert!(bound.value != $t::MAX); - RangeBound::new(bound.value + 1, Inclusive) + RangeBound::new(bound.value + ($delta), Inclusive) } _ => bound } @@ -143,8 +140,13 @@ macro_rules! bounded_normalizable { ) } -bounded_normalizable!(i32); -bounded_normalizable!(i64); +bounded_normalizable!(i32, 1); +bounded_normalizable!(i64, 1); + +mod impls; + +#[cfg(feature = "with-chrono-0_4")] +mod chrono_04; /// The possible sides of a bound. #[derive(Debug, PartialEq, Eq, Clone, Copy)]