cache_fn/
cache.rs

1use crate::{client::WorkerClient, error::CacheError, options::CacheOptions};
2use futures::future::BoxFuture;
3use serde::{de::DeserializeOwned, Serialize};
4use std::collections::hash_map::DefaultHasher;
5use std::hash::{Hash, Hasher};
6
7pub struct Cache {
8    client: WorkerClient,
9}
10
11impl Cache {
12    pub fn new(options: CacheOptions) -> Self {
13        Self {
14            client: WorkerClient::new(options),
15        }
16    }
17
18    pub async fn invalidate_by_tag(&self, tags: Vec<String>) -> Result<(), CacheError> {
19        self.client.invalidate_tags(&tags).await
20    }
21
22    pub fn cache<F, Fut, Args, R>(
23        &self,
24        func: F,
25        tags: Vec<String>,
26        options: Option<CacheOptions>,
27    ) -> impl Fn(Args) -> BoxFuture<'static, Result<R, CacheError>>
28    where
29        F: Fn(Args) -> Fut + Clone + Send + 'static,
30        Fut: std::future::Future<Output = R> + Send + 'static,
31        Args: Clone + Serialize + Send + 'static,
32        R: Serialize + DeserializeOwned + Send + Sync + 'static,
33    {
34        let client = self.client.clone();
35        let mut cache_options = options.unwrap_or_default();
36        cache_options.tags = tags;
37
38        move |args: Args| {
39            let func = func.clone();
40            let args_clone = args.clone();
41            let client = client.clone();
42            let options = cache_options.clone();
43
44            Box::pin(async move {
45                let mut hasher = DefaultHasher::new();
46                let args_serialized =
47                    serde_json::to_string(&args_clone).map_err(CacheError::Serialization)?;
48                args_serialized.hash(&mut hasher);
49
50                let key = format!("{:x}", hasher.finish());
51
52                if let Some(cached) = client.get::<R>(&key).await? {
53                    return Ok(cached);
54                }
55
56                let result = func(args).await;
57                let should_cache = options.should_cache.unwrap_or(true);
58                if should_cache {
59                    client.set(&key, &result).await?;
60                }
61
62                Ok(result)
63            })
64        }
65    }
66}