use crate::{Cache, CheckValue, Result};
use std::time::Duration;
use std::future::Future;
pub struct CachifiedOptions<T, F, C>
where
T: Clone + Send + Sync + 'static,
C: Cache<T> + Clone,
{
pub cache: C,
pub key: String,
pub ttl: Option<Duration>,
pub stale_while_revalidate: Option<Duration>,
pub force_fresh: bool,
pub fallback_to_cache: bool,
pub check_value: Option<Box<dyn CheckValue<T> + Send + Sync>>,
pub get_fresh_value: F,
}
pub struct CachifiedOptionsBuilder<T, C>
where
T: Clone + Send + Sync + 'static,
C: Cache<T> + Clone,
{
cache: C,
key: String,
ttl: Option<Duration>,
stale_while_revalidate: Option<Duration>,
force_fresh: bool,
fallback_to_cache: bool,
check_value: Option<Box<dyn CheckValue<T> + Send + Sync>>,
}
impl<T, C> CachifiedOptionsBuilder<T, C>
where
T: Clone + Send + Sync + 'static,
C: Cache<T> + Clone,
{
pub fn new(cache: C, key: impl Into<String>) -> Self {
Self {
cache,
key: key.into(),
ttl: None,
stale_while_revalidate: None,
force_fresh: false,
fallback_to_cache: false,
check_value: None,
}
}
pub fn ttl(mut self, ttl: Duration) -> Self {
self.ttl = Some(ttl);
self
}
pub fn stale_while_revalidate(mut self, duration: Duration) -> Self {
self.stale_while_revalidate = Some(duration);
self
}
pub fn force_fresh(mut self, force: bool) -> Self {
self.force_fresh = force;
self
}
pub fn fallback_to_cache(mut self, fallback: bool) -> Self {
self.fallback_to_cache = fallback;
self
}
pub fn check_value<V>(mut self, validator: V) -> Self
where
V: CheckValue<T> + Send + Sync + 'static,
{
self.check_value = Some(Box::new(validator));
self
}
pub fn get_fresh_value<F, Fut>(self, get_fresh_value: F) -> CachifiedOptions<T, F, C>
where
F: Fn() -> Fut + Send + Sync,
Fut: Future<Output = Result<T>> + Send,
{
CachifiedOptions {
cache: self.cache,
key: self.key,
ttl: self.ttl,
stale_while_revalidate: self.stale_while_revalidate,
force_fresh: self.force_fresh,
fallback_to_cache: self.fallback_to_cache,
check_value: self.check_value,
get_fresh_value,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{MokaCache, validation::NonNullValidator};
#[tokio::test]
async fn test_cachified_options_builder() {
let cache = MokaCache::new(100);
let options = CachifiedOptionsBuilder::new(cache, "test-key")
.ttl(Duration::from_secs(300))
.stale_while_revalidate(Duration::from_secs(60))
.force_fresh(false)
.fallback_to_cache(true)
.check_value(NonNullValidator)
.get_fresh_value(|| async { Ok(Some("test".to_string())) });
assert_eq!(options.key, "test-key");
assert_eq!(options.ttl, Some(Duration::from_secs(300)));
assert_eq!(options.stale_while_revalidate, Some(Duration::from_secs(60)));
assert!(!options.force_fresh);
assert!(options.fallback_to_cache);
assert!(options.check_value.is_some());
}
#[tokio::test]
async fn test_cachified_options_builder_minimal() {
let cache = MokaCache::new(100);
let options = CachifiedOptionsBuilder::new(cache, "test-key")
.get_fresh_value(|| async { Ok("test".to_string()) });
assert_eq!(options.key, "test-key");
assert_eq!(options.ttl, None);
assert_eq!(options.stale_while_revalidate, None);
assert!(!options.force_fresh);
assert!(!options.fallback_to_cache);
assert!(options.check_value.is_none());
}
}