From e285f0858f453a0614b1cfde035dbff57c604111 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Fri, 17 Jul 2020 02:24:30 -0700 Subject: [PATCH] refactor: split up postgres chrono/time modules --- sqlx-core/src/postgres/types/chrono/date.rs | 51 ++++++++ .../types/{chrono.rs => chrono/datetime.rs} | 98 +--------------- sqlx-core/src/postgres/types/chrono/mod.rs | 3 + sqlx-core/src/postgres/types/chrono/time.rs | 55 +++++++++ sqlx-core/src/postgres/types/mod.rs | 6 +- sqlx-core/src/postgres/types/time/date.rs | 52 +++++++++ .../types/{time.rs => time/datetime.rs} | 110 +----------------- sqlx-core/src/postgres/types/time/mod.rs | 6 + sqlx-core/src/postgres/types/time/time.rs | 67 +++++++++++ sqlx-core/src/types/mod.rs | 7 ++ 10 files changed, 247 insertions(+), 208 deletions(-) create mode 100644 sqlx-core/src/postgres/types/chrono/date.rs rename sqlx-core/src/postgres/types/{chrono.rs => chrono/datetime.rs} (57%) create mode 100644 sqlx-core/src/postgres/types/chrono/mod.rs create mode 100644 sqlx-core/src/postgres/types/chrono/time.rs create mode 100644 sqlx-core/src/postgres/types/time/date.rs rename sqlx-core/src/postgres/types/{time.rs => time/datetime.rs} (54%) create mode 100644 sqlx-core/src/postgres/types/time/mod.rs create mode 100644 sqlx-core/src/postgres/types/time/time.rs diff --git a/sqlx-core/src/postgres/types/chrono/date.rs b/sqlx-core/src/postgres/types/chrono/date.rs new file mode 100644 index 00000000..185f46c7 --- /dev/null +++ b/sqlx-core/src/postgres/types/chrono/date.rs @@ -0,0 +1,51 @@ +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 chrono::{Duration, NaiveDate}; +use std::mem; + +impl Type for NaiveDate { + fn type_info() -> PgTypeInfo { + PgTypeInfo::DATE + } +} + +impl Type for [NaiveDate] { + fn type_info() -> PgTypeInfo { + PgTypeInfo::DATE_ARRAY + } +} + +impl Type for Vec { + fn type_info() -> PgTypeInfo { + <[NaiveDate] as Type>::type_info() + } +} + +impl Encode<'_, Postgres> for NaiveDate { + fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { + // DATE is encoded as the days since epoch + let days = (*self - NaiveDate::from_ymd(2000, 1, 1)).num_days() as i32; + Encode::::encode(&days, buf) + } + + fn size_hint(&self) -> usize { + mem::size_of::() + } +} + +impl<'r> Decode<'r, Postgres> for NaiveDate { + fn decode(value: PgValueRef<'r>) -> Result { + Ok(match value.format() { + PgValueFormat::Binary => { + // DATE is encoded as the days since epoch + let days: i32 = Decode::::decode(value)?; + NaiveDate::from_ymd(2000, 1, 1) + Duration::days(days.into()) + } + + PgValueFormat::Text => NaiveDate::parse_from_str(value.as_str()?, "%Y-%m-%d")?, + }) + } +} diff --git a/sqlx-core/src/postgres/types/chrono.rs b/sqlx-core/src/postgres/types/chrono/datetime.rs similarity index 57% rename from sqlx-core/src/postgres/types/chrono.rs rename to sqlx-core/src/postgres/types/chrono/datetime.rs index 19ac89a8..ce97c700 100644 --- a/sqlx-core/src/postgres/types/chrono.rs +++ b/sqlx-core/src/postgres/types/chrono/datetime.rs @@ -1,24 +1,10 @@ -use std::mem; - -use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; - 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; - -impl Type for NaiveTime { - fn type_info() -> PgTypeInfo { - PgTypeInfo::TIME - } -} - -impl Type for NaiveDate { - fn type_info() -> PgTypeInfo { - PgTypeInfo::DATE - } -} +use chrono::{DateTime, Duration, Local, NaiveDate, NaiveDateTime, TimeZone, Utc}; +use std::mem; impl Type for NaiveDateTime { fn type_info() -> PgTypeInfo { @@ -32,18 +18,6 @@ impl Type for DateTime { } } -impl Type for [NaiveTime] { - fn type_info() -> PgTypeInfo { - PgTypeInfo::TIME_ARRAY - } -} - -impl Type for [NaiveDate] { - fn type_info() -> PgTypeInfo { - PgTypeInfo::DATE_ARRAY - } -} - impl Type for [NaiveDateTime] { fn type_info() -> PgTypeInfo { PgTypeInfo::TIMESTAMP_ARRAY @@ -56,18 +30,6 @@ impl Type for [DateTime] { } } -impl Type for Vec { - fn type_info() -> PgTypeInfo { - <[NaiveTime] as Type>::type_info() - } -} - -impl Type for Vec { - fn type_info() -> PgTypeInfo { - <[NaiveDate] as Type>::type_info() - } -} - impl Type for Vec { fn type_info() -> PgTypeInfo { <[NaiveDateTime] as Type>::type_info() @@ -80,61 +42,6 @@ impl Type for Vec> { } } -impl Encode<'_, Postgres> for NaiveTime { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { - // TIME is encoded as the microseconds since midnight - // NOTE: panic! is on overflow and 1 day does not have enough micros to overflow - let us = (*self - NaiveTime::from_hms(0, 0, 0)) - .num_microseconds() - .unwrap(); - Encode::::encode(&us, buf) - } - - fn size_hint(&self) -> usize { - mem::size_of::() - } -} - -impl<'r> Decode<'r, Postgres> for NaiveTime { - fn decode(value: PgValueRef<'r>) -> Result { - Ok(match value.format() { - PgValueFormat::Binary => { - // TIME is encoded as the microseconds since midnight - let us: i64 = Decode::::decode(value)?; - NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(us) - } - - PgValueFormat::Text => NaiveTime::parse_from_str(value.as_str()?, "%H:%M:%S%.f")?, - }) - } -} - -impl Encode<'_, Postgres> for NaiveDate { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { - // DATE is encoded as the days since epoch - let days = (*self - NaiveDate::from_ymd(2000, 1, 1)).num_days() as i32; - Encode::::encode(&days, buf) - } - - fn size_hint(&self) -> usize { - mem::size_of::() - } -} - -impl<'r> Decode<'r, Postgres> for NaiveDate { - fn decode(value: PgValueRef<'r>) -> Result { - Ok(match value.format() { - PgValueFormat::Binary => { - // DATE is encoded as the days since epoch - let days: i32 = Decode::::decode(value)?; - NaiveDate::from_ymd(2000, 1, 1) + Duration::days(days.into()) - } - - PgValueFormat::Text => NaiveDate::parse_from_str(value.as_str()?, "%Y-%m-%d")?, - }) - } -} - impl Encode<'_, Postgres> for NaiveDateTime { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { // FIXME: We should *really* be returning an error, Encode needs to be fallible @@ -143,6 +50,7 @@ impl Encode<'_, Postgres> for NaiveDateTime { let us = (*self - epoch) .num_microseconds() .unwrap_or_else(|| panic!("NaiveDateTime out of range for Postgres: {:?}", self)); + Encode::::encode(&us, buf) } diff --git a/sqlx-core/src/postgres/types/chrono/mod.rs b/sqlx-core/src/postgres/types/chrono/mod.rs new file mode 100644 index 00000000..bd27c4d2 --- /dev/null +++ b/sqlx-core/src/postgres/types/chrono/mod.rs @@ -0,0 +1,3 @@ +mod date; +mod datetime; +mod time; diff --git a/sqlx-core/src/postgres/types/chrono/time.rs b/sqlx-core/src/postgres/types/chrono/time.rs new file mode 100644 index 00000000..e0a5ceb6 --- /dev/null +++ b/sqlx-core/src/postgres/types/chrono/time.rs @@ -0,0 +1,55 @@ +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 chrono::{Duration, NaiveTime}; +use std::mem; + +impl Type for NaiveTime { + fn type_info() -> PgTypeInfo { + PgTypeInfo::TIME + } +} + +impl Type for [NaiveTime] { + fn type_info() -> PgTypeInfo { + PgTypeInfo::TIME_ARRAY + } +} + +impl Type for Vec { + fn type_info() -> PgTypeInfo { + <[NaiveTime] as Type>::type_info() + } +} + +impl Encode<'_, Postgres> for NaiveTime { + fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { + // TIME is encoded as the microseconds since midnight + // NOTE: panic! is on overflow and 1 day does not have enough micros to overflow + let us = (*self - NaiveTime::from_hms(0, 0, 0)) + .num_microseconds() + .unwrap(); + + Encode::::encode(&us, buf) + } + + fn size_hint(&self) -> usize { + mem::size_of::() + } +} + +impl<'r> Decode<'r, Postgres> for NaiveTime { + fn decode(value: PgValueRef<'r>) -> Result { + Ok(match value.format() { + PgValueFormat::Binary => { + // TIME is encoded as the microseconds since midnight + let us: i64 = Decode::::decode(value)?; + NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(us) + } + + PgValueFormat::Text => NaiveTime::parse_from_str(value.as_str()?, "%H:%M:%S%.f")?, + }) + } +} diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index c8a19768..4a808239 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -5,6 +5,7 @@ //! | Rust type | Postgres type(s) | //! |---------------------------------------|------------------------------------------------------| //! | `bool` | BOOL | +//! | `i8` | "CHAR" | //! | `i16` | SMALLINT, SMALLSERIAL, INT2 | //! | `i32` | INT, SERIAL, INT4 | //! | `i64` | BIGINT, BIGSERIAL, INT8 | @@ -143,11 +144,6 @@ //! enum Mood { Sad = 0, Ok = 1, Happy = 2 } //! ``` //! -//! # Nullable -//! -//! In addition, `Option` is supported where `T` implements `Type`. An `Option` represents -//! a potentially `NULL` value from Postgres. -//! use crate::postgres::type_info::PgTypeKind; use crate::postgres::{PgTypeInfo, Postgres}; diff --git a/sqlx-core/src/postgres/types/time/date.rs b/sqlx-core/src/postgres/types/time/date.rs new file mode 100644 index 00000000..e2c74b8c --- /dev/null +++ b/sqlx-core/src/postgres/types/time/date.rs @@ -0,0 +1,52 @@ +use crate::decode::Decode; +use crate::encode::{Encode, IsNull}; +use crate::error::BoxDynError; +use crate::postgres::types::time::PG_EPOCH; +use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres}; +use crate::types::Type; +use std::mem; +use time::{Date, Duration}; + +impl Type for Date { + fn type_info() -> PgTypeInfo { + PgTypeInfo::DATE + } +} + +impl Type for [Date] { + fn type_info() -> PgTypeInfo { + PgTypeInfo::DATE_ARRAY + } +} + +impl Type for Vec { + fn type_info() -> PgTypeInfo { + <[Date] as Type>::type_info() + } +} + +impl Encode<'_, Postgres> for Date { + fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { + // DATE is encoded as the days since epoch + let days = (*self - PG_EPOCH).whole_days() as i32; + Encode::::encode(&days, buf) + } + + fn size_hint(&self) -> usize { + mem::size_of::() + } +} + +impl<'r> Decode<'r, Postgres> for Date { + fn decode(value: PgValueRef<'r>) -> Result { + Ok(match value.format() { + PgValueFormat::Binary => { + // DATE is encoded as the days since epoch + let days: i32 = Decode::::decode(value)?; + PG_EPOCH + Duration::days(days.into()) + } + + PgValueFormat::Text => Date::parse(value.as_str()?, "%Y-%m-%d")?, + }) + } +} diff --git a/sqlx-core/src/postgres/types/time.rs b/sqlx-core/src/postgres/types/time/datetime.rs similarity index 54% rename from sqlx-core/src/postgres/types/time.rs rename to sqlx-core/src/postgres/types/time/datetime.rs index 3338680d..19d543a3 100644 --- a/sqlx-core/src/postgres/types/time.rs +++ b/sqlx-core/src/postgres/types/time/datetime.rs @@ -1,27 +1,12 @@ -use time::{date, offset, Date, Duration, OffsetDateTime, PrimitiveDateTime, Time}; - use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; +use crate::postgres::types::time::PG_EPOCH; use crate::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres}; use crate::types::Type; use std::borrow::Cow; use std::mem; - -#[rustfmt::skip] -const PG_EPOCH: Date = date!(2000-1-1); - -impl Type for Time { - fn type_info() -> PgTypeInfo { - PgTypeInfo::TIME - } -} - -impl Type for Date { - fn type_info() -> PgTypeInfo { - PgTypeInfo::DATE - } -} +use time::{offset, Duration, OffsetDateTime, PrimitiveDateTime}; impl Type for PrimitiveDateTime { fn type_info() -> PgTypeInfo { @@ -35,18 +20,6 @@ impl Type for OffsetDateTime { } } -impl Type for [Time] { - fn type_info() -> PgTypeInfo { - PgTypeInfo::TIME_ARRAY - } -} - -impl Type for [Date] { - fn type_info() -> PgTypeInfo { - PgTypeInfo::DATE_ARRAY - } -} - impl Type for [PrimitiveDateTime] { fn type_info() -> PgTypeInfo { PgTypeInfo::TIMESTAMP_ARRAY @@ -59,18 +32,6 @@ impl Type for [OffsetDateTime] { } } -impl Type for Vec