diff --git a/Cargo.toml b/Cargo.toml index be73eca..0f12d7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,8 @@ uuid = { version = "~1", optional = true } linkme = { version = "~0.3" } # Time and date library -chrono = { version = ">=0.4.20", default-features = false } +chrono = { version = ">=0.4.20", default-features = false, optional = true } +time = { version = "~0.3", optional = true } # Allow wrapping futures and streams pin-project = { version = "~1" } diff --git a/src/conditions/mod.rs b/src/conditions/mod.rs index 4d7d8a8..038fe38 100644 --- a/src/conditions/mod.rs +++ b/src/conditions/mod.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; -use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; +// use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use rorm_db::sql::{conditional, value}; use crate::internal::field::RawField; @@ -79,11 +79,29 @@ pub enum Value<'a> { /// binary representation Binary(Cow<'a, [u8]>), /// Naive Time representation - NaiveTime(NaiveTime), + #[cfg(feature = "chrono")] + ChronoNaiveTime(chrono::NaiveTime), /// Naive Date representation - NaiveDate(NaiveDate), + #[cfg(feature = "chrono")] + ChronoNaiveDate(chrono::NaiveDate), /// Naive DateTime representation - NaiveDateTime(NaiveDateTime), + #[cfg(feature = "chrono")] + ChronoNaiveDateTime(chrono::NaiveDateTime), + /// DateTime representation + #[cfg(feature = "chrono")] + ChronoDateTime(chrono::DateTime), + /// time's date representation + #[cfg(feature = "time")] + TimeDate(time::Date), + /// time's time representation + #[cfg(feature = "time")] + TimeTime(time::Time), + /// time's offset datetime representation + #[cfg(feature = "time")] + TimeOffsetDateTime(time::OffsetDateTime), + /// time's primitive datetime representation + #[cfg(feature = "time")] + TimePrimitiveDateTime(time::PrimitiveDateTime), } impl<'a> Value<'a> { /// Convert into an [`sql::Value`](value::Value) instead of an [`sql::Condition`](conditional::Condition) directly. @@ -99,9 +117,22 @@ impl<'a> Value<'a> { Value::F64(v) => value::Value::F64(*v), Value::F32(v) => value::Value::F32(*v), Value::Binary(v) => value::Value::Binary(v.as_ref()), - Value::NaiveTime(v) => value::Value::ChronoNaiveTime(*v), - Value::NaiveDate(v) => value::Value::ChronoNaiveDate(*v), - Value::NaiveDateTime(v) => value::Value::ChronoNaiveDateTime(*v), + #[cfg(feature = "chrono")] + Value::ChronoNaiveTime(v) => value::Value::ChronoNaiveTime(*v), + #[cfg(feature = "chrono")] + Value::ChronoNaiveDate(v) => value::Value::ChronoNaiveDate(*v), + #[cfg(feature = "chrono")] + Value::ChronoNaiveDateTime(v) => value::Value::ChronoNaiveDateTime(*v), + #[cfg(feature = "chrono")] + Value::ChronoDateTime(v) => value::Value::ChronoDateTime(*v), + #[cfg(feature = "time")] + Value::TimeDate(v) => value::Value::TimeDate(*v), + #[cfg(feature = "time")] + Value::TimeTime(v) => value::Value::TimeTime(*v), + #[cfg(feature = "time")] + Value::TimeOffsetDateTime(v) => value::Value::TimeOffsetDateTime(*v), + #[cfg(feature = "time")] + Value::TimePrimitiveDateTime(v) => value::Value::TimePrimitiveDateTime(*v), } } } diff --git a/src/fields/types/chrono.rs b/src/fields/types/chrono.rs new file mode 100644 index 0000000..b965137 --- /dev/null +++ b/src/fields/types/chrono.rs @@ -0,0 +1,205 @@ +use std::marker::PhantomData; + +use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; +use rorm_db::Error::DecodeError; +use rorm_db::{Error, Row}; +use rorm_declaration::imr; + +use crate::conditions::Value; +use crate::crud::decoder::{Decoder, DirectDecoder}; +use crate::fields::traits::FieldType; +use crate::internal::field::as_db_type::AsDbType; +use crate::internal::field::decoder::FieldDecoder; +use crate::internal::field::{kind, AbstractField, ContainerField, FieldProxy, RawField}; +use crate::internal::hmr::annotations::Annotations; +use crate::internal::hmr::{db_type, Source}; +use crate::internal::query_context::QueryContext; +use crate::internal::relation_path::Path; +use crate::model::ConstNew; +use crate::{const_concat, impl_AsDbType, new_converting_decoder, sealed}; + +impl_AsDbType!(NaiveTime, db_type::Time, Value::ChronoNaiveTime); +impl_AsDbType!(NaiveDate, db_type::Date, Value::ChronoNaiveDate); +impl_AsDbType!(NaiveDateTime, db_type::DateTime, Value::ChronoNaiveDateTime); +impl_AsDbType!(DateTime, db_type::DateTime, Value::ChronoDateTime); + +/// Implementation detail of [`DateTime`] +const _: () = { + new_converting_decoder!( + /// [`FieldDecoder`] for [`FixedOffset`] + FixedOffsetDecoder, + |value: i32| -> FixedOffset { + FixedOffset::east_opt(value) + .ok_or_else(|| DecodeError(format!("Couldn't decode fixed offset: {value}"))) + } + ); + impl FieldType for FixedOffset { + type Kind = kind::AsDbType; + + type Columns = [T; 1]; + + fn into_values(self) -> Self::Columns> { + [Value::I32(self.local_minus_utc())] + } + + fn as_values(&self) -> Self::Columns> { + [Value::I32(self.local_minus_utc())] + } + + type Decoder = FixedOffsetDecoder; + } + impl AsDbType for FixedOffset { + type Primitive = i32; + type DbType = db_type::Int32; + + fn from_primitive(primitive: Self::Primitive) -> Self { + FixedOffset::east_opt(primitive).unwrap() // TODO handle this + } + } + new_converting_decoder!( + /// [`FieldDecoder`] for [`Option`](FixedOffset) + OptionFixedOffsetDecoder, + |value: Option| -> Option { + value + .map(|value| { + FixedOffset::east_opt(value).ok_or_else(|| { + DecodeError(format!("Couldn't decode fixed offset: {value}")) + }) + }) + .transpose() + } + ); + impl_AsDbType!(Option, OptionFixedOffsetDecoder); + + impl FieldType for DateTime { + type Kind = kind::DateTime; + + type Columns = [T; 2]; + + fn into_values(self) -> Self::Columns> { + let [offset] = self.offset().into_values(); + [offset, Value::ChronoNaiveDateTime(self.naive_utc())] + } + + fn as_values(&self) -> Self::Columns> { + let [offset] = self.offset().as_values(); + [offset, Value::ChronoNaiveDateTime(self.naive_utc())] + } + + type Decoder = DateTimeDecoder; + } + + /// [`FieldDecoder`] for [`DateTime`] + pub struct DateTimeDecoder { + offset: FixedOffsetDecoder, + utc: DirectDecoder, + } + impl Decoder for DateTimeDecoder { + type Result = DateTime; + + fn by_name(&self, row: &Row) -> Result { + let offset = self.offset.by_name(row)?; + let utc = self.utc.by_name(row)?; + Ok(offset.from_utc_datetime(&utc)) + } + + fn by_index(&self, row: &Row) -> Result { + let offset = self.offset.by_index(row)?; + let utc = self.utc.by_index(row)?; + Ok(offset.from_utc_datetime(&utc)) + } + } + impl FieldDecoder for DateTimeDecoder { + fn new(ctx: &mut QueryContext, _: FieldProxy) -> Self + where + F: RawField, + P: Path, + { + Self { + offset: FixedOffsetDecoder::new(ctx, FieldProxy::<__DateTime_offset, P>::new()), + utc: DirectDecoder::new(ctx, FieldProxy::<__DateTime_utc, P>::new()), + } + } + } + impl AbstractField for F + where + F: RawField>, + { + sealed!(impl); + + fn push_imr(self, imr: &mut Vec) { + __DateTime_offset::::new().push_imr(imr); + __DateTime_utc::::new().push_imr(imr); + } + + const COLUMNS: &'static [&'static str] = + &[__DateTime_offset::::NAME, __DateTime_utc::::NAME]; + } + impl ContainerField for F + where + P: Path, + F: RawField>, + { + type Target = __DateTime_Fields; + } + + /// [`DateTime`]'s internal fields + #[allow(non_camel_case_types)] + pub struct __DateTime_Fields { + /// [`DateTime`]'s internal offset field + pub offset: FieldProxy<__DateTime_offset, P>, + + /// [`DateTime`]'s internal offset field + pub utc: FieldProxy<__DateTime_utc, P>, + } + impl ConstNew for __DateTime_Fields + where + F: RawField>, + { + const NEW: Self = __DateTime_Fields { + offset: FieldProxy::new(), + utc: FieldProxy::new(), + }; + const REF: &'static Self = &Self::NEW; + } + + /// [`DateTime`]'s internal offset field + #[allow(non_camel_case_types)] + #[derive(Copy, Clone)] + pub struct __DateTime_offset(PhantomData); + impl RawField for __DateTime_offset + where + F: RawField>, + { + type Kind = kind::AsDbType; + type Type = FixedOffset; + type Model = F::Model; + const INDEX: usize = F::INDEX + 1; + const NAME: &'static str = const_concat!(&[F::NAME, "_offset"]); + const EXPLICIT_ANNOTATIONS: Annotations = F::EXPLICIT_ANNOTATIONS; + const SOURCE: Option = F::SOURCE; + fn new() -> Self { + Self(PhantomData) + } + } + + /// [`DateTime`]'s internal offset field + #[allow(non_camel_case_types)] + #[derive(Copy, Clone)] + pub struct __DateTime_utc(PhantomData); + impl RawField for __DateTime_utc + where + F: RawField>, + { + type Kind = kind::AsDbType; + type Type = NaiveDateTime; + type Model = F::Model; + const INDEX: usize = F::INDEX + 2; + const NAME: &'static str = const_concat!(&[F::NAME, "_utc"]); + const EXPLICIT_ANNOTATIONS: Annotations = F::EXPLICIT_ANNOTATIONS; + const SOURCE: Option = F::SOURCE; + fn new() -> Self { + Self(PhantomData) + } + } +}; diff --git a/src/fields/types/mod.rs b/src/fields/types/mod.rs index b35a8c0..e65c1bd 100644 --- a/src/fields/types/mod.rs +++ b/src/fields/types/mod.rs @@ -3,10 +3,14 @@ //! See [`rorm::fields`](crate::fields) for full list of supported field types mod back_ref; +#[cfg(feature = "chrono")] +mod chrono; mod foreign_model; mod json; #[cfg(feature = "msgpack")] mod msgpack; +#[cfg(feature = "time")] +mod time; #[cfg(feature = "uuid")] mod uuid; diff --git a/src/fields/types/time.rs b/src/fields/types/time.rs new file mode 100644 index 0000000..cecac9c --- /dev/null +++ b/src/fields/types/time.rs @@ -0,0 +1,16 @@ +use crate::conditions::Value; +use crate::impl_AsDbType; +use crate::internal::hmr::db_type; + +impl_AsDbType!(time::Time, db_type::Time, Value::TimeTime); +impl_AsDbType!(time::Date, db_type::Date, Value::TimeDate); +impl_AsDbType!( + time::OffsetDateTime, + db_type::DateTime, + Value::TimeOffsetDateTime +); +impl_AsDbType!( + time::PrimitiveDateTime, + db_type::DateTime, + Value::TimePrimitiveDateTime +); diff --git a/src/fields/types/uuid.rs b/src/fields/types/uuid.rs index c79179e..3cba743 100644 --- a/src/fields/types/uuid.rs +++ b/src/fields/types/uuid.rs @@ -8,7 +8,7 @@ use crate::internal::field::as_db_type::AsDbType; use crate::internal::field::kind; use crate::internal::hmr::db_type; use crate::Error::DecodeError; -use crate::{impl_option_as_db_type, new_converting_decoder}; +use crate::{impl_AsDbType, new_converting_decoder}; new_converting_decoder!(UuidDecoder, |value: Vec| -> Uuid { Uuid::from_slice(&value).map_err(|err| DecodeError(format!("Couldn't decode uuid: {err}"))) @@ -48,4 +48,4 @@ new_converting_decoder!( .transpose() } ); -impl_option_as_db_type!(Uuid, OptionUuidDecoder); +impl_AsDbType!(Option, OptionUuidDecoder); diff --git a/src/internal/field/as_db_type.rs b/src/internal/field/as_db_type.rs index 737612f..2f18a5f 100644 --- a/src/internal/field/as_db_type.rs +++ b/src/internal/field/as_db_type.rs @@ -2,16 +2,13 @@ use std::borrow::Cow; -use chrono::{TimeZone, Utc}; use rorm_db::row::DecodeOwned; use crate::conditions::Value; -use crate::crud::decoder::DirectDecoder; use crate::internal::field::{kind, FieldType}; use crate::internal::hmr::annotations::Annotations; use crate::internal::hmr::db_type; use crate::internal::hmr::db_type::DbType; -use crate::new_converting_decoder; /// This trait maps rust types to database types /// @@ -33,34 +30,43 @@ pub trait AsDbType: FieldType + Sized { fn from_primitive(primitive: Self::Primitive) -> Self; } -#[doc(hidden)] +/// Provides the "default" implementation of [`AsDbType`] and [`FieldType`] of kind `AsDbType`. +/// +/// ## Usages +/// - `impl_as_db_type!(RustType, DbType, into_value, as_value);` +/// - `RustType` is the type to implement the traits on. +/// - `DbType` is the database type to associate with (must implement [`DbType`]). +/// - `into_value` is used to convert `RustType` into a [`Value<'static>`] (must implement `Fn(RustType) -> Value<'static>`). +/// - `as_value` is used to convert `&'a RustType` into a [`Value<'a>`] (must implement `Fn(&'_ RustType) -> Value<'_>`). +/// If `RustType` implements `Copy`, `as_value` can be omitted and will use `into_value` instead. +#[allow(non_snake_case)] #[macro_export] -macro_rules! impl_option_as_db_type { - ($type:ty, $decoder:ty) => { - impl FieldType for Option<$type> { - type Kind = kind::AsDbType; +macro_rules! impl_AsDbType { + (Option<$type:ty>, $decoder:ty) => { + impl $crate::fields::traits::FieldType for Option<$type> { + type Kind = $crate::internal::field::kind::AsDbType; type Columns = [T; 1]; - fn into_values(self) -> Self::Columns> { + fn into_values(self) -> Self::Columns<$crate::conditions::Value<'static>> { self.map(<$type>::into_values) - .unwrap_or([Value::Null(<<$type as AsDbType>::DbType as $crate::internal::hmr::db_type::DbType>::NULL_TYPE)]) + .unwrap_or([Value::Null(<<$type as $crate::internal::field::as_db_type::AsDbType>::DbType as $crate::internal::hmr::db_type::DbType>::NULL_TYPE)]) } - fn as_values(&self) -> Self::Columns> { + fn as_values(&self) -> Self::Columns<$crate::conditions::Value<'_>> { self.as_ref() .map(<$type>::as_values) - .unwrap_or([Value::Null(<<$type as AsDbType>::DbType as $crate::internal::hmr::db_type::DbType>::NULL_TYPE)]) + .unwrap_or([Value::Null(<<$type as $crate::internal::field::as_db_type::AsDbType>::DbType as $crate::internal::hmr::db_type::DbType>::NULL_TYPE)]) } type Decoder = $decoder; } - impl AsDbType for Option<$type> { - type Primitive = Option<<$type as AsDbType>::Primitive>; - type DbType = <$type as AsDbType>::DbType; + impl $crate::internal::field::as_db_type::AsDbType for Option<$type> { + type Primitive = Option<<$type as $crate::internal::field::as_db_type::AsDbType>::Primitive>; + type DbType = <$type as $crate::internal::field::as_db_type::AsDbType>::DbType; const IMPLICIT: Option<$crate::internal::hmr::annotations::Annotations> = { - let mut annos = if let Some(annos) = <$type as AsDbType>::IMPLICIT { + let mut annos = if let Some(annos) = <$type as $crate::internal::field::as_db_type::AsDbType>::IMPLICIT { annos } else { $crate::internal::hmr::annotations::Annotations::empty() @@ -70,26 +76,34 @@ macro_rules! impl_option_as_db_type { }; fn from_primitive(primitive: Self::Primitive) -> Self { - primitive.map(<$type as AsDbType>::from_primitive) + primitive.map(<$type as $crate::internal::field::as_db_type::AsDbType>::from_primitive) } } }; -} -macro_rules! impl_as_db_type { - ($type:ty, $db_type:ident, $value_variant:ident $(using $method:ident)?) => { - impl FieldType for $type { - type Kind = kind::AsDbType; + ($type:ty, $db_type:ty, $into_value:expr) => { + impl_AsDbType!($type, $db_type, $into_value, |&value| $into_value(value)); + }; + ($type:ty, $db_type:ty, $into_value:expr, $as_value:expr) => { + impl $crate::fields::traits::FieldType for $type { + type Kind = $crate::internal::field::kind::AsDbType; type Columns = [T; 1]; - impl_as_db_type!(impl_as_primitive, $type, $db_type, $value_variant $(using $method)?); + #[inline(always)] + fn as_values(&self) -> Self::Columns<$crate::conditions::Value<'_>> { + [$as_value(self)] + } - type Decoder = DirectDecoder; + fn into_values(self) -> Self::Columns<$crate::conditions::Value<'static>> { + [$into_value(self)] + } + + type Decoder = $crate::crud::decoder::DirectDecoder; } - impl AsDbType for $type { + impl $crate::internal::field::as_db_type::AsDbType for $type { type Primitive = Self; - type DbType = db_type::$db_type; + type DbType = $db_type; #[inline(always)] fn from_primitive(primitive: Self::Primitive) -> Self { @@ -97,76 +111,24 @@ macro_rules! impl_as_db_type { } } - impl_option_as_db_type!($type, DirectDecoder); - }; - (impl_as_primitive, $type:ty, $db_type:ident, $value_variant:ident) => { - #[inline(always)] - fn as_values(&self) -> Self::Columns> { - [Value::$value_variant(*self)] - } - - #[inline(always)] - fn into_values(self) -> Self::Columns> { - [Value::$value_variant(self)] - } - }; - (impl_as_primitive, $type:ty, $db_type:ident, $value_variant:ident using $method:ident) => { - #[inline(always)] - fn as_values(&self) -> Self::Columns> { - [Value::$value_variant(Cow::Borrowed(self.$method()))] - } - - #[inline(always)] - fn into_values(self) -> Self::Columns> { - [Value::$value_variant(Cow::Owned(self))] - } + impl_AsDbType!(Option<$type>, $crate::crud::decoder::DirectDecoder); }; } -impl_as_db_type!(chrono::NaiveTime, Time, NaiveTime); -impl_as_db_type!(chrono::NaiveDateTime, DateTime, NaiveDateTime); -impl_as_db_type!(chrono::NaiveDate, Date, NaiveDate); -impl_as_db_type!(i16, Int16, I16); -impl_as_db_type!(i32, Int32, I32); -impl_as_db_type!(i64, Int64, I64); -impl_as_db_type!(f32, Float, F32); -impl_as_db_type!(f64, Double, F64); -impl_as_db_type!(bool, Boolean, Bool); -impl_as_db_type!(Vec, VarBinary, Binary using as_slice); -impl_as_db_type!(String, VarChar, String using as_str); - -new_converting_decoder!( - /// [`FieldDecoder`](crate::internal::field::decoder::FieldDecoder) for [`chrono::DateTime`] - UtcDateTimeDecoder, - |value: chrono::NaiveDateTime| -> chrono::DateTime { Ok(Utc.from_utc_datetime(&value)) } +impl_AsDbType!(i16, db_type::Int16, Value::I16); +impl_AsDbType!(i32, db_type::Int32, Value::I32); +impl_AsDbType!(i64, db_type::Int64, Value::I64); +impl_AsDbType!(f32, db_type::Float, Value::F32); +impl_AsDbType!(f64, db_type::Double, Value::F64); +impl_AsDbType!(bool, db_type::Boolean, Value::Bool); +impl_AsDbType!( + Vec, + db_type::VarBinary, + |b| Value::Binary(Cow::Owned(b)), + |b| { Value::Binary(Cow::Borrowed(b)) } ); -impl FieldType for chrono::DateTime { - type Kind = kind::AsDbType; - - type Columns = [T; 1]; - - fn into_values(self) -> Self::Columns> { - [Value::NaiveDateTime(self.naive_utc())] - } - - fn as_values(&self) -> Self::Columns> { - [Value::NaiveDateTime(self.naive_utc())] - } - - type Decoder = UtcDateTimeDecoder; -} -impl AsDbType for chrono::DateTime { - type Primitive = chrono::NaiveDateTime; - type DbType = db_type::DateTime; - - fn from_primitive(primitive: Self::Primitive) -> Self { - Utc.from_utc_datetime(&primitive) - } -} -new_converting_decoder!( - /// [`FieldDecoder`](crate::internal::field::decoder::FieldDecoder) for [`Option>`](chrono::DateTime) - OptionUtcDateTimeDecoder, - |value: Option| -> Option> { - Ok(value.map(|value| Utc.from_utc_datetime(&value))) - } +impl_AsDbType!( + String, + db_type::VarChar, + |s| Value::String(Cow::Owned(s)), + |s| { Value::String(Cow::Borrowed(s)) } ); -impl_option_as_db_type!(chrono::DateTime, OptionUtcDateTimeDecoder); diff --git a/src/internal/field/datetime.rs b/src/internal/field/datetime.rs deleted file mode 100644 index 6dfed50..0000000 --- a/src/internal/field/datetime.rs +++ /dev/null @@ -1,199 +0,0 @@ -//! Implementation detail of [`DateTime`] - -use std::marker::PhantomData; - -use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone}; -use rorm_db::Error::DecodeError; -use rorm_db::{Error, Row}; -use rorm_declaration::imr; - -use crate::conditions::Value; -use crate::crud::decoder::{Decoder, DirectDecoder}; -use crate::internal::field::as_db_type::AsDbType; -use crate::internal::field::decoder::FieldDecoder; -use crate::internal::field::{ - kind, AbstractField, ContainerField, FieldProxy, FieldType, RawField, -}; -use crate::internal::hmr::annotations::Annotations; -use crate::internal::hmr::{db_type, Source}; -use crate::internal::query_context::QueryContext; -use crate::internal::relation_path::Path; -use crate::model::ConstNew; -use crate::{const_concat, impl_option_as_db_type, new_converting_decoder, sealed}; - -new_converting_decoder!( - /// [`FieldDecoder`] for [`FixedOffset`] - FixedOffsetDecoder, - |value: i32| -> FixedOffset { - FixedOffset::east_opt(value) - .ok_or_else(|| DecodeError(format!("Couldn't decode fixed offset: {value}"))) - } -); -impl FieldType for FixedOffset { - type Kind = kind::AsDbType; - - type Columns = [T; 1]; - - fn into_values(self) -> Self::Columns> { - [Value::I32(self.local_minus_utc())] - } - - fn as_values(&self) -> Self::Columns> { - [Value::I32(self.local_minus_utc())] - } - - type Decoder = FixedOffsetDecoder; -} -impl AsDbType for FixedOffset { - type Primitive = i32; - type DbType = db_type::Int32; - - fn from_primitive(primitive: Self::Primitive) -> Self { - FixedOffset::east_opt(primitive).unwrap() // TODO handle this - } -} -new_converting_decoder!( - /// [`FieldDecoder`] for [`Option`](FixedOffset) - OptionFixedOffsetDecoder, - |value: Option| -> Option { - value - .map(|value| { - FixedOffset::east_opt(value) - .ok_or_else(|| DecodeError(format!("Couldn't decode fixed offset: {value}"))) - }) - .transpose() - } -); -impl_option_as_db_type!(FixedOffset, OptionFixedOffsetDecoder); - -impl FieldType for DateTime { - type Kind = kind::DateTime; - - type Columns = [T; 2]; - - fn into_values(self) -> Self::Columns> { - let [offset] = self.offset().into_values(); - [offset, Value::NaiveDateTime(self.naive_utc())] - } - - fn as_values(&self) -> Self::Columns> { - let [offset] = self.offset().as_values(); - [offset, Value::NaiveDateTime(self.naive_utc())] - } - - type Decoder = DateTimeDecoder; -} - -/// [`FieldDecoder`] for [`DateTime`] -pub struct DateTimeDecoder { - offset: FixedOffsetDecoder, - utc: DirectDecoder, -} -impl Decoder for DateTimeDecoder { - type Result = DateTime; - - fn by_name(&self, row: &Row) -> Result { - let offset = self.offset.by_name(row)?; - let utc = self.utc.by_name(row)?; - Ok(offset.from_utc_datetime(&utc)) - } - - fn by_index(&self, row: &Row) -> Result { - let offset = self.offset.by_index(row)?; - let utc = self.utc.by_index(row)?; - Ok(offset.from_utc_datetime(&utc)) - } -} -impl FieldDecoder for DateTimeDecoder { - fn new(ctx: &mut QueryContext, _: FieldProxy) -> Self - where - F: RawField, - P: Path, - { - Self { - offset: FixedOffsetDecoder::new(ctx, FieldProxy::<__DateTime_offset, P>::new()), - utc: DirectDecoder::new(ctx, FieldProxy::<__DateTime_utc, P>::new()), - } - } -} -impl AbstractField for F -where - F: RawField>, -{ - sealed!(impl); - - fn push_imr(self, imr: &mut Vec) { - __DateTime_offset::::new().push_imr(imr); - __DateTime_utc::::new().push_imr(imr); - } - - const COLUMNS: &'static [&'static str] = - &[__DateTime_offset::::NAME, __DateTime_utc::::NAME]; -} -impl ContainerField for F -where - P: Path, - F: RawField>, -{ - type Target = __DateTime_Fields; -} - -/// [`DateTime`]'s internal fields -#[allow(non_camel_case_types)] -pub struct __DateTime_Fields { - /// [`DateTime`]'s internal offset field - pub offset: FieldProxy<__DateTime_offset, P>, - - /// [`DateTime`]'s internal offset field - pub utc: FieldProxy<__DateTime_utc, P>, -} -impl ConstNew for __DateTime_Fields -where - F: RawField>, -{ - const NEW: Self = __DateTime_Fields { - offset: FieldProxy::new(), - utc: FieldProxy::new(), - }; - const REF: &'static Self = &Self::NEW; -} - -/// [`DateTime`]'s internal offset field -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub struct __DateTime_offset(PhantomData); -impl RawField for __DateTime_offset -where - F: RawField>, -{ - type Kind = kind::AsDbType; - type Type = FixedOffset; - type Model = F::Model; - const INDEX: usize = F::INDEX + 1; - const NAME: &'static str = const_concat!(&[F::NAME, "_offset"]); - const EXPLICIT_ANNOTATIONS: Annotations = F::EXPLICIT_ANNOTATIONS; - const SOURCE: Option = F::SOURCE; - fn new() -> Self { - Self(PhantomData) - } -} - -/// [`DateTime`]'s internal offset field -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub struct __DateTime_utc(PhantomData); -impl RawField for __DateTime_utc -where - F: RawField>, -{ - type Kind = kind::AsDbType; - type Type = NaiveDateTime; - type Model = F::Model; - const INDEX: usize = F::INDEX + 2; - const NAME: &'static str = const_concat!(&[F::NAME, "_utc"]); - const EXPLICIT_ANNOTATIONS: Annotations = F::EXPLICIT_ANNOTATIONS; - const SOURCE: Option = F::SOURCE; - fn new() -> Self { - Self(PhantomData) - } -} diff --git a/src/internal/field/mod.rs b/src/internal/field/mod.rs index 3c3bfe8..9e3318e 100644 --- a/src/internal/field/mod.rs +++ b/src/internal/field/mod.rs @@ -82,7 +82,6 @@ use crate::{const_panic, sealed}; pub mod access; pub mod as_db_type; -pub mod datetime; pub mod decoder; pub mod foreign_model;