Skip to main content

entrenar/storage/sqlite/
artifacts.rs

1//! Artifact operations for SQLite Backend.
2//!
3//! Contains artifact retrieval and listing methods.
4
5use super::backend::SqliteBackend;
6use super::types::ArtifactRef;
7use crate::storage::{Result, StorageError};
8use chrono::Utc;
9use rusqlite::params;
10
11impl SqliteBackend {
12    /// Get artifact data by SHA-256 hash
13    pub fn get_artifact_data(&self, sha256: &str) -> Result<Vec<u8>> {
14        let conn = self.lock_conn()?;
15
16        let data: Vec<u8> = conn
17            .query_row("SELECT data FROM artifacts WHERE sha256 = ?1 LIMIT 1", [sha256], |row| {
18                row.get(0)
19            })
20            .map_err(|e| match e {
21                rusqlite::Error::QueryReturnedNoRows => {
22                    StorageError::Backend(format!("Artifact not found: {sha256}"))
23                }
24                _ => StorageError::Backend(format!("Failed to get artifact data: {e}")),
25            })?;
26
27        Ok(data)
28    }
29
30    /// List artifacts for a run
31    pub fn list_artifacts(&self, run_id: &str) -> Result<Vec<ArtifactRef>> {
32        let conn = self.lock_conn()?;
33
34        // Verify run exists
35        let exists: bool = conn
36            .query_row("SELECT EXISTS(SELECT 1 FROM runs WHERE id = ?1)", [run_id], |row| {
37                row.get(0)
38            })
39            .map_err(|e| StorageError::Backend(format!("Failed to check run: {e}")))?;
40
41        if !exists {
42            return Err(StorageError::RunNotFound(run_id.to_string()));
43        }
44
45        let mut stmt = conn
46            .prepare(
47                "SELECT id, run_id, path, size_bytes, sha256, created_at FROM artifacts WHERE run_id = ?1 ORDER BY created_at",
48            )
49            .map_err(|e| StorageError::Backend(format!("Failed to prepare query: {e}")))?;
50
51        let rows = stmt
52            .query_map(params![run_id], |row| {
53                let id: String = row.get(0)?;
54                let run_id: String = row.get(1)?;
55                let path: String = row.get(2)?;
56                let size_bytes: i64 = row.get(3)?;
57                let sha256: String = row.get(4)?;
58                let created_str: String = row.get(5)?;
59                Ok((id, run_id, path, size_bytes, sha256, created_str))
60            })
61            .map_err(|e| StorageError::Backend(format!("Failed to query artifacts: {e}")))?;
62
63        let mut result = Vec::new();
64        for row in rows {
65            let (id, run_id, path, size_bytes, sha256, created_str) = row
66                .map_err(|e| StorageError::Backend(format!("Failed to read artifact row: {e}")))?;
67            let created_at = created_str.parse().unwrap_or_else(|_| Utc::now());
68            result.push(ArtifactRef {
69                id,
70                run_id,
71                path,
72                size_bytes: size_bytes as u64,
73                sha256,
74                created_at,
75            });
76        }
77
78        Ok(result)
79    }
80}