1use crate::db::{bytes_to_embedding, with_transaction};
7use crate::error::MemoryError;
8use crate::types::Fact;
9use rusqlite::{params, Connection};
10
11pub fn insert_fact_with_fts(
15 conn: &Connection,
16 fact_id: &str,
17 namespace: &str,
18 content: &str,
19 embedding_bytes: &[u8],
20 source: Option<&str>,
21 metadata: Option<&serde_json::Value>,
22) -> Result<(), MemoryError> {
23 insert_fact_with_fts_q8(conn, fact_id, namespace, content, embedding_bytes, None, source, metadata)
24}
25
26#[allow(clippy::too_many_arguments)]
28pub fn insert_fact_with_fts_q8(
29 conn: &Connection,
30 fact_id: &str,
31 namespace: &str,
32 content: &str,
33 embedding_bytes: &[u8],
34 q8_bytes: Option<&[u8]>,
35 source: Option<&str>,
36 metadata: Option<&serde_json::Value>,
37) -> Result<(), MemoryError> {
38 let metadata_str = metadata.map(|m| m.to_string());
39 with_transaction(conn, |tx| {
40 tx.execute(
42 "INSERT INTO facts (id, namespace, content, source, embedding, embedding_q8, metadata) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
43 params![fact_id, namespace, content, source, embedding_bytes, q8_bytes, metadata_str],
44 )?;
45
46 tx.execute(
48 "INSERT INTO facts_rowid_map (fact_id) VALUES (?1)",
49 params![fact_id],
50 )?;
51 let fts_rowid = tx.last_insert_rowid();
52
53 tx.execute(
55 "INSERT INTO facts_fts(rowid, content) VALUES (?1, ?2)",
56 params![fts_rowid, content],
57 )?;
58
59 Ok(())
60 })
61}
62
63pub fn delete_fact_with_fts(conn: &Connection, fact_id: &str) -> Result<(), MemoryError> {
68 with_transaction(conn, |tx| {
69 let fts_rowid: i64 = tx
71 .query_row(
72 "SELECT rowid FROM facts_rowid_map WHERE fact_id = ?1",
73 params![fact_id],
74 |row| row.get(0),
75 )
76 .map_err(|_| MemoryError::FactNotFound(fact_id.to_string()))?;
77
78 let content: String = tx
80 .query_row(
81 "SELECT content FROM facts WHERE id = ?1",
82 params![fact_id],
83 |row| row.get(0),
84 )
85 .map_err(|_| MemoryError::FactNotFound(fact_id.to_string()))?;
86
87 tx.execute(
89 "INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', ?1, ?2)",
90 params![fts_rowid, content],
91 )?;
92
93 tx.execute(
95 "DELETE FROM facts_rowid_map WHERE fact_id = ?1",
96 params![fact_id],
97 )?;
98
99 tx.execute("DELETE FROM facts WHERE id = ?1", params![fact_id])?;
101
102 Ok(())
103 })
104}
105
106pub fn update_fact_with_fts(
110 conn: &Connection,
111 fact_id: &str,
112 new_content: &str,
113 new_embedding_bytes: &[u8],
114) -> Result<(), MemoryError> {
115 with_transaction(conn, |tx| {
116 let (fts_rowid, old_content): (i64, String) = tx
118 .query_row(
119 "SELECT fm.rowid, f.content FROM facts f
120 JOIN facts_rowid_map fm ON fm.fact_id = f.id
121 WHERE f.id = ?1",
122 params![fact_id],
123 |row| Ok((row.get(0)?, row.get(1)?)),
124 )
125 .map_err(|_| MemoryError::FactNotFound(fact_id.to_string()))?;
126
127 tx.execute(
129 "INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', ?1, ?2)",
130 params![fts_rowid, old_content],
131 )?;
132
133 tx.execute(
135 "UPDATE facts SET content = ?1, embedding = ?2, updated_at = datetime('now') WHERE id = ?3",
136 params![new_content, new_embedding_bytes, fact_id],
137 )?;
138
139 tx.execute(
141 "INSERT INTO facts_fts(rowid, content) VALUES (?1, ?2)",
142 params![fts_rowid, new_content],
143 )?;
144
145 Ok(())
146 })
147}
148
149pub fn delete_namespace(conn: &Connection, namespace: &str) -> Result<usize, MemoryError> {
154 with_transaction(conn, |tx| {
155 let mut stmt = tx.prepare(
157 "SELECT f.id, fm.rowid, f.content
158 FROM facts f
159 JOIN facts_rowid_map fm ON fm.fact_id = f.id
160 WHERE f.namespace = ?1",
161 )?;
162 let facts: Vec<(String, i64, String)> = stmt
163 .query_map(params![namespace], |row| {
164 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
165 })?
166 .collect::<Result<Vec<_>, _>>()?;
167
168 let count = facts.len();
169
170 for (fact_id, fts_rowid, content) in &facts {
172 tx.execute(
173 "INSERT INTO facts_fts(facts_fts, rowid, content) VALUES('delete', ?1, ?2)",
174 params![fts_rowid, content],
175 )?;
176 tx.execute(
177 "DELETE FROM facts_rowid_map WHERE fact_id = ?1",
178 params![fact_id],
179 )?;
180 }
181
182 tx.execute(
184 "DELETE FROM facts WHERE namespace = ?1",
185 params![namespace],
186 )?;
187
188 Ok(count)
189 })
190}
191
192pub fn get_fact(conn: &Connection, fact_id: &str) -> Result<Option<Fact>, MemoryError> {
194 let result = conn.query_row(
195 "SELECT id, namespace, content, source, created_at, updated_at, metadata
196 FROM facts WHERE id = ?1",
197 params![fact_id],
198 |row| {
199 let metadata_str: Option<String> = row.get(6)?;
200 Ok(Fact {
201 id: row.get(0)?,
202 namespace: row.get(1)?,
203 content: row.get(2)?,
204 source: row.get(3)?,
205 created_at: row.get(4)?,
206 updated_at: row.get(5)?,
207 metadata: metadata_str.and_then(|s| serde_json::from_str(&s).ok()),
208 })
209 },
210 );
211
212 match result {
213 Ok(fact) => Ok(Some(fact)),
214 Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
215 Err(e) => Err(MemoryError::Database(e)),
216 }
217}
218
219pub fn get_fact_embedding(
221 conn: &Connection,
222 fact_id: &str,
223) -> Result<Option<Vec<f32>>, MemoryError> {
224 let result: Result<Option<Vec<u8>>, _> = conn.query_row(
225 "SELECT embedding FROM facts WHERE id = ?1",
226 params![fact_id],
227 |row| row.get(0),
228 );
229
230 match result {
231 Ok(Some(bytes)) => Ok(Some(bytes_to_embedding(&bytes)?)),
232 Ok(None) => Ok(None),
233 Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
234 Err(e) => Err(MemoryError::Database(e)),
235 }
236}
237
238pub fn list_facts(
240 conn: &Connection,
241 namespace: &str,
242 limit: usize,
243 offset: usize,
244) -> Result<Vec<Fact>, MemoryError> {
245 let mut stmt = conn.prepare(
246 "SELECT id, namespace, content, source, created_at, updated_at, metadata
247 FROM facts
248 WHERE namespace = ?1
249 ORDER BY updated_at DESC
250 LIMIT ?2 OFFSET ?3",
251 )?;
252
253 let facts = stmt
254 .query_map(params![namespace, limit as i64, offset as i64], |row| {
255 let metadata_str: Option<String> = row.get(6)?;
256 Ok(Fact {
257 id: row.get(0)?,
258 namespace: row.get(1)?,
259 content: row.get(2)?,
260 source: row.get(3)?,
261 created_at: row.get(4)?,
262 updated_at: row.get(5)?,
263 metadata: metadata_str.and_then(|s| serde_json::from_str(&s).ok()),
264 })
265 })?
266 .collect::<Result<Vec<_>, _>>()?;
267
268 Ok(facts)
269}