retrom_codegen/
timestamp.rs

1use std::time::{Duration, SystemTime, UNIX_EPOCH};
2
3use diesel::sql_types::{self, SqlType};
4use diesel::{
5    deserialize::{FromSql, FromSqlRow},
6    expression::AsExpression,
7    pg::PgValue,
8    serialize::{Output, ToSql},
9};
10
11fn pg_epoch() -> SystemTime {
12    let thirty_years = Duration::from_secs(946_684_800);
13    UNIX_EPOCH + thirty_years
14}
15
16#[derive(
17    Clone,
18    Eq,
19    Hash,
20    PartialEq,
21    PartialOrd,
22    Ord,
23    ::prost::Message,
24    ::serde::Serialize,
25    ::serde::Deserialize,
26    SqlType,
27    AsExpression,
28    FromSqlRow,
29)]
30#[diesel(postgres_type(oid = 1114, array_oid = 1115))]
31#[diesel(sql_type = diesel::sql_types::Timestamp)]
32#[diesel(sql_type = diesel::sql_types::Timestamptz)]
33pub struct Timestamp {
34    #[prost(int64, tag = "1")]
35    pub seconds: i64,
36    #[prost(int32, tag = "2")]
37    pub nanos: i32,
38}
39
40impl Timestamp {}
41
42impl TryFrom<Timestamp> for prost_types::Timestamp {
43    type Error = prost::DecodeError;
44
45    fn try_from(value: Timestamp) -> Result<Self, Self::Error> {
46        Ok(prost_types::Timestamp {
47            seconds: value.seconds,
48            nanos: value.nanos,
49        })
50    }
51}
52
53impl From<prost_types::Timestamp> for Timestamp {
54    fn from(value: prost_types::Timestamp) -> Self {
55        Timestamp {
56            seconds: value.seconds,
57            nanos: value.nanos,
58        }
59    }
60}
61
62impl From<std::time::SystemTime> for Timestamp {
63    fn from(time: std::time::SystemTime) -> Self {
64        prost_types::Timestamp::from(time).into()
65    }
66}
67
68impl ToSql<sql_types::Timestamp, diesel::pg::Pg> for Timestamp {
69    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::pg::Pg>) -> diesel::serialize::Result {
70        let thirty_years_seconds = 946_684_800;
71        let micros = (self.seconds - thirty_years_seconds) * 1_000_000 + self.nanos as i64 / 1_000;
72
73        ToSql::<sql_types::BigInt, diesel::pg::Pg>::to_sql(&micros, &mut out.reborrow())
74    }
75}
76
77impl ToSql<sql_types::Timestamptz, diesel::pg::Pg> for Timestamp {
78    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::pg::Pg>) -> diesel::serialize::Result {
79        ToSql::<sql_types::Timestamp, diesel::pg::Pg>::to_sql(self, out)
80    }
81}
82
83impl FromSql<sql_types::Timestamp, diesel::pg::Pg> for Timestamp {
84    fn from_sql(bytes: PgValue<'_>) -> diesel::deserialize::Result<Self> {
85        let micros = i64::from_sql(bytes)?;
86
87        let pg_timestamp = match micros < 0 {
88            true => pg_epoch() - Duration::from_micros(micros.unsigned_abs()),
89            false => pg_epoch() + Duration::from_micros(micros.unsigned_abs()),
90        };
91
92        Ok(pg_timestamp.into())
93    }
94}
95
96impl FromSql<sql_types::Timestamptz, diesel::pg::Pg> for Timestamp {
97    fn from_sql(bytes: PgValue<'_>) -> diesel::deserialize::Result<Self> {
98        FromSql::<sql_types::Timestamp, diesel::pg::Pg>::from_sql(bytes)
99    }
100}