bms_dtos 0.3.3

Common DTOs for communication over network for the BMS Uni project
Documentation
use anyhow::bail;
use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc};
use serde::{Deserialize, Serialize};
use tokio_postgres::Row;

#[derive(Serialize, Deserialize, Debug)]
pub struct TrendDataRaw {
    pub externallogid: i64,
    pub timestamp: String,
    pub timestamp_tzinfo: i64,
    pub value: Option<f64>,
}

#[derive(Debug, Clone)]
pub struct TrendDataDb {
    pub log_id: i64,
    pub timestamp: DateTime<Utc>,
    pub value: Option<f64>
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MetadataJson {
    pub externallogid: i64,
    pub source: String,
    pub unit: String,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct MetadataDb {
    pub log_id: i64,
    pub source: String,
    pub unit: String,
}

impl From<&Row> for MetadataDb {
    fn from(value: &Row) -> MetadataDb {
        let log_id: i64 = value.get("log_id");
        let source: String = value.get("source");
        let unit: String = value.get("unit");

        MetadataDb { log_id, source, unit }
    }
}

impl TryFrom<&TrendDataRaw> for TrendDataDb {
    type Error = anyhow::Error;

    fn try_from(value: &TrendDataRaw) -> Result<Self, Self::Error> {
        let naive_timestamp = NaiveDateTime::parse_from_str(&value.timestamp, "%Y-%m-%d %H:%M:%S");
        if let Err(e) = naive_timestamp {
            let timestamp = &value.timestamp;
            bail!("error parsing {timestamp}: {e}");
        }
        let mut naive_timestamp = naive_timestamp.unwrap();
        match value.timestamp_tzinfo {
            248 => { // CET
                naive_timestamp = naive_timestamp - TimeDelta::hours(1);
            },
            241 => { // CEST
                naive_timestamp = naive_timestamp - TimeDelta::hours(2);
            },
            _ => {
                let timezone = value.timestamp_tzinfo;
                bail!("did not recognize timestamp timezone {timezone}");
            }
        }

        let utc_time: DateTime<Utc> = naive_timestamp.and_local_timezone(Utc).unwrap();

        Ok(TrendDataDb {
            log_id: value.externallogid,
            timestamp: utc_time,
            value: value.value,
        })
    }
}

impl From<&Row> for TrendDataDb {
    fn from(row: &Row) -> TrendDataDb {
        let log_id: i64 = row.get("log_id");
        let timestamp: DateTime<Utc> = row.get("timestamp");
        let value: Option<f64> = row.get("value");

        TrendDataDb {
            log_id,
            timestamp,
            value
        }
    }
}