skp_cache/manager/
groups.rs

1use skp_cache_core::{
2    CacheBackend, CacheKey, CacheMetrics, CacheOptions, CacheResult, DependencyBackend,
3    Result, Serializer, TaggableBackend,
4};
5use crate::CacheManager;
6
7/// A logical grouping of cache entries with shared namespace and invalidation
8pub struct CacheGroup<'a, B, S, M>
9where
10    B: CacheBackend + DependencyBackend,
11    S: Serializer,
12    M: CacheMetrics,
13{
14    manager: &'a CacheManager<B, S, M>,
15    namespace: String,
16}
17
18impl<'a, B, S, M> CacheGroup<'a, B, S, M>
19where
20    B: CacheBackend + DependencyBackend,
21    S: Serializer,
22    M: CacheMetrics,
23{
24    pub(crate) fn new(manager: &'a CacheManager<B, S, M>, namespace: String) -> Self {
25        Self { manager, namespace }
26    }
27
28    /// Get the fully qualified key for this group
29    pub fn group_key(&self, key: &str) -> String {
30        format!("{}:{}", self.namespace, key)
31    }
32
33    /// Tag used for invalidation of entire group
34    pub fn group_tag(&self) -> String {
35        format!("group:{}", self.namespace)
36    }
37
38    /// Get a value from the group
39    pub async fn get<T>(&self, key: impl CacheKey) -> Result<CacheResult<T>>
40    where
41        T: serde::de::DeserializeOwned,
42    {
43        // We wrap the key to include namespace
44        let composite_key = self.group_key(&key.full_key());
45        self.manager.get(composite_key).await
46    }
47
48    /// Set a value in the group
49    pub async fn set<T>(
50        &self,
51        key: impl CacheKey,
52        value: T,
53        options: impl Into<CacheOptions>,
54    ) -> Result<()>
55    where
56        T: serde::Serialize,
57    {
58        let composite_key = self.group_key(&key.full_key());
59        let mut opts = options.into();
60        
61        // Auto-add group tag
62        let tag = self.group_tag();
63        opts.tags.push(tag);
64
65        self.manager.set(composite_key, value, opts).await
66    }
67    
68    /// Delete a key from the group
69    pub async fn delete(&self, key: impl CacheKey) -> Result<bool> {
70        let composite_key = self.group_key(&key.full_key());
71        self.manager.delete(composite_key).await
72    }
73}
74
75// Separate impl for TaggableBackend requirements
76impl<'a, B, S, M> CacheGroup<'a, B, S, M>
77where
78    B: CacheBackend + DependencyBackend + TaggableBackend,
79    S: Serializer,
80    M: CacheMetrics,
81{
82    /// Invalidate all entries in this group
83    pub async fn invalidate_all(&self) -> Result<u64> {
84         let tag = self.group_tag();
85         self.manager.delete_by_tag(&tag).await
86    }
87    
88    /// Get all keys in this group
89    pub async fn keys(&self) -> Result<Vec<String>> {
90        let tag = self.group_tag();
91        self.manager.get_keys_by_tag(&tag).await
92    }
93}