postgres_types/
special.rs

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