use bytes::BytesMut; use postgres_protocol::types; use std::error::Error; use std::{i32, i64}; use crate::{FromSql, IsNull, ToSql, Type}; /// A wrapper that can be used to represent infinity with `Type::Date` types. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Date { /// Represents `infinity`, a date that is later than all other dates. PosInfinity, /// Represents `-infinity`, a date that is earlier than all other dates. NegInfinity, /// The wrapped date. Value(T), } impl<'a, T: FromSql<'a>> FromSql<'a> for Date { fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { match types::date_from_sql(raw)? { i32::MAX => Ok(Date::PosInfinity), i32::MIN => Ok(Date::NegInfinity), _ => T::from_sql(ty, raw).map(Date::Value), } } fn accepts(ty: &Type) -> bool { *ty == Type::DATE && T::accepts(ty) } } impl ToSql for Date { fn to_sql( &self, ty: &Type, out: &mut BytesMut, ) -> Result> { let value = match *self { Date::PosInfinity => i32::MAX, Date::NegInfinity => i32::MIN, Date::Value(ref v) => return v.to_sql(ty, out), }; types::date_to_sql(value, out); Ok(IsNull::No) } fn accepts(ty: &Type) -> bool { *ty == Type::DATE && T::accepts(ty) } to_sql_checked!(); } /// A wrapper that can be used to represent infinity with `Type::Timestamp` and `Type::Timestamptz` /// types. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Timestamp { /// Represents `infinity`, a timestamp that is later than all other timestamps. PosInfinity, /// Represents `-infinity`, a timestamp that is earlier than all other timestamps. NegInfinity, /// The wrapped timestamp. Value(T), } impl<'a, T: FromSql<'a>> FromSql<'a> for Timestamp { fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { match types::timestamp_from_sql(raw)? { i64::MAX => Ok(Timestamp::PosInfinity), i64::MIN => Ok(Timestamp::NegInfinity), _ => T::from_sql(ty, raw).map(Timestamp::Value), } } fn accepts(ty: &Type) -> bool { match *ty { Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty) => true, _ => false, } } } impl ToSql for Timestamp { fn to_sql( &self, ty: &Type, out: &mut BytesMut, ) -> Result> { let value = match *self { Timestamp::PosInfinity => i64::MAX, Timestamp::NegInfinity => i64::MIN, Timestamp::Value(ref v) => return v.to_sql(ty, out), }; types::timestamp_to_sql(value, out); Ok(IsNull::No) } fn accepts(ty: &Type) -> bool { match *ty { Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty) => true, _ => false, } } to_sql_checked!(); }