mall-portrait-common 0.1.1

Common utilities and types for mall portrait projects.
Documentation
use std::collections::HashMap;

use chrono::{FixedOffset, NaiveDate, NaiveDateTime, TimeZone};

pub struct RecordParser<'a> {
    fields: &'a HashMap<String, String>,
}

impl<'a> RecordParser<'a> {
    pub fn new(fields: &'a HashMap<String, String>) -> Self {
        Self { fields }
    }

    pub fn get_string(&self, key: &str) -> Option<String> {
        self.fields.get(key).map(|s| s.trim().to_string())
    }

    pub fn parse_date(&self, key: &str) -> Option<i64> {
        self.fields.get(key).and_then(|s| {
            NaiveDate::parse_from_str(s, "%Y-%m-%d")
                .ok()
                .and_then(|d| d.and_hms_opt(0, 0, 0))
                .and_then(|dt| {
                    FixedOffset::east_opt(8 * 3600)
                        .and_then(|offset| offset.from_local_datetime(&dt).single())
                        .map(|dt| dt.timestamp())
                })
        })
    }

    pub fn parse_datetime(&self, key: &str) -> Option<i64> {
        self.fields.get(key).and_then(|s| {
            NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S")
                .ok()
                .and_then(|dt| {
                    FixedOffset::east_opt(8 * 3600)
                        .and_then(|offset| offset.from_local_datetime(&dt).single())
                        .map(|dt| dt.timestamp())
                })
        })
    }

    pub fn parse_u32(&self, key: &str) -> Option<u32> {
        self.fields.get(key).and_then(|s| s.trim().parse().ok())
    }

    pub fn parse_f64(&self, key: &str) -> Option<f64> {
        self.fields.get(key).and_then(|s| s.trim().parse().ok())
    }

    pub fn calculate_quality_score(&self) -> f64 {
        let total = self.fields.len() as f64;
        if total == 0.0 {
            return 0.0;
        }
        let empty_count = self.fields.values().filter(|v| v.trim().is_empty()).count() as f64;
        (total - empty_count) / total
    }
}