agentroot_core/db/
content.rs1use super::Database;
4use crate::error::Result;
5use chrono::Utc;
6use rusqlite::params;
7use sha2::{Digest, Sha256};
8
9pub fn hash_content(content: &str) -> String {
11 let mut hasher = Sha256::new();
12 hasher.update(content.as_bytes());
13 format!("{:x}", hasher.finalize())
14}
15
16pub fn docid_from_hash(hash: &str) -> String {
18 hash.chars().take(6).collect()
19}
20
21impl Database {
22 pub fn insert_content(&self, hash: &str, content: &str) -> Result<bool> {
24 let now = Utc::now().to_rfc3339();
25 let rows = self.conn.execute(
26 "INSERT OR IGNORE INTO content (hash, doc, created_at) VALUES (?1, ?2, ?3)",
27 params![hash, content, now],
28 )?;
29 Ok(rows > 0)
30 }
31
32 pub fn get_content(&self, hash: &str) -> Result<Option<String>> {
34 let result = self.conn.query_row(
35 "SELECT doc FROM content WHERE hash = ?1",
36 params![hash],
37 |row| row.get(0),
38 );
39 match result {
40 Ok(content) => Ok(Some(content)),
41 Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
42 Err(e) => Err(e.into()),
43 }
44 }
45
46 pub fn cleanup_orphaned_content(&self) -> Result<usize> {
48 let rows = self.conn.execute(
49 "DELETE FROM content WHERE hash NOT IN
50 (SELECT DISTINCT hash FROM documents WHERE active = 1)",
51 [],
52 )?;
53 Ok(rows)
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn test_hash_content() {
63 let hash = hash_content("Hello, World!");
64 assert_eq!(hash.len(), 64);
65 }
66
67 #[test]
68 fn test_docid_from_hash() {
69 let hash = "abcdef1234567890";
70 assert_eq!(docid_from_hash(hash), "abcdef");
71 }
72}