diff --git a/sea-query-sqlx/src/sqlx_any.rs b/sea-query-sqlx/src/sqlx_any.rs index f128eb14a..b22489240 100644 --- a/sea-query-sqlx/src/sqlx_any.rs +++ b/sea-query-sqlx/src/sqlx_any.rs @@ -88,6 +88,10 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::any::Any> for SqlxValues { let _ = args.add(Value::TimeDateTime(t).time_as_naive_utc_in_string()); } #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(t) => { + let _ = args.add(Value::TimeDateTimeUtc(t).time_as_naive_utc_in_string()); + } + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(t) => { let _ = args.add(Value::TimeDateTimeWithTimeZone(t).time_as_naive_utc_in_string()); diff --git a/sea-query-sqlx/src/sqlx_mysql.rs b/sea-query-sqlx/src/sqlx_mysql.rs index 0cec071b3..ca48c27ec 100644 --- a/sea-query-sqlx/src/sqlx_mysql.rs +++ b/sea-query-sqlx/src/sqlx_mysql.rs @@ -87,6 +87,10 @@ impl sqlx::IntoArguments<'_, sqlx::mysql::MySql> for SqlxValues { let _ = args.add(t); } #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(t) => { + let _ = args.add(t.map(sqlx::types::time::OffsetDateTime::from)); + } + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(t) => { let _ = args.add(t); } diff --git a/sea-query-sqlx/src/sqlx_postgres.rs b/sea-query-sqlx/src/sqlx_postgres.rs index fe04fb3b8..b21932a82 100644 --- a/sea-query-sqlx/src/sqlx_postgres.rs +++ b/sea-query-sqlx/src/sqlx_postgres.rs @@ -104,6 +104,10 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues { let _ = args.add(t); } #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(t) => { + let _ = args.add(t.map(sqlx::types::time::OffsetDateTime::from)); + } + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(t) => { let _ = args.add(t); } @@ -273,6 +277,15 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues { let _ = args.add(value); } #[cfg(feature = "with-time")] + ArrayType::TimeDateTimeUtc => { + let value: Option> = Value::Array(ty, v) + .expect("This Value::Array should consist of Value::TimeDateTimeUtc"); + // temprorary, until sqlx supports UtcDateTime + let value: Option> = value + .map(|vec| vec.into_iter().map(time::OffsetDateTime::from).collect()); + let _ = args.add(value); + } + #[cfg(feature = "with-time")] ArrayType::TimeDateTimeWithTimeZone => { let value: Option> = Value::Array(ty, v).expect( "This Value::Array should consist of Value::TimeDateTimeWithTimeZone", diff --git a/sea-query-sqlx/src/sqlx_sqlite.rs b/sea-query-sqlx/src/sqlx_sqlite.rs index 555633f00..2f1758b7c 100644 --- a/sea-query-sqlx/src/sqlx_sqlite.rs +++ b/sea-query-sqlx/src/sqlx_sqlite.rs @@ -87,6 +87,10 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::sqlite::Sqlite> for SqlxValues { let _ = args.add(t); } #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(t) => { + let _ = args.add(t.map(sqlx::types::time::OffsetDateTime::from)); + } + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(t) => { let _ = args.add(t); } @@ -100,7 +104,6 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::sqlite::Sqlite> for SqlxValues { } #[cfg(feature = "with-bigdecimal")] Value::BigDecimal(big_decimal) => { - use sea_query::prelude::bigdecimal::ToPrimitive; let _ = args.add(big_decimal.map(|d| d.to_string())); } #[cfg(feature = "with-json")] diff --git a/src/backend/query_builder.rs b/src/backend/query_builder.rs index aa12f4877..36e7331bc 100644 --- a/src/backend/query_builder.rs +++ b/src/backend/query_builder.rs @@ -1199,6 +1199,8 @@ pub trait QueryBuilder: #[cfg(feature = "with-time")] Value::TimeDateTime(None) => buf.write_str("NULL")?, #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(None) => buf.write_str("NULL")?, + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(None) => buf.write_str("NULL")?, #[cfg(feature = "with-jiff")] Value::JiffDate(None) => buf.write_str("NULL")?, @@ -1315,6 +1317,12 @@ pub trait QueryBuilder: buf.write_str("'")?; } #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(Some(v)) => { + buf.write_str("'")?; + buf.write_str(&v.format(time_format::FORMAT_DATETIME_TZ).unwrap())?; + buf.write_str("'")?; + } + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(Some(v)) => { buf.write_str("'")?; buf.write_str(&v.format(time_format::FORMAT_DATETIME_TZ).unwrap())?; diff --git a/src/value.rs b/src/value.rs index 337e5f18a..38b6bbbe4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -134,6 +134,10 @@ pub enum ArrayType { #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] TimeDateTime, + #[cfg(feature = "with-time")] + #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] + TimeDateTimeUtc, + #[cfg(feature = "with-time")] #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] TimeDateTimeWithTimeZone, @@ -246,6 +250,10 @@ pub enum Value { #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] TimeDateTime(Option), + #[cfg(feature = "with-time")] + #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] + TimeDateTimeUtc(Option), + #[cfg(feature = "with-time")] #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] TimeDateTimeWithTimeZone(Option), @@ -409,6 +417,10 @@ impl Value { #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] Self::TimeDateTime(_) => Self::TimeDateTime(None), + #[cfg(feature = "with-time")] + #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] + Self::TimeDateTimeUtc(_) => Self::TimeDateTimeUtc(None), + #[cfg(feature = "with-time")] #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] Self::TimeDateTimeWithTimeZone(_) => Self::TimeDateTimeWithTimeZone(None), @@ -535,6 +547,10 @@ impl Value { #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] Self::TimeDateTime(_) => Self::TimeDateTime(Some(PrimitiveDateTime::MIN)), + #[cfg(feature = "with-time")] + #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] + Self::TimeDateTimeUtc(_) => Self::TimeDateTimeUtc(Some(time::UtcDateTime::MIN)), + #[cfg(feature = "with-time")] #[cfg_attr(docsrs, doc(cfg(feature = "with-time")))] Self::TimeDateTimeWithTimeZone(_) => { diff --git a/src/value/hashable_value.rs b/src/value/hashable_value.rs index 087ba976b..8635c82d8 100644 --- a/src/value/hashable_value.rs +++ b/src/value/hashable_value.rs @@ -131,6 +131,8 @@ impl Hash for Value { #[cfg(feature = "with-time")] Value::TimeDateTime(primitive_date_time) => primitive_date_time.hash(state), #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(utc_date_time) => utc_date_time.hash(state), + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(offset_date_time) => offset_date_time.hash(state), #[cfg(feature = "with-jiff")] diff --git a/src/value/prelude.rs b/src/value/prelude.rs index 660c004fc..59a0395e0 100644 --- a/src/value/prelude.rs +++ b/src/value/prelude.rs @@ -5,7 +5,7 @@ pub use serde_json::{self, Value as Json}; pub use chrono::{self, DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc}; #[cfg(feature = "with-time")] -pub use time::{self, OffsetDateTime, PrimitiveDateTime}; +pub use time::{self, OffsetDateTime, PrimitiveDateTime, UtcDateTime}; #[cfg(feature = "with-jiff")] pub use jiff::{self, Timestamp, Zoned}; diff --git a/src/value/with_array.rs b/src/value/with_array.rs index ef198974f..bf35014f9 100644 --- a/src/value/with_array.rs +++ b/src/value/with_array.rs @@ -49,6 +49,9 @@ impl NotU8 for PrimitiveDateTime {} #[cfg(feature = "with-time")] impl NotU8 for OffsetDateTime {} +#[cfg(feature = "with-time")] +impl NotU8 for UtcDateTime {} + #[cfg(feature = "with-rust_decimal")] impl NotU8 for Decimal {} diff --git a/src/value/with_json.rs b/src/value/with_json.rs index 63e51bd53..36a40eb15 100644 --- a/src/value/with_json.rs +++ b/src/value/with_json.rs @@ -84,6 +84,8 @@ pub fn sea_value_to_json_value(value: &Value) -> Json { #[cfg(feature = "with-time")] Value::TimeDateTime(_) => CommonSqlQueryBuilder.value_to_string(value).into(), #[cfg(feature = "with-time")] + Value::TimeDateTimeUtc(_) => CommonSqlQueryBuilder.value_to_string(value).into(), + #[cfg(feature = "with-time")] Value::TimeDateTimeWithTimeZone(_) => CommonSqlQueryBuilder.value_to_string(value).into(), #[cfg(feature = "with-jiff")] Value::JiffDate(_) => CommonSqlQueryBuilder.value_to_string(value).into(), diff --git a/src/value/with_time.rs b/src/value/with_time.rs index 291feb1ce..c3716b8ab 100644 --- a/src/value/with_time.rs +++ b/src/value/with_time.rs @@ -8,25 +8,27 @@ impl DateLikeValue for time::Date {} impl TimeLikeValue for time::Time {} impl DateTimeLikeValue for time::PrimitiveDateTime {} impl DateTimeLikeValue for time::OffsetDateTime {} +impl DateTimeLikeValue for time::UtcDateTime {} impl DateLikeValueNullable for Option {} impl TimeLikeValueNullable for Option {} impl DateTimeLikeValueNullable for Option {} impl DateTimeLikeValueNullable for Option {} +impl DateTimeLikeValueNullable for Option {} -impl From for Value { - fn from(v: OffsetDateTime) -> Value { +impl From for Value { + fn from(v: time::OffsetDateTime) -> Value { Value::TimeDateTimeWithTimeZone(Some(v)) } } -impl Nullable for OffsetDateTime { +impl Nullable for time::OffsetDateTime { fn null() -> Value { Value::TimeDateTimeWithTimeZone(None) } } -impl ValueType for OffsetDateTime { +impl ValueType for time::OffsetDateTime { fn try_from(v: Value) -> Result { match v { Value::TimeDateTimeWithTimeZone(Some(x)) => Ok(x), @@ -47,6 +49,39 @@ impl ValueType for OffsetDateTime { } } +impl From for Value { + fn from(v: time::UtcDateTime) -> Value { + Value::TimeDateTimeUtc(Some(v)) + } +} + +impl Nullable for time::UtcDateTime { + fn null() -> Value { + Value::TimeDateTimeUtc(None) + } +} + +impl ValueType for time::UtcDateTime { + fn try_from(v: Value) -> Result { + match v { + Value::TimeDateTimeUtc(Some(x)) => Ok(x), + _ => Err(ValueTypeErr), + } + } + + fn type_name() -> String { + stringify!(UtcDateTime).to_owned() + } + + fn array_type() -> ArrayType { + ArrayType::TimeDateTimeUtc + } + + fn column_type() -> ColumnType { + ColumnType::TimestampWithTimeZone + } +} + impl Value { pub fn is_time_date(&self) -> bool { matches!(self, Self::TimeDate(_)) @@ -86,6 +121,19 @@ impl Value { } } +impl Value { + pub fn is_time_date_time_utc(&self) -> bool { + matches!(self, Self::TimeDateTimeUtc(_)) + } + + pub fn as_ref_time_date_time_utc(&self) -> Option<&time::UtcDateTime> { + match self { + Self::TimeDateTimeUtc(v) => v.as_ref(), + _ => panic!("not Value::TimeDateTimeUtc"), + } + } +} + impl Value { pub fn is_time_date_time_with_time_zone(&self) -> bool { matches!(self, Self::TimeDateTimeWithTimeZone(_)) @@ -111,6 +159,9 @@ impl Value { Self::TimeDateTime(v) => v .as_ref() .and_then(|v| v.format(time_format::FORMAT_DATETIME).ok()), + Self::TimeDateTimeUtc(v) => v.as_ref().and_then(|v| { + v.format(time_format::FORMAT_DATETIME_TZ).ok() + }), Self::TimeDateTimeWithTimeZone(v) => v.as_ref().and_then(|v| { v.to_offset(time::macros::offset!(UTC)) .format(time_format::FORMAT_DATETIME_TZ)