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