Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests, Fixed microseconds in ToSql implementations #1

Open
wants to merge 9 commits into
base: jiff
Choose a base branch
from
19 changes: 9 additions & 10 deletions postgres-types/src/jiff_01.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use bytes::BytesMut;
use jiff_01::{
civil::{Date, DateTime, Time},
tz::TimeZone,
Span, Timestamp, Zoned,
Span, Timestamp, Unit,
};
use postgres_protocol::types;
use std::error::Error;
Expand All @@ -23,15 +22,15 @@ fn base_ts() -> Timestamp {
impl<'a> FromSql<'a> for DateTime {
fn from_sql(_: &Type, raw: &[u8]) -> Result<DateTime, Box<dyn Error + Sync + Send>> {
let t = types::timestamp_from_sql(raw)?;
Ok(base().checked_add(Span::new().microseconds(t))?)
Ok(base().checked_add(Span::new().try_microseconds(t)?)?)
}

accepts!(TIMESTAMP);
}

impl ToSql for DateTime {
fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
types::timestamp_to_sql(self.since(base())?.get_microseconds(), w);
types::timestamp_to_sql(self.since(base())?.total(Unit::Microsecond)? as i64, w);
Ok(IsNull::No)
}

Expand All @@ -42,15 +41,15 @@ impl ToSql for DateTime {
impl<'a> FromSql<'a> for Timestamp {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Timestamp, Box<dyn Error + Sync + Send>> {
let t = types::timestamp_from_sql(raw)?;
Ok(base_ts().checked_add(Span::new().microseconds(t))?)
Ok(base_ts().checked_add(Span::new().try_microseconds(t)?)?)
}

accepts!(TIMESTAMPTZ);
}

impl ToSql for Timestamp {
fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
types::timestamp_to_sql(self.since(base_ts())?.get_microseconds(), w);
types::timestamp_to_sql(self.since(base_ts())?.total(Unit::Microsecond)? as i64, w);
Ok(IsNull::No)
}

Expand All @@ -61,15 +60,15 @@ impl ToSql for Timestamp {
impl<'a> FromSql<'a> for Date {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Date, Box<dyn Error + Sync + Send>> {
let jd = types::date_from_sql(raw)?;
Ok(base().date().checked_add(Span::new().days(jd))?)
Ok(base().date().checked_add(Span::new().try_days(jd)?)?)
}

accepts!(DATE);
}

impl ToSql for Date {
fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
let jd = self.since(base().date())?.get_days();
let jd = self.since(base())?.total(Unit::Day)? as i32;
types::date_to_sql(jd, w);
Ok(IsNull::No)
}
Expand All @@ -81,7 +80,7 @@ impl ToSql for Date {
impl<'a> FromSql<'a> for Time {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Time, Box<dyn Error + Sync + Send>> {
let usec = types::time_from_sql(raw)?;
Ok(Time::midnight() + Span::new().microseconds(usec))
Ok(Time::midnight() + Span::new().try_microseconds(usec)?)
}

accepts!(TIME);
Expand All @@ -90,7 +89,7 @@ impl<'a> FromSql<'a> for Time {
impl ToSql for Time {
fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
let delta = self.since(Time::midnight())?;
types::time_to_sql(delta.get_microseconds(), w);
types::time_to_sql(delta.total(Unit::Microsecond)? as i64, w);
Ok(IsNull::No)
}

Expand Down
8 changes: 7 additions & 1 deletion tokio-postgres/src/keepalive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ impl From<&KeepaliveConfig> for TcpKeepalive {
fn from(keepalive_config: &KeepaliveConfig) -> Self {
let mut tcp_keepalive = Self::new().with_time(keepalive_config.idle);

#[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "openbsd")))]
#[cfg(not(any(
target_os = "aix",
target_os = "redox",
target_os = "solaris",
target_os = "openbsd"
)))]
if let Some(interval) = keepalive_config.interval {
tcp_keepalive = tcp_keepalive.with_interval(interval);
}

#[cfg(not(any(
target_os = "aix",
target_os = "redox",
target_os = "solaris",
target_os = "windows",
Expand Down
13 changes: 9 additions & 4 deletions tokio-postgres/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,15 @@ where

loop {
match responses.next().await? {
Message::ParseComplete
| Message::BindComplete
| Message::ParameterDescription(_)
| Message::NoData => {}
Message::ParseComplete | Message::BindComplete | Message::ParameterDescription(_) => {}
Message::NoData => {
return Ok(RowStream {
statement: Statement::unnamed(vec![], vec![]),
responses,
rows_affected: None,
_p: PhantomPinned,
});
}
Message::RowDescription(row_description) => {
let mut columns: Vec<Column> = vec![];
let mut it = row_description.fields();
Expand Down
14 changes: 14 additions & 0 deletions tokio-postgres/tests/test/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,13 @@ async fn query_typed_no_transaction() {
assert_eq!(second_row.get::<_, i32>(1), 40);
assert_eq!(second_row.get::<_, &str>(2), "literal");
assert_eq!(second_row.get::<_, i32>(3), 5);

// Test for UPDATE that returns no data
let updated_rows = client
.query_typed("UPDATE foo set age = 33", &[])
.await
.unwrap();
assert_eq!(updated_rows.len(), 0);
}

#[tokio::test]
Expand Down Expand Up @@ -1064,4 +1071,11 @@ async fn query_typed_with_transaction() {
assert_eq!(second_row.get::<_, i32>(1), 40);
assert_eq!(second_row.get::<_, &str>(2), "literal");
assert_eq!(second_row.get::<_, i32>(3), 5);

// Test for UPDATE that returns no data
let updated_rows = transaction
.query_typed("UPDATE foo set age = 33", &[])
.await
.unwrap();
assert_eq!(updated_rows.len(), 0);
}
176 changes: 176 additions & 0 deletions tokio-postgres/tests/test/types/jiff_01.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
use jiff_01::{civil::Date, civil::DateTime, civil::Time, Timestamp};
use std::fmt;
use tokio_postgres::types::{self, FromSqlOwned};
use tokio_postgres::Client;

use crate::connect;
use crate::types::test_type;

#[tokio::test]
async fn test_civil_datetime_params() {
fn make_check(time: &str) -> (Option<DateTime>, &str) {
(
Some(DateTime::strptime("'%Y-%m-%d %H:%M:%S.%f'", time).unwrap()),
time,
)
}
test_type(
"TIMESTAMP",
&[
make_check("'1970-01-01 00:00:00.010000000'"),
make_check("'1965-09-25 11:19:33.100314000'"),
make_check("'2010-02-09 23:11:45.120200000'"),
(None, "NULL"),
],
)
.await;
}

#[tokio::test]
async fn test_with_special_civil_datetime_params() {
fn make_check(time: &str) -> (types::Timestamp<DateTime>, &str) {
(
types::Timestamp::Value(DateTime::strptime("'%Y-%m-%d %H:%M:%S.%f'", time).unwrap()),
time,
)
}
test_type(
"TIMESTAMP",
&[
make_check("'1970-01-01 00:00:00.010000000'"),
make_check("'1965-09-25 11:19:33.100314000'"),
make_check("'2010-02-09 23:11:45.120200000'"),
(types::Timestamp::PosInfinity, "'infinity'"),
(types::Timestamp::NegInfinity, "'-infinity'"),
],
)
.await;
}

#[tokio::test]
async fn test_timestamp_params() {
fn make_check(time: &str) -> (Option<Timestamp>, &str) {
(
Some(Timestamp::strptime("'%Y-%m-%d %H:%M:%S.%f %z'", time).unwrap()),
time,
)
}
test_type(
"TIMESTAMP WITH TIME ZONE",
&[
make_check("'1970-01-01 00:00:00.010000000 +0000'"),
make_check("'1965-09-25 11:19:33.100314000 +0000'"),
make_check("'2010-02-09 23:11:45.120200000 +0000'"),
make_check("'2010-11-20 17:11:45.120200000 +0500'"),
(None, "NULL"),
],
)
.await;
}

#[tokio::test]
async fn test_with_special_timestamp_params() {
fn make_check(time: &str) -> (types::Timestamp<Timestamp>, &str) {
(
types::Timestamp::Value(
Timestamp::strptime("'%Y-%m-%d %H:%M:%S.%f %z'", time).unwrap(),
),
time,
)
}
test_type(
"TIMESTAMP WITH TIME ZONE",
&[
make_check("'1970-01-01 00:00:00.010000000 +0000'"),
make_check("'1965-09-25 11:19:33.100314000 +0000'"),
make_check("'2010-02-09 23:11:45.120200000 +0000'"),
(types::Timestamp::PosInfinity, "'infinity'"),
(types::Timestamp::NegInfinity, "'-infinity'"),
],
)
.await;
}

#[tokio::test]
async fn test_date_params() {
fn make_check(time: &str) -> (Option<Date>, &str) {
(Some(Date::strptime("'%Y-%m-%d'", time).unwrap()), time)
}
test_type(
"DATE",
&[
make_check("'1970-01-01'"),
make_check("'1965-09-25'"),
make_check("'2010-02-09'"),
(None, "NULL"),
],
)
.await;
}

#[tokio::test]
async fn test_with_special_date_params() {
fn make_check(date: &str) -> (types::Date<Date>, &str) {
(
types::Date::Value(Date::strptime("'%Y-%m-%d'", date).unwrap()),
date,
)
}
test_type(
"DATE",
&[
make_check("'1970-01-01'"),
make_check("'1965-09-25'"),
make_check("'2010-02-09'"),
(types::Date::PosInfinity, "'infinity'"),
(types::Date::NegInfinity, "'-infinity'"),
],
)
.await;
}

#[tokio::test]
async fn test_time_params() {
fn make_check(time: &str) -> (Option<Time>, &str) {
(Some(Time::strptime("'%H:%M:%S.%f'", time).unwrap()), time)
}
test_type(
"TIME",
&[
make_check("'00:00:00.010000000'"),
make_check("'11:19:33.100314000'"),
make_check("'23:11:45.120200000'"),
(None, "NULL"),
],
)
.await;
}

#[tokio::test]
async fn test_special_params_without_wrapper() {
async fn assert_overflows<T>(client: &mut Client, val: &str, sql_type: &str)
where
T: FromSqlOwned + fmt::Debug,
{
let err = client
.query_one(&*format!("SELECT {}::{}", val, sql_type), &[])
.await
.unwrap()
.try_get::<_, T>(0)
.unwrap_err();
// Jiff's Error type has limited introspection so I am being dirty here
let display_string = format!("{}", err);
assert!(display_string.contains("is not in the required range of"));
}

let mut client = connect("user=postgres").await;

assert_overflows::<Timestamp>(&mut client, "'-infinity'", "timestamptz").await;
assert_overflows::<Timestamp>(&mut client, "'infinity'", "timestamptz").await;

assert_overflows::<DateTime>(&mut client, "'-infinity'", "timestamp").await;
assert_overflows::<DateTime>(&mut client, "'infinity'", "timestamp").await;

assert_overflows::<Date>(&mut client, "'-infinity'", "date").await;
assert_overflows::<Date>(&mut client, "'infinity'", "date").await;
}
2 changes: 2 additions & 0 deletions tokio-postgres/tests/test/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ mod eui48_1;
mod geo_types_06;
#[cfg(feature = "with-geo-types-0_7")]
mod geo_types_07;
#[cfg(feature = "with-jiff-0_1")]
mod jiff_01;
#[cfg(feature = "with-serde_json-1")]
mod serde_json_1;
#[cfg(feature = "with-smol_str-01")]
Expand Down