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}