proof_of_sql/base/posql_time/
unit.rs

1use super::PoSQLTimestampError;
2use core::fmt;
3use serde::{Deserialize, Serialize};
4
5/// An intermediate type representing the time units from a parsed query
6#[derive(Debug, Clone, Copy, Hash, Serialize, Deserialize, PartialEq, Eq)]
7pub enum PoSQLTimeUnit {
8    /// Represents seconds with precision 0: ex "2024-06-20 12:34:56"
9    Second,
10    /// Represents milliseconds with precision 3: ex "2024-06-20 12:34:56.123"
11    Millisecond,
12    /// Represents microseconds with precision 6: ex "2024-06-20 12:34:56.123456"
13    Microsecond,
14    /// Represents nanoseconds with precision 9: ex "2024-06-20 12:34:56.123456789"
15    Nanosecond,
16}
17
18impl From<PoSQLTimeUnit> for u64 {
19    fn from(value: PoSQLTimeUnit) -> u64 {
20        match value {
21            PoSQLTimeUnit::Second => 0,
22            PoSQLTimeUnit::Millisecond => 3,
23            PoSQLTimeUnit::Microsecond => 6,
24            PoSQLTimeUnit::Nanosecond => 9,
25        }
26    }
27}
28
29impl From<proof_of_sql_parser::posql_time::PoSQLTimeUnit> for PoSQLTimeUnit {
30    fn from(value: proof_of_sql_parser::posql_time::PoSQLTimeUnit) -> Self {
31        match value {
32            proof_of_sql_parser::posql_time::PoSQLTimeUnit::Second => PoSQLTimeUnit::Second,
33            proof_of_sql_parser::posql_time::PoSQLTimeUnit::Millisecond => {
34                PoSQLTimeUnit::Millisecond
35            }
36            proof_of_sql_parser::posql_time::PoSQLTimeUnit::Microsecond => {
37                PoSQLTimeUnit::Microsecond
38            }
39            proof_of_sql_parser::posql_time::PoSQLTimeUnit::Nanosecond => PoSQLTimeUnit::Nanosecond,
40        }
41    }
42}
43
44impl TryFrom<&str> for PoSQLTimeUnit {
45    type Error = PoSQLTimestampError;
46    fn try_from(value: &str) -> Result<Self, PoSQLTimestampError> {
47        match value {
48            "0" => Ok(PoSQLTimeUnit::Second),
49            "3" => Ok(PoSQLTimeUnit::Millisecond),
50            "6" => Ok(PoSQLTimeUnit::Microsecond),
51            "9" => Ok(PoSQLTimeUnit::Nanosecond),
52            _ => Err(PoSQLTimestampError::UnsupportedPrecision {
53                error: value.into(),
54            }),
55        }
56    }
57}
58
59impl fmt::Display for PoSQLTimeUnit {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            PoSQLTimeUnit::Second => write!(f, "seconds (precision: 0)"),
63            PoSQLTimeUnit::Millisecond => write!(f, "milliseconds (precision: 3)"),
64            PoSQLTimeUnit::Microsecond => write!(f, "microseconds (precision: 6)"),
65            PoSQLTimeUnit::Nanosecond => write!(f, "nanoseconds (precision: 9)"),
66        }
67    }
68}
69
70// expect(deprecated) for the sole purpose of testing that
71// timestamp precision is parsed correctly.
72#[cfg(test)]
73#[expect(clippy::missing_panics_doc)]
74mod time_unit_tests {
75    use super::*;
76    use crate::base::posql_time::PoSQLTimestampError;
77
78    #[test]
79    fn test_valid_precisions() {
80        assert_eq!(PoSQLTimeUnit::try_from("0"), Ok(PoSQLTimeUnit::Second));
81        assert_eq!(PoSQLTimeUnit::try_from("3"), Ok(PoSQLTimeUnit::Millisecond));
82        assert_eq!(PoSQLTimeUnit::try_from("6"), Ok(PoSQLTimeUnit::Microsecond));
83        assert_eq!(PoSQLTimeUnit::try_from("9"), Ok(PoSQLTimeUnit::Nanosecond));
84    }
85
86    #[test]
87    fn test_invalid_precision() {
88        let invalid_precisions = [
89            "1", "2", "4", "5", "7", "8", "10", "zero", "three", "cat", "-1", "-2",
90        ]; // Testing all your various invalid inputs
91        for &value in &invalid_precisions {
92            let result = PoSQLTimeUnit::try_from(value);
93            assert!(matches!(
94                result,
95                Err(PoSQLTimestampError::UnsupportedPrecision { .. })
96            ));
97        }
98    }
99}