valis_core/modules/db/
serializers.rs

1use std::str::FromStr;
2
3use chrono::{DateTime, Duration, NaiveDate, ParseError, Utc};
4use rusqlite::types::FromSqlError;
5use rusqlite::types::{FromSql, FromSqlResult, ValueRef};
6use serde::de::Error;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9#[derive(Debug, Clone)]
10pub struct SerializableDateTime(DateTime<Utc>);
11
12impl Serialize for SerializableDateTime {
13    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14    where
15        S: Serializer,
16    {
17        let s = self.0.to_rfc3339();
18        serializer.serialize_str(&s)
19    }
20}
21
22impl<'de> Deserialize<'de> for SerializableDateTime {
23    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
24    where
25        D: Deserializer<'de>,
26    {
27        let s = String::deserialize(deserializer)?;
28        let dt = DateTime::parse_from_rfc3339(&s)
29            .map_err(Error::custom)?
30            .with_timezone(&Utc);
31        Ok(SerializableDateTime(dt))
32    }
33}
34
35impl FromSql for SerializableDateTime {
36    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
37        match value {
38            ValueRef::Text(s) => {
39                let s = String::from_utf8(s.to_vec())
40                    .map_err(|_| rusqlite::types::FromSqlError::InvalidType)?;
41                DateTime::from_str(&s)
42                    .map_err(|_| FromSqlError::InvalidType)
43                    .map(|dt| SerializableDateTime(dt))
44            }
45            ValueRef::Blob(b) => {
46                let s = String::from_utf8(b.to_vec())
47                    .map_err(|_| rusqlite::types::FromSqlError::InvalidType)?;
48                DateTime::parse_from_rfc3339(&s)
49                    .map_err(|_| rusqlite::types::FromSqlError::InvalidType)
50                    .map(|dt| SerializableDateTime(dt.with_timezone(&Utc)))
51            }
52            _ => Err(FromSqlError::InvalidType),
53        }
54    }
55}
56
57impl SerializableDateTime {
58    pub fn parse_from_rfc3339(s: &str) -> Result<SerializableDateTime, ParseError> {
59        let dt = DateTime::parse_from_rfc3339(s)?;
60        Ok(SerializableDateTime(dt.with_timezone(&Utc)))
61    }
62    pub fn with_timezone(&self, tz: &Utc) -> SerializableDateTime {
63        SerializableDateTime(self.0.with_timezone(tz))
64    }
65    pub fn now() -> Self {
66        SerializableDateTime(Utc::now())
67    }
68    pub fn to_string(&self) -> String {
69        self.0.to_rfc3339()
70    }
71    pub fn add_weeks(&self, weeks: i64) -> Self {
72        SerializableDateTime(self.0 + Duration::weeks(weeks))
73    }
74    // Create a new SerializableDateTime from a string
75    pub fn from_str(date: &str) -> Result<Self, chrono::format::ParseError> {
76        let naive_date = NaiveDate::parse_from_str(date, "%Y-%m-%d")?;
77        let datetime = DateTime::from_utc(naive_date.and_hms(0, 0, 0), Utc);
78        Ok(SerializableDateTime(datetime))
79    }
80    pub fn get_utc(&self) -> DateTime<Utc> {
81        self.0
82    }
83}