Skip to main content

vantage_sql/primitives/
interval.rs

1use vantage_expressions::{Expression, Expressive};
2
3/// Vendor-aware time interval literal.
4///
5/// Renders as:
6/// - **PostgreSQL:** `INTERVAL '1 year'`
7/// - **MySQL:**      `INTERVAL 1 YEAR`
8/// - **SQLite:**     `1` (numeric days — caller must convert units)
9///
10/// # Examples
11///
12/// ```ignore
13/// use vantage_sql::primitives::interval::Interval;
14///
15/// Interval::new(1, "year")
16/// Interval::new(6, "month")
17/// Interval::new(30, "day")
18/// ```
19#[derive(Debug, Clone)]
20pub struct Interval {
21    amount: i64,
22    unit: String,
23}
24
25impl Interval {
26    pub fn new(amount: i64, unit: impl Into<String>) -> Self {
27        Self {
28            amount,
29            unit: unit.into().to_lowercase(),
30        }
31    }
32
33    /// Convert to approximate days for SQLite (which has no INTERVAL type).
34    #[cfg(feature = "sqlite")]
35    fn to_days(&self) -> i64 {
36        match self.unit.as_str() {
37            "year" | "years" => self.amount * 365,
38            "month" | "months" => self.amount * 30,
39            "week" | "weeks" => self.amount * 7,
40            "day" | "days" => self.amount,
41            "hour" | "hours" => (self.amount as f64 / 24.0).round() as i64,
42            _ => self.amount,
43        }
44    }
45}
46
47// -- SQLite: numeric days (approximate) --------------------------------------
48
49#[cfg(feature = "sqlite")]
50impl Expressive<crate::sqlite::types::AnySqliteType> for Interval {
51    fn expr(&self) -> Expression<crate::sqlite::types::AnySqliteType> {
52        Expression::new(format!("{}", self.to_days()), vec![])
53    }
54}
55
56// -- MySQL: INTERVAL 1 YEAR -------------------------------------------------
57
58#[cfg(feature = "mysql")]
59impl Expressive<crate::mysql::types::AnyMysqlType> for Interval {
60    fn expr(&self) -> Expression<crate::mysql::types::AnyMysqlType> {
61        Expression::new(
62            format!("INTERVAL {} {}", self.amount, self.unit.to_uppercase()),
63            vec![],
64        )
65    }
66}
67
68// -- PostgreSQL: INTERVAL '1 year' ------------------------------------------
69
70#[cfg(feature = "postgres")]
71impl Expressive<crate::postgres::types::AnyPostgresType> for Interval {
72    fn expr(&self) -> Expression<crate::postgres::types::AnyPostgresType> {
73        Expression::new(format!("INTERVAL '{} {}'", self.amount, self.unit), vec![])
74    }
75}