use std::time::Duration;
use hydracache::{CacheKeyBuilder, CacheOptions, RefreshOptions, TagSet};
use crate::CacheEntity;
const SHORT_LIVED_TTL: Duration = Duration::from_secs(30);
const READ_MOSTLY_TTL: Duration = Duration::from_secs(300);
const PER_ENTITY_TTL: Duration = Duration::from_secs(300);
const NEGATIVE_CACHE_TTL: Duration = Duration::from_secs(30);
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct QueryCachePolicy {
name: Option<String>,
key: Option<String>,
tags: TagSet,
ttl: Option<Duration>,
refresh: Option<RefreshOptions>,
}
impl QueryCachePolicy {
pub fn new() -> Self {
Self::default()
}
pub fn short_lived() -> Self {
Self::new().ttl(SHORT_LIVED_TTL)
}
pub fn read_mostly() -> Self {
Self::new().ttl(READ_MOSTLY_TTL)
}
pub fn per_entity() -> Self {
Self::new().ttl(PER_ENTITY_TTL)
}
pub fn no_ttl_explicit_invalidation() -> Self {
Self::new()
}
pub fn negative_cache() -> Self {
Self::new().ttl(NEGATIVE_CACHE_TTL)
}
pub fn named(name: impl Into<String>) -> Self {
Self::new().with_name(name)
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
pub fn key_value(&self) -> Option<&str> {
self.key.as_deref()
}
pub fn tags_value(&self) -> &[String] {
self.tags.as_slice()
}
pub fn ttl_value(&self) -> Option<Duration> {
self.ttl
}
pub fn refresh_policy_value(&self) -> Option<RefreshOptions> {
self.refresh
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
pub fn key_builder(self, key: CacheKeyBuilder) -> Self {
self.key(key.build_string())
}
pub fn for_entity(mut self, kind: impl ToString, id: impl ToString) -> Self {
let key = entity_key(kind, id);
self.key = Some(key.clone());
self.tags = self.tags.tag(key);
self
}
pub fn for_cache_entity<T>(mut self, id: T::Id) -> Self
where
T: CacheEntity,
{
let key = T::cache_key_for(&id);
self.key = Some(key);
self.tags = self.tags.tag(T::entity_tag_for(&id));
self.tags = append_optional_tag(self.tags, T::collection_tag());
self
}
pub fn collection(mut self, name: impl ToString) -> Self {
let tag = collection_tag(name);
self.key = Some(tag.clone());
self.tags = self.tags.tag(tag);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.tags = self.tags.tag(tag);
self
}
pub fn collection_tag(mut self, name: impl ToString) -> Self {
self.tags = self.tags.tag(collection_tag(name));
self
}
pub fn tags<I, S>(mut self, tags: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.tags = self.tags.tags(tags);
self
}
pub fn tag_set(mut self, tags: TagSet) -> Self {
self.tags = tags;
self
}
pub fn ttl(mut self, ttl: Duration) -> Self {
self.ttl = Some(ttl);
self
}
pub fn refresh_policy(mut self, refresh: RefreshOptions) -> Self {
self.refresh = Some(refresh);
self
}
pub(crate) fn cache_options(&self) -> CacheOptions {
let mut options = CacheOptions::new().tag_set(self.tags.clone());
if let Some(ttl) = self.ttl {
options = options.ttl(ttl);
}
options
}
}
pub(crate) fn entity_key(kind: impl ToString, id: impl ToString) -> String {
CacheKeyBuilder::new().entity(kind, id).build_string()
}
pub(crate) fn collection_tag(name: impl ToString) -> String {
CacheKeyBuilder::from_segment(name).build_string()
}
fn append_optional_tag(tags: TagSet, tag: Option<String>) -> TagSet {
match tag {
Some(tag) => tags.tag(tag),
None => tags,
}
}