use anyhow::Result;
use std::sync::Arc;
use super::stats::CachePreloader;
use super::ThingsCache;
pub struct DefaultPreloader {
cache: std::sync::Weak<ThingsCache>,
db: Arc<crate::database::ThingsDatabase>,
}
impl DefaultPreloader {
#[must_use]
pub fn new(cache: &Arc<ThingsCache>, db: Arc<crate::database::ThingsDatabase>) -> Arc<Self> {
Arc::new(Self {
cache: Arc::downgrade(cache),
db,
})
}
}
impl CachePreloader for DefaultPreloader {
fn predict(&self, accessed_key: &str) -> Vec<(String, u32)> {
match accessed_key {
"inbox:all" => vec![("today:all".to_string(), 8)],
"today:all" => vec![("inbox:all".to_string(), 10)],
"areas:all" => vec![("projects:all".to_string(), 7)],
_ => vec![],
}
}
fn warm(&self, key: &str) {
let Some(cache) = self.cache.upgrade() else {
return;
};
let db = Arc::clone(&self.db);
let key = key.to_string();
tokio::spawn(async move {
let result: Result<()> = match key.as_str() {
"inbox:all" => cache
.get_tasks(&key, || async {
db.get_inbox(None).await.map_err(anyhow::Error::from)
})
.await
.map(|_| ()),
"today:all" => cache
.get_tasks(&key, || async {
db.get_today(None).await.map_err(anyhow::Error::from)
})
.await
.map(|_| ()),
"areas:all" => cache
.get_areas(&key, || async {
db.get_areas().await.map_err(anyhow::Error::from)
})
.await
.map(|_| ()),
"projects:all" => cache
.get_projects(&key, || async {
db.get_projects(None).await.map_err(anyhow::Error::from)
})
.await
.map(|_| ()),
_ => Ok(()),
};
if let Err(e) = result {
tracing::warn!("DefaultPreloader::warm({key}) failed: {e}");
}
});
}
}
pub mod keys {
#[must_use]
pub fn inbox(limit: Option<usize>) -> String {
format!(
"inbox:{}",
limit.map_or("all".to_string(), |l| l.to_string())
)
}
#[must_use]
pub fn today(limit: Option<usize>) -> String {
format!(
"today:{}",
limit.map_or("all".to_string(), |l| l.to_string())
)
}
#[must_use]
pub fn projects(area_uuid: Option<&str>) -> String {
format!("projects:{}", area_uuid.unwrap_or("all"))
}
#[must_use]
pub fn areas() -> String {
"areas:all".to_string()
}
#[must_use]
pub fn search(query: &str, limit: Option<usize>) -> String {
format!(
"search:{}:{}",
query,
limit.map_or("all".to_string(), |l| l.to_string())
)
}
}