use chrono::{NaiveDate, NaiveDateTime, NaiveTime, TimeDelta};
use diesel::{
deserialize::{FromSql, Result as DeserializeResult},
serialize::{IsNull, Output, Result as SerializeResult, ToSql},
sql_types::{BigInt, Date as SqlDate, Interval, Time, Timestamp as SqlTimestamp},
};
#[cfg(feature = "date")]
use crate::Date;
#[cfg(feature = "datetime")]
use crate::DateTime;
#[cfg(feature = "timeofday")]
use crate::TimeOfDay;
use crate::{Duration, Timestamp};
#[cfg(feature = "diesel-mysql")]
mod diesel_mysql {
use diesel::{
mysql::{Mysql, MysqlValue},
sql_types::Datetime as MysqlDateTime,
};
use super::*;
#[cfg(feature = "timeofday")]
impl FromSql<Time, Mysql> for TimeOfDay {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_time: NaiveTime = FromSql::<Time, Mysql>::from_sql(bytes)?;
Ok(chrono_time.into())
}
}
impl FromSql<SqlTimestamp, Mysql> for Timestamp {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Mysql>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
impl FromSql<BigInt, Mysql> for Timestamp {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let millis: i64 = FromSql::<BigInt, Mysql>::from_sql(bytes)?;
Ok(Self::from_unix_millis(millis))
}
}
impl FromSql<MysqlDateTime, Mysql> for Timestamp {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<MysqlDateTime, Mysql>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "datetime")]
impl FromSql<SqlTimestamp, Mysql> for DateTime {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Mysql>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "datetime")]
impl FromSql<MysqlDateTime, Mysql> for DateTime {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<MysqlDateTime, Mysql>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "date")]
impl FromSql<SqlDate, Mysql> for Date {
fn from_sql(bytes: MysqlValue<'_>) -> DeserializeResult<Self> {
let chrono_date: NaiveDate = FromSql::<SqlDate, Mysql>::from_sql(bytes)?;
Ok(chrono_date.into())
}
}
#[cfg(feature = "timeofday")]
impl ToSql<Time, Mysql> for TimeOfDay {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
let chrono_time: NaiveTime = (*self).try_into()?;
ToSql::<Time, Mysql>::to_sql(&chrono_time, &mut out.reborrow())
}
}
impl ToSql<SqlTimestamp, Mysql> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = (*self).try_into()?;
ToSql::<SqlTimestamp, Mysql>::to_sql(&chrono_datetime, &mut out.reborrow())
}
}
impl ToSql<BigInt, Mysql> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
let millis = self
.checked_total_i64_millis()
.ok_or("Failed to convert proto timestamp to UNIX milliseconds")?;
ToSql::<BigInt, Mysql>::to_sql(&millis, &mut out.reborrow())
}
}
impl ToSql<MysqlDateTime, Mysql> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
ToSql::<SqlTimestamp, Mysql>::to_sql(self, out)
}
}
#[cfg(feature = "datetime")]
impl ToSql<SqlTimestamp, Mysql> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = self.clone().try_into()?;
ToSql::<SqlTimestamp, Mysql>::to_sql(&chrono_datetime, &mut out.reborrow())
}
}
#[cfg(feature = "datetime")]
impl ToSql<MysqlDateTime, Mysql> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
ToSql::<SqlTimestamp, Mysql>::to_sql(self, out)
}
}
#[cfg(feature = "date")]
impl ToSql<SqlDate, Mysql> for Date {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> SerializeResult {
let chrono_date: NaiveDate = (*self).try_into()?;
ToSql::<SqlDate, Mysql>::to_sql(&chrono_date, &mut out.reborrow())
}
}
}
#[cfg(feature = "diesel-postgres")]
mod diesel_postgres {
use diesel::{
pg::{Pg, PgValue},
sql_types::Timestamptz,
};
use super::*;
impl FromSql<Interval, Pg> for Duration {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_duration: TimeDelta = FromSql::<Interval, Pg>::from_sql(bytes)?;
Ok(chrono_duration.into())
}
}
#[cfg(feature = "timeofday")]
impl FromSql<Time, Pg> for TimeOfDay {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_time: NaiveTime = FromSql::<Time, Pg>::from_sql(bytes)?;
Ok(chrono_time.into())
}
}
impl FromSql<SqlTimestamp, Pg> for Timestamp {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Pg>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
impl FromSql<BigInt, Pg> for Timestamp {
fn from_sql(value: PgValue<'_>) -> DeserializeResult<Self> {
let millis: i64 = FromSql::<BigInt, Pg>::from_sql(value)?;
Ok(Self::from_unix_millis(millis))
}
}
impl FromSql<Timestamptz, Pg> for Timestamp {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<Timestamptz, Pg>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "datetime")]
impl FromSql<SqlTimestamp, Pg> for DateTime {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Pg>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "datetime")]
impl FromSql<Timestamptz, Pg> for DateTime {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<Timestamptz, Pg>::from_sql(bytes)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "date")]
impl FromSql<SqlDate, Pg> for Date {
fn from_sql(bytes: PgValue<'_>) -> DeserializeResult<Self> {
let chrono_date: NaiveDate = FromSql::<SqlDate, Pg>::from_sql(bytes)?;
Ok(chrono_date.into())
}
}
impl ToSql<Interval, Pg> for Duration {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let chrono_duration: TimeDelta = (*self).try_into()?;
ToSql::<Interval, Pg>::to_sql(&chrono_duration, &mut out.reborrow())
}
}
#[cfg(feature = "timeofday")]
impl ToSql<Time, Pg> for TimeOfDay {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let chrono_time: NaiveTime = (*self).try_into()?;
ToSql::<Time, Pg>::to_sql(&chrono_time, &mut out.reborrow())
}
}
impl ToSql<BigInt, Pg> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let millis = self
.checked_total_i64_millis()
.ok_or("Failed to convert proto timestamp to UNIX milliseconds")?;
ToSql::<BigInt, Pg>::to_sql(&millis, &mut out.reborrow())
}
}
impl ToSql<SqlTimestamp, Pg> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = (*self).try_into()?;
ToSql::<SqlTimestamp, Pg>::to_sql(&chrono_datetime, &mut out.reborrow())
}
}
impl ToSql<Timestamptz, Pg> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
ToSql::<SqlTimestamp, Pg>::to_sql(self, out)
}
}
#[cfg(feature = "datetime")]
impl ToSql<SqlTimestamp, Pg> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = self.clone().try_into()?;
ToSql::<SqlTimestamp, Pg>::to_sql(&chrono_datetime, &mut out.reborrow())
}
}
#[cfg(feature = "datetime")]
impl ToSql<Timestamptz, Pg> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
ToSql::<SqlTimestamp, Pg>::to_sql(self, out)
}
}
#[cfg(feature = "date")]
impl ToSql<SqlDate, Pg> for Date {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> SerializeResult {
let chrono_date: NaiveDate = (*self).try_into()?;
ToSql::<SqlDate, Pg>::to_sql(&chrono_date, &mut out.reborrow())
}
}
}
#[cfg(feature = "diesel-sqlite")]
mod diesel_sqlite {
use crate::{String, ToString};
use diesel::{backend::Backend, sql_types::TimestamptzSqlite, sqlite::Sqlite};
use super::*;
const ENCODE_NAIVE_DATETIME_FORMAT: &str = "%F %T%.f";
const DATE_FORMAT: &str = "%F";
const ENCODE_TIME_FORMAT: &str = "%T%.f";
fn format_naive_datetime(value: NaiveDateTime) -> String {
value
.format(ENCODE_NAIVE_DATETIME_FORMAT)
.to_string()
}
#[cfg(feature = "timeofday")]
impl FromSql<Time, Sqlite> for TimeOfDay {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_time: NaiveTime = FromSql::<Time, Sqlite>::from_sql(value)?;
Ok(chrono_time.into())
}
}
impl FromSql<SqlTimestamp, Sqlite> for Timestamp {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Sqlite>::from_sql(value)?;
Ok(chrono_datetime.into())
}
}
impl FromSql<TimestamptzSqlite, Sqlite> for Timestamp {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime =
FromSql::<TimestamptzSqlite, Sqlite>::from_sql(value)?;
Ok(chrono_datetime.into())
}
}
impl FromSql<BigInt, Sqlite> for Timestamp {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let millis: i64 = FromSql::<BigInt, Sqlite>::from_sql(value)?;
Ok(Self::from_unix_millis(millis))
}
}
#[cfg(feature = "datetime")]
impl FromSql<SqlTimestamp, Sqlite> for DateTime {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime = FromSql::<SqlTimestamp, Sqlite>::from_sql(value)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "datetime")]
impl FromSql<TimestamptzSqlite, Sqlite> for DateTime {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_datetime: NaiveDateTime =
FromSql::<TimestamptzSqlite, Sqlite>::from_sql(value)?;
Ok(chrono_datetime.into())
}
}
#[cfg(feature = "date")]
impl FromSql<SqlDate, Sqlite> for Date {
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> DeserializeResult<Self> {
let chrono_date: NaiveDate = FromSql::<SqlDate, Sqlite>::from_sql(value)?;
Ok(chrono_date.into())
}
}
#[cfg(feature = "timeofday")]
impl ToSql<Time, Sqlite> for TimeOfDay {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_time: NaiveTime = (*self).try_into()?;
out.set_value(chrono_time.format(ENCODE_TIME_FORMAT).to_string());
Ok(IsNull::No)
}
}
impl ToSql<BigInt, Sqlite> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let millis = self
.checked_total_i64_millis()
.ok_or("Failed to convert proto timestamp to UNIX milliseconds")?;
out.set_value(millis);
Ok(IsNull::No)
}
}
impl ToSql<TimestamptzSqlite, Sqlite> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = (*self).try_into()?;
out.set_value(format_naive_datetime(chrono_datetime));
Ok(IsNull::No)
}
}
impl ToSql<SqlTimestamp, Sqlite> for Timestamp {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = (*self).try_into()?;
out.set_value(format_naive_datetime(chrono_datetime));
Ok(IsNull::No)
}
}
#[cfg(feature = "datetime")]
impl ToSql<TimestamptzSqlite, Sqlite> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = self.clone().try_into()?;
out.set_value(format_naive_datetime(chrono_datetime));
Ok(IsNull::No)
}
}
#[cfg(feature = "datetime")]
impl ToSql<SqlTimestamp, Sqlite> for DateTime {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_datetime: NaiveDateTime = self.clone().try_into()?;
out.set_value(format_naive_datetime(chrono_datetime));
Ok(IsNull::No)
}
}
#[cfg(feature = "date")]
impl ToSql<SqlDate, Sqlite> for Date {
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> SerializeResult {
let chrono_date: NaiveDate = (*self).try_into()?;
out.set_value(chrono_date.format(DATE_FORMAT).to_string());
Ok(IsNull::No)
}
}
}