Skip to main content

parsentry_cache/
entry.rs

1//! Generic cache entry and metadata
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// A content-addressable cache entry
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CacheEntry {
9    /// Cache format version
10    pub version: String,
11
12    /// SHA256 key identifying this entry
13    pub key: String,
14
15    /// User-defined grouping (replaces agent+model with a single dimension)
16    pub namespace: String,
17
18    /// Cached value (JSON string or raw text)
19    pub value: String,
20
21    /// Metadata for cache management
22    pub metadata: CacheMetadata,
23}
24
25/// Metadata for cache entry management
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct CacheMetadata {
28    /// When this entry was created
29    pub created_at: DateTime<Utc>,
30
31    /// Last time this entry was accessed
32    pub last_accessed: DateTime<Utc>,
33
34    /// Number of times this entry has been accessed
35    pub access_count: usize,
36
37    /// Size of the input that produced this entry, in bytes
38    pub input_size: usize,
39
40    /// Size of the cached value in bytes
41    pub value_size: usize,
42}
43
44impl CacheEntry {
45    /// Create a new cache entry
46    pub fn new(
47        version: String,
48        namespace: String,
49        key: String,
50        value: String,
51        input_size: usize,
52    ) -> Self {
53        let now = Utc::now();
54        let value_size = value.len();
55
56        Self {
57            version,
58            key,
59            namespace,
60            value,
61            metadata: CacheMetadata {
62                created_at: now,
63                last_accessed: now,
64                access_count: 0,
65                input_size,
66                value_size,
67            },
68        }
69    }
70
71    /// Update access metadata
72    pub fn record_access(&mut self) {
73        self.metadata.last_accessed = Utc::now();
74        self.metadata.access_count += 1;
75    }
76
77    /// Get age in days since creation
78    pub fn age_days(&self) -> i64 {
79        let now = Utc::now();
80        (now - self.metadata.created_at).num_days()
81    }
82
83    /// Get idle days since last access
84    pub fn idle_days(&self) -> i64 {
85        let now = Utc::now();
86        (now - self.metadata.last_accessed).num_days()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_cache_entry_creation() {
96        let entry = CacheEntry::new(
97            "1.0.0".to_string(),
98            "my-ns".to_string(),
99            "abc123".to_string(),
100            "test value".to_string(),
101            100,
102        );
103
104        assert_eq!(entry.version, "1.0.0");
105        assert_eq!(entry.namespace, "my-ns");
106        assert_eq!(entry.key, "abc123");
107        assert_eq!(entry.value, "test value");
108        assert_eq!(entry.metadata.access_count, 0);
109        assert_eq!(entry.metadata.input_size, 100);
110        assert_eq!(entry.metadata.value_size, 10);
111    }
112
113    #[test]
114    fn test_record_access() {
115        let mut entry = CacheEntry::new(
116            "1.0.0".to_string(),
117            "ns".to_string(),
118            "abc123".to_string(),
119            "test".to_string(),
120            100,
121        );
122
123        assert_eq!(entry.metadata.access_count, 0);
124
125        entry.record_access();
126        assert_eq!(entry.metadata.access_count, 1);
127
128        entry.record_access();
129        assert_eq!(entry.metadata.access_count, 2);
130    }
131
132    #[test]
133    fn test_idle_days_returns_actual_value() {
134        let mut entry = CacheEntry::new(
135            "1.0.0".to_string(),
136            "ns".to_string(),
137            "abc123".to_string(),
138            "test".to_string(),
139            10,
140        );
141
142        assert_eq!(entry.idle_days(), 0);
143
144        entry.metadata.last_accessed = Utc::now() - chrono::Duration::days(5);
145        assert_eq!(entry.idle_days(), 5);
146
147        entry.metadata.last_accessed = Utc::now() - chrono::Duration::days(100);
148        assert_eq!(entry.idle_days(), 100);
149    }
150
151    #[test]
152    fn test_age_days_returns_actual_value() {
153        let mut entry = CacheEntry::new(
154            "1.0.0".to_string(),
155            "ns".to_string(),
156            "abc123".to_string(),
157            "test".to_string(),
158            10,
159        );
160
161        assert_eq!(entry.age_days(), 0);
162
163        entry.metadata.created_at = Utc::now() - chrono::Duration::days(10);
164        assert_eq!(entry.age_days(), 10);
165    }
166}