agentroot_core/db/
content.rs

1//! Content storage operations
2
3use super::Database;
4use crate::error::Result;
5use chrono::Utc;
6use rusqlite::params;
7use sha2::{Digest, Sha256};
8
9/// Hash content using SHA-256
10pub 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
16/// Generate short docid (first 6 chars of hash)
17pub fn docid_from_hash(hash: &str) -> String {
18    hash.chars().take(6).collect()
19}
20
21impl Database {
22    /// Insert content if not exists (content-addressable)
23    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    /// Get content by hash
33    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    /// Delete orphaned content (not referenced by any active document)
47    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}