From 516af077131b0d6ec4c71282c660d73cae119e02 Mon Sep 17 00:00:00 2001 From: Felipe Lessa Date: Sat, 27 Jun 2020 09:31:42 +0100 Subject: [PATCH] Sqlite support for DateTime<{Utc,Local}>. --- sqlx-core/src/sqlite/types/chrono.rs | 85 ++++++++++++++++++---------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/sqlx-core/src/sqlite/types/chrono.rs b/sqlx-core/src/sqlite/types/chrono.rs index 37ec119a..f6e9b090 100644 --- a/sqlx-core/src/sqlite/types/chrono.rs +++ b/sqlx-core/src/sqlite/types/chrono.rs @@ -22,40 +22,67 @@ impl Encode<'_, Sqlite> for NaiveDateTime { impl<'a> Decode<'a, Sqlite> for NaiveDateTime { fn decode(value: SqliteValueRef<'a>) -> Result { - let text = Decode::::decode(value)?; - decode_from_text(text) + decode_naive_from_text(value.text()?) } } -fn decode_from_text(text: Option<&str>) -> Result { - if let Some(raw) = text { - // Loop over common date time patterns, inspired by Diesel - // https://docs.diesel.rs/src/diesel/sqlite/types/date_and_time/chrono.rs.html#56-97 - let sqlite_datetime_formats = &[ - // Most likely format - "%F %T%.f", - // Other formats in order of appearance in docs - "%F %R", - "%F %RZ", - "%F %R%:z", - "%F %T%.fZ", - "%F %T%.f%:z", - "%FT%R", - "%FT%RZ", - "%FT%R%:z", - "%FT%T%.f", - "%FT%T%.fZ", - "%FT%T%.f%:z", - ]; +fn decode_naive_from_text(text: &str) -> Result { + // Loop over common date time patterns, inspired by Diesel + // https://docs.diesel.rs/src/diesel/sqlite/types/date_and_time/chrono.rs.html#56-97 + let sqlite_datetime_formats = &[ + // Most likely format + "%F %T%.f", + // Other formats in order of appearance in docs + "%F %R", + "%F %RZ", + "%F %R%:z", + "%F %T%.fZ", + "%F %T%.f%:z", + "%FT%R", + "%FT%RZ", + "%FT%R%:z", + "%FT%T%.f", + "%FT%T%.fZ", + "%FT%T%.f%:z", + ]; - for format in sqlite_datetime_formats { - if let Ok(dt) = NaiveDateTime::parse_from_str(raw, format) { - return Ok(dt); - } + for format in sqlite_datetime_formats { + if let Ok(dt) = NaiveDateTime::parse_from_str(text, format) { + return Ok(dt); } - - return Err(err_protocol!("Did not find a matching pattern").into()); } - Err(err_protocol!("There was no text value to decode").into()) + return Err(err_protocol!("Did not find a matching pattern").into()); +} + +impl Type for DateTime { + fn type_info() -> SqliteTypeInfo { + SqliteTypeInfo(DataType::Timestamp) + } +} + +impl Encode<'_, Sqlite> for DateTime { + fn encode_by_ref(&self, buf: &mut Vec>) -> IsNull { + let text = self.with_timezone(&Utc).to_rfc3339(); + Encode::::encode(text, buf) + } +} + +impl<'a> Decode<'a, Sqlite> for DateTime { + fn decode(value: SqliteValueRef<'a>) -> Result { + let text = value.text()?; + if let Ok(dt) = DateTime::parse_from_rfc3339(text) { + Ok(dt.with_timezone(&Utc)) + } else { + let dt = decode_naive_from_text(text)?; + Ok(Utc.from_utc_datetime(&dt)) + } + } +} + +impl<'a> Decode<'a, Sqlite> for DateTime { + fn decode(value: SqliteValueRef<'a>) -> Result { + let as_utc: DateTime = Decode::::decode(value)?; + Ok(as_utc.with_timezone(&Local)) + } }