1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::{Monotonic, Timestamp};
use sqlx::{
    encode::IsNull,
    error::BoxDynError,
    postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef},
    sqlite::{SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef},
    Decode, Encode, Postgres, Sqlite, Type,
};

// Timestamp

impl Type<Sqlite> for Timestamp {
    fn type_info() -> SqliteTypeInfo {
        <i64 as Type<Sqlite>>::type_info()
    }
    fn compatible(ty: &SqliteTypeInfo) -> bool {
        *ty == <i64 as Type<Sqlite>>::type_info()
            || *ty == <i32 as Type<Sqlite>>::type_info()
            || *ty == <i16 as Type<Sqlite>>::type_info()
            || *ty == <i8 as Type<Sqlite>>::type_info()
    }
}
impl<'q> Encode<'q, Sqlite> for Timestamp {
    fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> IsNull {
        args.push(SqliteArgumentValue::Int64(
            (*self).try_into().expect("timestamp too large"),
        ));
        IsNull::No
    }
}
impl<'r> Decode<'r, Sqlite> for Timestamp {
    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
        let value = <i64 as Decode<Sqlite>>::decode(value)?;
        Ok(value.try_into()?)
    }
}

const J2000_EPOCH_US: i64 = 946_684_800_000_000;

impl Type<Postgres> for Timestamp {
    fn type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("TIMESTAMPTZ")
    }
    fn compatible(ty: &PgTypeInfo) -> bool {
        *ty == PgTypeInfo::with_name("TIMESTAMPTZ") || *ty == PgTypeInfo::with_name("TIMESTAMP")
    }
}

impl PgHasArrayType for Timestamp {
    fn array_type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("_TIMESTAMPTZ")
    }

    fn array_compatible(ty: &PgTypeInfo) -> bool {
        *ty == PgTypeInfo::with_name("_TIMESTAMPTZ") || *ty == PgTypeInfo::with_name("_TIMESTAMP")
    }
}

impl Encode<'_, Postgres> for Timestamp {
    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
        let us = i64::try_from(self.as_micros()).expect("timestamp too large") - J2000_EPOCH_US;
        Encode::<Postgres>::encode(us, buf)
    }
    fn size_hint(&self) -> usize {
        std::mem::size_of::<i64>()
    }
}
impl<'r> Decode<'r, Postgres> for Timestamp {
    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
        let us: i64 = Decode::<Postgres>::decode(value)?;
        Ok(Timestamp::from_micros((us + J2000_EPOCH_US).try_into()?))
    }
}

// Monotonic

impl Type<Sqlite> for Monotonic {
    fn type_info() -> SqliteTypeInfo {
        <i64 as Type<Sqlite>>::type_info()
    }
    fn compatible(ty: &SqliteTypeInfo) -> bool {
        *ty == <i64 as Type<Sqlite>>::type_info()
            || *ty == <i32 as Type<Sqlite>>::type_info()
            || *ty == <i16 as Type<Sqlite>>::type_info()
            || *ty == <i8 as Type<Sqlite>>::type_info()
    }
}
impl<'q> Encode<'q, Sqlite> for Monotonic {
    fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> IsNull {
        args.push(SqliteArgumentValue::Int64(
            (*self).try_into().expect("timestamp too large"),
        ));
        IsNull::No
    }
}
impl<'r> Decode<'r, Sqlite> for Monotonic {
    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
        let value = <i64 as Decode<Sqlite>>::decode(value)?;
        Ok(value.try_into()?)
    }
}

impl Type<Postgres> for Monotonic {
    fn type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("INT8")
    }
}

impl PgHasArrayType for Monotonic {
    fn array_type_info() -> PgTypeInfo {
        PgTypeInfo::with_name("_INT8")
    }
}

impl Encode<'_, Postgres> for Monotonic {
    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
        let us = i64::try_from(self.as_nanos()).expect("timestamp too large");
        Encode::<Postgres>::encode(us, buf)
    }
    fn size_hint(&self) -> usize {
        std::mem::size_of::<i64>()
    }
}

impl<'r> Decode<'r, Postgres> for Monotonic {
    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
        let ns: i64 = Decode::<Postgres>::decode(value)?;
        Ok(Monotonic::from_nanos(ns.try_into()?))
    }
}