1use rusqlite::params;
2
3use super::StateStore;
4use super::types::DriftEvent;
5use crate::errors::Result;
6
7impl StateStore {
8 pub fn record_drift(
10 &self,
11 resource_type: &str,
12 resource_id: &str,
13 expected: Option<&str>,
14 actual: Option<&str>,
15 source: &str,
16 ) -> Result<i64> {
17 let timestamp = crate::utc_now_iso8601();
18 self.conn
19 .execute(
20 "INSERT INTO drift_events (timestamp, resource_type, resource_id, expected, actual, source) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
21 params![timestamp, resource_type, resource_id, expected, actual, source],
22 )
23 ?;
24 Ok(self.conn.last_insert_rowid())
25 }
26
27 pub fn resolve_drift(
29 &self,
30 apply_id: i64,
31 resource_type: &str,
32 resource_id: &str,
33 ) -> Result<()> {
34 self.conn
35 .execute(
36 "UPDATE drift_events SET resolved_by = ?1 WHERE resource_type = ?2 AND resource_id = ?3 AND resolved_by IS NULL",
37 params![apply_id, resource_type, resource_id],
38 )
39 ?;
40 Ok(())
41 }
42
43 pub fn unresolved_drift(&self) -> Result<Vec<DriftEvent>> {
45 let mut stmt = self
46 .conn
47 .prepare(
48 "SELECT id, timestamp, resource_type, resource_id, expected, actual, resolved_by, source FROM drift_events WHERE resolved_by IS NULL ORDER BY timestamp DESC",
49 )
50 ?;
51
52 let events = stmt
53 .query_map([], |row| {
54 Ok(DriftEvent {
55 id: row.get(0)?,
56 timestamp: row.get(1)?,
57 resource_type: row.get(2)?,
58 resource_id: row.get(3)?,
59 expected: row.get(4)?,
60 actual: row.get(5)?,
61 resolved_by: row.get(6)?,
62 source: row.get(7)?,
63 })
64 })?
65 .collect::<std::result::Result<Vec<_>, _>>()?;
66
67 Ok(events)
68 }
69}