xxai_postgres_types/
special.rs

1use bytes::BytesMut;
2use postgres_protocol::types;
3use std::error::Error;
4use std::{i32, i64};
5
6use crate::{FromSql, IsNull, ToSql, Type};
7
8/// A wrapper that can be used to represent infinity with `Type::Date` types.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Date<T> {
11    /// Represents `infinity`, a date that is later than all other dates.
12    PosInfinity,
13    /// Represents `-infinity`, a date that is earlier than all other dates.
14    NegInfinity,
15    /// The wrapped date.
16    Value(T),
17}
18
19impl<'a, T: FromSql<'a>> FromSql<'a> for Date<T> {
20    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
21        match types::date_from_sql(raw)? {
22            i32::MAX => Ok(Date::PosInfinity),
23            i32::MIN => Ok(Date::NegInfinity),
24            _ => T::from_sql(ty, raw).map(Date::Value),
25        }
26    }
27
28    fn accepts(ty: &Type) -> bool {
29        *ty == Type::DATE && T::accepts(ty)
30    }
31}
32
33impl<T: ToSql> ToSql for Date<T> {
34    fn to_sql(
35        &self,
36        ty: &Type,
37        out: &mut BytesMut,
38    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
39        let value = match *self {
40            Date::PosInfinity => i32::MAX,
41            Date::NegInfinity => i32::MIN,
42            Date::Value(ref v) => return v.to_sql(ty, out),
43        };
44
45        types::date_to_sql(value, out);
46        Ok(IsNull::No)
47    }
48
49    fn accepts(ty: &Type) -> bool {
50        *ty == Type::DATE && T::accepts(ty)
51    }
52
53    to_sql_checked!();
54}
55
56/// A wrapper that can be used to represent infinity with `Type::Timestamp` and `Type::Timestamptz`
57/// types.
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum Timestamp<T> {
60    /// Represents `infinity`, a timestamp that is later than all other timestamps.
61    PosInfinity,
62    /// Represents `-infinity`, a timestamp that is earlier than all other timestamps.
63    NegInfinity,
64    /// The wrapped timestamp.
65    Value(T),
66}
67
68impl<'a, T: FromSql<'a>> FromSql<'a> for Timestamp<T> {
69    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
70        match types::timestamp_from_sql(raw)? {
71            i64::MAX => Ok(Timestamp::PosInfinity),
72            i64::MIN => Ok(Timestamp::NegInfinity),
73            _ => T::from_sql(ty, raw).map(Timestamp::Value),
74        }
75    }
76
77    fn accepts(ty: &Type) -> bool {
78        matches!(*ty, Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty))
79    }
80}
81
82impl<T: ToSql> ToSql for Timestamp<T> {
83    fn to_sql(
84        &self,
85        ty: &Type,
86        out: &mut BytesMut,
87    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
88        let value = match *self {
89            Timestamp::PosInfinity => i64::MAX,
90            Timestamp::NegInfinity => i64::MIN,
91            Timestamp::Value(ref v) => return v.to_sql(ty, out),
92        };
93
94        types::timestamp_to_sql(value, out);
95        Ok(IsNull::No)
96    }
97
98    fn accepts(ty: &Type) -> bool {
99        matches!(*ty, Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty))
100    }
101
102    to_sql_checked!();
103}