use ocpp_core::DateTime;
use sqlx::encode::IsNull;
use sqlx::error::BoxDynError;
use sqlx::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef};
use sqlx::{Decode, Encode, Postgres, Type};
const PG_EPOCH_OFFSET_MICROS: i64 = 946_684_800_000_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Ts(pub DateTime);
impl From<DateTime> for Ts {
fn from(d: DateTime) -> Self {
Ts(d)
}
}
impl Type<Postgres> for Ts {
fn type_info() -> PgTypeInfo {
PgTypeInfo::with_name("timestamptz")
}
}
impl Encode<'_, Postgres> for Ts {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
buf.extend_from_slice(&(self.0.unix_micros() - PG_EPOCH_OFFSET_MICROS).to_be_bytes());
Ok(IsNull::No)
}
}
impl<'r> Decode<'r, Postgres> for Ts {
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
match value.format() {
PgValueFormat::Binary => {
let b: [u8; 8] = value.as_bytes()?.try_into()?;
Ok(Ts(DateTime::from_unix_micros(
i64::from_be_bytes(b) + PG_EPOCH_OFFSET_MICROS,
)))
}
PgValueFormat::Text => Ok(Ts(DateTime::parse(value.as_str()?)?)),
}
}
}
impl serde::Serialize for Ts {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}
impl<'de> serde::Deserialize<'de> for Ts {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
DateTime::deserialize(d).map(Ts)
}
}