From fa40e9e55f65721514ec0f06c2d576b5c7f8983f Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Fri, 17 Jul 2020 03:22:33 -0700 Subject: [PATCH] implement support for postgres TIMETZ type Co-authored-by: Julius de Bruijn --- .../src/postgres/types/chrono/datetime.rs | 11 +- sqlx-core/src/postgres/types/mod.rs | 10 + sqlx-core/src/postgres/types/time_tz.rs | 183 ++++++++++++++++++ sqlx-macros/src/database/postgres.rs | 9 +- tests/postgres/types.rs | 31 ++- 5 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 sqlx-core/src/postgres/types/time_tz.rs diff --git a/sqlx-core/src/postgres/types/chrono/datetime.rs b/sqlx-core/src/postgres/types/chrono/datetime.rs index ce97c700..a8712e7b 100644 --- a/sqlx-core/src/postgres/types/chrono/datetime.rs +++ b/sqlx-core/src/postgres/types/chrono/datetime.rs @@ -3,7 +3,9 @@ use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres}; use crate::types::Type; -use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, TimeZone, Utc}; +use chrono::{ + DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, Offset, TimeZone, Utc, +}; use std::mem; impl Type for NaiveDateTime { @@ -110,3 +112,10 @@ impl<'r> Decode<'r, Postgres> for DateTime { Ok(Utc.from_utc_datetime(&naive)) } } + +impl<'r> Decode<'r, Postgres> for DateTime { + fn decode(value: PgValueRef<'r>) -> Result { + let naive = >::decode(value)?; + Ok(Utc.fix().from_utc_datetime(&naive)) + } +} diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index 4a808239..811ee847 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -46,6 +46,7 @@ //! | `chrono::NaiveDateTime` | TIMESTAMP | //! | `chrono::NaiveDate` | DATE | //! | `chrono::NaiveTime` | TIME | +//! | [`PgTimeTz`] | TIMETZ | //! //! ### [`time`](https://crates.io/crates/time) //! @@ -57,6 +58,9 @@ //! | `time::OffsetDateTime` | TIMESTAMPTZ | //! | `time::Date` | DATE | //! | `time::Time` | TIME | +//! | [`PgTimeTz`] | TIMETZ | +//! +//! [`PgTimeTz`]: struct.PgTimeTz.html //! //! ### [`uuid`](https://crates.io/crates/uuid) //! @@ -162,6 +166,9 @@ mod str; mod tuple; mod void; +#[cfg(any(feature = "chrono", feature = "time"))] +mod time_tz; + #[cfg(feature = "bigdecimal")] mod bigdecimal; @@ -190,6 +197,9 @@ pub use interval::PgInterval; pub use money::PgMoney; pub use range::PgRange; +#[cfg(any(feature = "chrono", feature = "time"))] +pub use time_tz::PgTimeTz; + // used in derive(Type) for `struct` // but the interface is not considered part of the public API #[doc(hidden)] diff --git a/sqlx-core/src/postgres/types/time_tz.rs b/sqlx-core/src/postgres/types/time_tz.rs new file mode 100644 index 00000000..0129f482 --- /dev/null +++ b/sqlx-core/src/postgres/types/time_tz.rs @@ -0,0 +1,183 @@ +use crate::decode::Decode; +use crate::encode::{Encode, IsNull}; +use crate::error::BoxDynError; +use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres}; +use crate::types::Type; +use byteorder::{BigEndian, ReadBytesExt}; +use std::io::Cursor; +use std::mem; + +#[cfg(feature = "time")] +type DefaultTime = ::time::Time; + +#[cfg(all(not(feature = "time"), feature = "chrono"))] +type DefaultTime = ::chrono::NaiveTime; + +#[cfg(feature = "time")] +type DefaultOffset = ::time::UtcOffset; + +#[cfg(all(not(feature = "time"), feature = "chrono"))] +type DefaultOffset = ::chrono::FixedOffset; + +/// Represents a moment of time, in a specified timezone. +/// +/// # Warning +/// +/// `PgTimeTz` provides `TIMETZ` and is supported only for reading from legacy databases. +/// [PostgreSQL recommends] to use `TIMESTAMPTZ` instead. +/// +/// [PostgreSQL recommends]: https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_timetz +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct PgTimeTz