grafbase_sdk/host_io/
cache.rs

1//! A key-value cache shared with all instances of the extension.
2
3use std::time::Duration;
4
5use crate::cbor;
6
7/// Retrieves a value from the cache by key, initializing it if not present.
8///
9/// If the value exists in the cache, the function deserializes and returns it.
10/// If not found, it calls the initialization function, caches the result, and returns it.
11///
12/// # Arguments
13///
14/// * `key` - The cache key to look up
15/// * `init` - Function to initialize the value if not found in cache
16///
17/// # Errors
18///
19/// Returns an error if serialization/deserialization fails or if the init function fails
20pub fn get<F, T>(key: &str, init: F) -> Result<T, Box<dyn std::error::Error>>
21where
22    F: FnOnce() -> Result<CachedItem<T>, Box<dyn std::error::Error>>,
23    T: serde::Serialize + serde::de::DeserializeOwned,
24{
25    let value = crate::wit::Cache::get(key);
26
27    if let Some(value) = value {
28        Ok(cbor::from_slice(&value)?)
29    } else {
30        let value = init()?;
31        let serialized = cbor::to_vec(&value.value)?;
32
33        crate::wit::Cache::set(key, &serialized, value.duration.map(|d| d.as_millis() as u64));
34
35        Ok(value.value)
36    }
37}
38
39/// A value to be stored in the cache with an optional time-to-live duration.
40pub struct CachedItem<T> {
41    value: T,
42    duration: Option<Duration>,
43}
44
45impl<T> CachedItem<T>
46where
47    T: serde::Serialize,
48{
49    /// Creates a new cached item with the given value and optional TTL duration.
50    ///
51    /// # Arguments
52    ///
53    /// * `value` - The value to cache
54    /// * `duration` - Optional time-to-live duration after which the item expires
55    pub fn new(value: T, duration: Option<Duration>) -> Self
56    where
57        T: serde::Serialize,
58    {
59        Self { value, duration }
60    }
61}