retrom_codegen/
timestamp.rs1use 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 pub fn elapsed_since(&self, earlier: &Timestamp) -> Option<Duration> {
42 let self_duration = Duration::new(self.seconds as u64, self.nanos as u32);
43 let earlier_duration = Duration::new(earlier.seconds as u64, earlier.nanos as u32);
44
45 self_duration.checked_sub(earlier_duration)
46 }
47}
48
49impl TryFrom<Timestamp> for prost_types::Timestamp {
50 type Error = prost::DecodeError;
51
52 fn try_from(value: Timestamp) -> Result<Self, Self::Error> {
53 Ok(prost_types::Timestamp {
54 seconds: value.seconds,
55 nanos: value.nanos,
56 })
57 }
58}
59
60impl From<prost_types::Timestamp> for Timestamp {
61 fn from(value: prost_types::Timestamp) -> Self {
62 Timestamp {
63 seconds: value.seconds,
64 nanos: value.nanos,
65 }
66 }
67}
68
69impl From<std::time::SystemTime> for Timestamp {
70 fn from(time: std::time::SystemTime) -> Self {
71 prost_types::Timestamp::from(time).into()
72 }
73}
74
75impl ToSql<sql_types::Timestamp, diesel::pg::Pg> for Timestamp {
76 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::pg::Pg>) -> diesel::serialize::Result {
77 let thirty_years_seconds = 946_684_800;
78 let micros = (self.seconds - thirty_years_seconds) * 1_000_000 + self.nanos as i64 / 1_000;
79
80 ToSql::<sql_types::BigInt, diesel::pg::Pg>::to_sql(µs, &mut out.reborrow())
81 }
82}
83
84impl ToSql<sql_types::Timestamptz, diesel::pg::Pg> for Timestamp {
85 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, diesel::pg::Pg>) -> diesel::serialize::Result {
86 ToSql::<sql_types::Timestamp, diesel::pg::Pg>::to_sql(self, out)
87 }
88}
89
90impl FromSql<sql_types::Timestamp, diesel::pg::Pg> for Timestamp {
91 fn from_sql(bytes: PgValue<'_>) -> diesel::deserialize::Result<Self> {
92 let micros = i64::from_sql(bytes)?;
93
94 let pg_timestamp = match micros < 0 {
95 true => pg_epoch() - Duration::from_micros(micros.unsigned_abs()),
96 false => pg_epoch() + Duration::from_micros(micros.unsigned_abs()),
97 };
98
99 Ok(pg_timestamp.into())
100 }
101}
102
103impl FromSql<sql_types::Timestamptz, diesel::pg::Pg> for Timestamp {
104 fn from_sql(bytes: PgValue<'_>) -> diesel::deserialize::Result<Self> {
105 FromSql::<sql_types::Timestamp, diesel::pg::Pg>::from_sql(bytes)
106 }
107}