use crate::database::redis_util::RedisUtil;
use serde::{Serialize, de::DeserializeOwned};
pub async fn cached_query<T, E, F>(
cache_key: &str,
expiry_seconds: u64,
func: F,
) -> Result<T, E>
where
T: Serialize + DeserializeOwned + Send + Sync + 'static,
E: From<redis::RedisError> + From<serde_json::Error> + Send + 'static,
F: std::future::Future<Output = Result<T, E>> + Send,
{
async fn cached_inner<T, E, F>(
cache_key: &str,
expiry_seconds: u64,
redis_client: &mut RedisUtil,
func: F,
) -> Result<T, E>
where
T: Serialize + DeserializeOwned + Send + Sync + 'static,
E: From<redis::RedisError> + From<serde_json::Error> + Send + 'static,
F: std::future::Future<Output = Result<T, E>> + Send,
{
if let Ok(Some(cached)) = redis_client.get::<Vec<u8>>(cache_key) {
if let Ok(value) = serde_json::from_slice::<T>(&cached) {
tracing::info!("Cache hit for key: {}", cache_key);
return Ok(value);
}
}
let result = func.await;
if let Ok(ref value) = result {
let serialized_value = serde_json::to_vec(value).map_err(E::from)?;
if let Err(err) = redis_client.set_with_expiry(
cache_key,
&serialized_value, expiry_seconds,
) {
tracing::error!("Failed to set cache for key {}: {}", cache_key, err);
}
}
result
}
let mut redis_client = RedisUtil::new().expect("Failed to create Redis client");
cached_inner(cache_key, expiry_seconds, &mut redis_client, func).await
}