Skip to main content

chainlink/db/
time_entries.rs

1use anyhow::Result;
2use chrono::{DateTime, Utc};
3use rusqlite::params;
4
5use super::{parse_datetime, Database};
6
7impl Database {
8    pub fn start_timer(&self, issue_id: i64) -> Result<i64> {
9        let now = Utc::now().to_rfc3339();
10        self.conn.execute(
11            "INSERT INTO time_entries (issue_id, started_at) VALUES (?1, ?2)",
12            params![issue_id, now],
13        )?;
14        Ok(self.conn.last_insert_rowid())
15    }
16
17    pub fn stop_timer(&self, issue_id: i64) -> Result<bool> {
18        let now = Utc::now();
19        let now_str = now.to_rfc3339();
20
21        let started_at: Option<String> = self
22            .conn
23            .query_row(
24                "SELECT started_at FROM time_entries WHERE issue_id = ?1 AND ended_at IS NULL",
25                [issue_id],
26                |row| row.get(0),
27            )
28            .ok();
29
30        if let Some(started) = started_at {
31            let start_dt = DateTime::parse_from_rfc3339(&started)
32                .map(|dt| dt.with_timezone(&Utc))
33                .unwrap_or(now);
34            let duration = now.signed_duration_since(start_dt).num_seconds();
35
36            let rows = self.conn.execute(
37                "UPDATE time_entries SET ended_at = ?1, duration_seconds = ?2 WHERE issue_id = ?3 AND ended_at IS NULL",
38                params![now_str, duration, issue_id],
39            )?;
40            Ok(rows > 0)
41        } else {
42            Ok(false)
43        }
44    }
45
46    pub fn get_active_timer(&self) -> Result<Option<(i64, DateTime<Utc>)>> {
47        let result: Option<(i64, String)> = self
48            .conn
49            .query_row(
50                "SELECT issue_id, started_at FROM time_entries WHERE ended_at IS NULL ORDER BY id DESC LIMIT 1",
51                [],
52                |row| Ok((row.get(0)?, row.get(1)?)),
53            )
54            .ok();
55
56        Ok(result.map(|(id, started)| (id, parse_datetime(started))))
57    }
58
59    pub fn get_total_time(&self, issue_id: i64) -> Result<i64> {
60        let total: i64 = self
61            .conn
62            .query_row(
63                "SELECT COALESCE(SUM(duration_seconds), 0) FROM time_entries WHERE issue_id = ?1 AND duration_seconds IS NOT NULL",
64                [issue_id],
65                |row| row.get(0),
66            )
67            .unwrap_or(0);
68        Ok(total)
69    }
70}