1use rusqlite::params;
2
3use crate::sqlite::SqliteGraphStore;
4use crate::store::GraphStore;
5use crate::types::{GraphError, GraphNode};
6
7impl SqliteGraphStore {
8 pub fn load_circuit_breaker(&self) -> Result<Vec<(String, String, u32, bool)>, GraphError> {
10 let mut stmt = self.conn.prepare(
11 "SELECT error_code, hash, consecutive_failures, downgraded FROM circuit_breaker",
12 )?;
13 let rows = stmt
14 .query_map([], |row| {
15 Ok((
16 row.get::<_, String>(0)?,
17 row.get::<_, String>(1)?,
18 row.get::<_, u32>(2)?,
19 row.get::<_, i32>(3)? != 0,
20 ))
21 })?
22 .filter_map(|r| r.ok())
23 .collect();
24 Ok(rows)
25 }
26
27 pub fn save_circuit_breaker(
29 &self,
30 state: &[(String, String, u32, bool)],
31 ) -> Result<(), GraphError> {
32 self.conn.execute("DELETE FROM circuit_breaker", [])?;
33 let mut stmt = self.conn.prepare(
34 "INSERT INTO circuit_breaker (error_code, hash, consecutive_failures, downgraded) \
35 VALUES (?1, ?2, ?3, ?4)",
36 )?;
37 for (code, hash, consecutive, downgraded) in state {
38 stmt.execute(params![code, hash, consecutive, *downgraded as i32])?;
39 }
40 Ok(())
41 }
42
43 pub fn insert_node(&self, node: &GraphNode) -> Result<(), GraphError> {
44 self.conn.execute(
45 "INSERT INTO nodes (id, hash, kind, name, signature, file_path, line_start, line_end, docstring, is_public, type_hints_present, has_docstring, module_id)
46 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
47 ON CONFLICT(hash) DO UPDATE SET
48 kind = excluded.kind,
49 name = excluded.name,
50 signature = excluded.signature,
51 file_path = excluded.file_path,
52 line_start = excluded.line_start,
53 line_end = excluded.line_end,
54 docstring = excluded.docstring,
55 is_public = excluded.is_public,
56 type_hints_present = excluded.type_hints_present,
57 has_docstring = excluded.has_docstring,
58 module_id = excluded.module_id,
59 updated_at = datetime('now')",
60 params![
61 node.id,
62 node.hash,
63 node.kind.as_str(),
64 node.name,
65 node.signature,
66 node.file_path,
67 node.line_start,
68 node.line_end,
69 node.docstring,
70 node.is_public as i32,
71 node.type_hints_present as i32,
72 node.has_docstring as i32,
73 if node.module_id == 0 { None } else { Some(node.module_id) },
74 ],
75 )?;
76
77 self.conn.execute(
80 "DELETE FROM external_endpoints WHERE node_id = ?1",
81 params![node.id],
82 )?;
83 for ep in &node.external_endpoints {
84 self.conn.execute(
85 "INSERT INTO external_endpoints (node_id, kind, method, path, direction) VALUES (?1, ?2, ?3, ?4, ?5)",
86 params![node.id, ep.kind, ep.method, ep.path, ep.direction],
87 )?;
88 }
89
90 for ph in &node.previous_hashes {
92 self.conn.execute(
93 "INSERT OR IGNORE INTO previous_hashes (node_id, hash) VALUES (?1, ?2)",
94 params![node.id, ph],
95 )?;
96 }
97
98 Ok(())
99 }
100
101 pub fn update_node_in_db(&self, node: &GraphNode) -> Result<(), GraphError> {
102 if let Some(old) = self.get_node_by_id(node.id) {
104 if old.hash != node.hash {
105 self.conn.execute(
106 "INSERT OR IGNORE INTO previous_hashes (node_id, hash) VALUES (?1, ?2)",
107 params![node.id, old.hash],
108 )?;
109 self.conn.execute(
111 "DELETE FROM previous_hashes WHERE node_id = ?1 AND hash NOT IN (SELECT hash FROM previous_hashes WHERE node_id = ?1 ORDER BY created_at DESC LIMIT 3)",
112 params![node.id],
113 )?;
114 }
115 }
116
117 self.conn.execute(
118 "UPDATE nodes SET hash = ?1, kind = ?2, name = ?3, signature = ?4, file_path = ?5, line_start = ?6, line_end = ?7, docstring = ?8, is_public = ?9, type_hints_present = ?10, has_docstring = ?11, module_id = ?12, updated_at = datetime('now') WHERE id = ?13",
119 params![
120 node.hash,
121 node.kind.as_str(),
122 node.name,
123 node.signature,
124 node.file_path,
125 node.line_start,
126 node.line_end,
127 node.docstring,
128 node.is_public as i32,
129 node.type_hints_present as i32,
130 node.has_docstring as i32,
131 if node.module_id == 0 { None } else { Some(node.module_id) },
132 node.id,
133 ],
134 )?;
135
136 self.conn
138 .execute("DELETE FROM external_endpoints WHERE node_id = ?1", params![node.id])?;
139 for ep in &node.external_endpoints {
140 self.conn.execute(
141 "INSERT INTO external_endpoints (node_id, kind, method, path, direction) VALUES (?1, ?2, ?3, ?4, ?5)",
142 params![node.id, ep.kind, ep.method, ep.path, ep.direction],
143 )?;
144 }
145
146 Ok(())
147 }
148}