1use rusqlite::params;
2
3use super::StateStore;
4use super::types::{ModuleFileRecord, ModuleStateRecord};
5use crate::errors::{Result, StateError};
6
7impl StateStore {
8 pub fn upsert_module_state(
10 &self,
11 module_name: &str,
12 last_applied: Option<i64>,
13 packages_hash: &str,
14 files_hash: &str,
15 git_sources: Option<&str>,
16 status: &str,
17 ) -> Result<()> {
18 let now = crate::utc_now_iso8601();
19 self.conn
20 .execute(
21 "INSERT INTO module_state (module_name, installed_at, last_applied, packages_hash, files_hash, git_sources, status)
22 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
23 ON CONFLICT(module_name) DO UPDATE SET
24 last_applied = ?3,
25 packages_hash = ?4,
26 files_hash = ?5,
27 git_sources = ?6,
28 status = ?7",
29 params![module_name, now, last_applied, packages_hash, files_hash, git_sources, status],
30 )
31 ?;
32 Ok(())
33 }
34
35 pub fn module_states(&self) -> Result<Vec<ModuleStateRecord>> {
37 let mut stmt = self
38 .conn
39 .prepare(
40 "SELECT module_name, installed_at, last_applied, packages_hash, files_hash, git_sources, status
41 FROM module_state ORDER BY module_name",
42 )
43 ?;
44
45 let records = stmt
46 .query_map([], |row| {
47 Ok(ModuleStateRecord {
48 module_name: row.get(0)?,
49 installed_at: row.get(1)?,
50 last_applied: row.get(2)?,
51 packages_hash: row.get(3)?,
52 files_hash: row.get(4)?,
53 git_sources: row.get(5)?,
54 status: row.get(6)?,
55 })
56 })?
57 .collect::<std::result::Result<Vec<_>, _>>()?;
58
59 Ok(records)
60 }
61
62 pub fn module_state_by_name(&self, module_name: &str) -> Result<Option<ModuleStateRecord>> {
64 let mut stmt = self
65 .conn
66 .prepare(
67 "SELECT module_name, installed_at, last_applied, packages_hash, files_hash, git_sources, status
68 FROM module_state WHERE module_name = ?1",
69 )
70 ?;
71
72 let mut rows = stmt.query_map(params![module_name], |row| {
73 Ok(ModuleStateRecord {
74 module_name: row.get(0)?,
75 installed_at: row.get(1)?,
76 last_applied: row.get(2)?,
77 packages_hash: row.get(3)?,
78 files_hash: row.get(4)?,
79 git_sources: row.get(5)?,
80 status: row.get(6)?,
81 })
82 })?;
83
84 match rows.next() {
85 Some(Ok(record)) => Ok(Some(record)),
86 Some(Err(e)) => Err(StateError::Database(e.to_string()).into()),
87 None => Ok(None),
88 }
89 }
90
91 pub fn remove_module_state(&self, module_name: &str) -> Result<()> {
93 self.conn.execute(
94 "DELETE FROM module_state WHERE module_name = ?1",
95 params![module_name],
96 )?;
97 Ok(())
98 }
99
100 pub fn upsert_module_file(
102 &self,
103 module_name: &str,
104 file_path: &str,
105 content_hash: &str,
106 strategy: &str,
107 apply_id: i64,
108 ) -> Result<()> {
109 self.conn.execute(
110 "INSERT INTO module_file_manifest (module_name, file_path, content_hash, strategy, last_applied)
111 VALUES (?1, ?2, ?3, ?4, ?5)
112 ON CONFLICT(module_name, file_path) DO UPDATE SET
113 content_hash = excluded.content_hash,
114 strategy = excluded.strategy,
115 last_applied = excluded.last_applied",
116 params![module_name, file_path, content_hash, strategy, apply_id],
117 )?;
118 Ok(())
119 }
120
121 pub fn module_deployed_files(&self, module_name: &str) -> Result<Vec<ModuleFileRecord>> {
123 let mut stmt = self.conn.prepare(
124 "SELECT module_name, file_path, content_hash, strategy, last_applied
125 FROM module_file_manifest WHERE module_name = ?1 ORDER BY file_path",
126 )?;
127
128 let records = stmt
129 .query_map(params![module_name], |row| {
130 Ok(ModuleFileRecord {
131 module_name: row.get(0)?,
132 file_path: row.get(1)?,
133 content_hash: row.get(2)?,
134 strategy: row.get(3)?,
135 last_applied: row.get(4)?,
136 })
137 })?
138 .collect::<std::result::Result<Vec<_>, _>>()?;
139
140 Ok(records)
141 }
142
143 pub fn delete_module_files(&self, module_name: &str) -> Result<()> {
145 self.conn.execute(
146 "DELETE FROM module_file_manifest WHERE module_name = ?1",
147 params![module_name],
148 )?;
149 Ok(())
150 }
151}