1use crate::{Monotonic, Timestamp};
2use sqlx::{
3 Decode, Encode, Postgres, Sqlite, Type,
4 encode::IsNull,
5 error::BoxDynError,
6 postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
7 sqlite::{SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef},
8};
9
10type ResultIsNull = Result<IsNull, Box<(dyn std::error::Error + Send + Sync + 'static)>>;
11
12impl Type<Sqlite> for Timestamp {
15 fn type_info() -> SqliteTypeInfo {
16 <i64 as Type<Sqlite>>::type_info()
17 }
18 fn compatible(ty: &SqliteTypeInfo) -> bool {
19 *ty == <i64 as Type<Sqlite>>::type_info()
20 || *ty == <i32 as Type<Sqlite>>::type_info()
21 || *ty == <i16 as Type<Sqlite>>::type_info()
22 || *ty == <i8 as Type<Sqlite>>::type_info()
23 }
24}
25impl<'q> Encode<'q, Sqlite> for Timestamp {
26 fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> ResultIsNull {
27 args.push(SqliteArgumentValue::Int64(
28 (*self).try_into().expect("timestamp too large"),
29 ));
30 Ok(IsNull::No)
31 }
32}
33impl<'r> Decode<'r, Sqlite> for Timestamp {
34 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
35 let value = <i64 as Decode<Sqlite>>::decode(value)?;
36 Ok(value.try_into()?)
37 }
38}
39
40const J2000_EPOCH_US: i64 = 946_684_800_000_000;
41
42impl Type<Postgres> for Timestamp {
43 fn type_info() -> PgTypeInfo {
44 PgTypeInfo::with_name("TIMESTAMPTZ")
45 }
46 fn compatible(ty: &PgTypeInfo) -> bool {
47 *ty == PgTypeInfo::with_name("TIMESTAMPTZ") || *ty == PgTypeInfo::with_name("TIMESTAMP")
48 }
49}
50
51impl PgHasArrayType for Timestamp {
52 fn array_type_info() -> PgTypeInfo {
53 PgTypeInfo::with_name("_TIMESTAMPTZ")
54 }
55
56 fn array_compatible(ty: &PgTypeInfo) -> bool {
57 *ty == PgTypeInfo::with_name("_TIMESTAMPTZ") || *ty == PgTypeInfo::with_name("_TIMESTAMP")
58 }
59}
60
61impl Encode<'_, Postgres> for Timestamp {
62 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> ResultIsNull {
63 let us = i64::try_from(self.as_micros()).expect("timestamp too large") - J2000_EPOCH_US;
64 Encode::<Postgres>::encode(us, buf)
65 }
66 fn size_hint(&self) -> usize {
67 std::mem::size_of::<i64>()
68 }
69}
70impl<'r> Decode<'r, Postgres> for Timestamp {
71 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
72 let us: i64 = Decode::<Postgres>::decode(value)?;
73 Ok(Timestamp::from_micros((us + J2000_EPOCH_US).try_into()?))
74 }
75}
76
77impl Type<Sqlite> for Monotonic {
80 fn type_info() -> SqliteTypeInfo {
81 <i64 as Type<Sqlite>>::type_info()
82 }
83 fn compatible(ty: &SqliteTypeInfo) -> bool {
84 *ty == <i64 as Type<Sqlite>>::type_info()
85 || *ty == <i32 as Type<Sqlite>>::type_info()
86 || *ty == <i16 as Type<Sqlite>>::type_info()
87 || *ty == <i8 as Type<Sqlite>>::type_info()
88 }
89}
90impl<'q> Encode<'q, Sqlite> for Monotonic {
91 fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> ResultIsNull {
92 args.push(SqliteArgumentValue::Int64(
93 (*self).try_into().expect("timestamp too large"),
94 ));
95 Ok(IsNull::No)
96 }
97}
98impl<'r> Decode<'r, Sqlite> for Monotonic {
99 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
100 let value = <i64 as Decode<Sqlite>>::decode(value)?;
101 Ok(value.try_into()?)
102 }
103}
104
105impl Type<Postgres> for Monotonic {
106 fn type_info() -> PgTypeInfo {
107 PgTypeInfo::with_name("INT8")
108 }
109}
110
111impl PgHasArrayType for Monotonic {
112 fn array_type_info() -> PgTypeInfo {
113 PgTypeInfo::with_name("_INT8")
114 }
115}
116
117impl Encode<'_, Postgres> for Monotonic {
118 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> ResultIsNull {
119 let us = i64::try_from(self.as_nanos()).expect("timestamp too large");
120 Encode::<Postgres>::encode(us, buf)
121 }
122 fn size_hint(&self) -> usize {
123 std::mem::size_of::<i64>()
124 }
125}
126
127impl<'r> Decode<'r, Postgres> for Monotonic {
128 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
129 let ns: i64 = Decode::<Postgres>::decode(value)?;
130 Ok(Monotonic::from_nanos(ns.try_into()?))
131 }
132}