things3_core/cache/
preloader.rs1use anyhow::Result;
2use std::sync::Arc;
3
4use super::stats::CachePreloader;
5use super::ThingsCache;
6
7pub struct DefaultPreloader {
31 cache: std::sync::Weak<ThingsCache>,
32 db: Arc<crate::database::ThingsDatabase>,
33}
34
35impl DefaultPreloader {
36 #[must_use]
40 pub fn new(cache: &Arc<ThingsCache>, db: Arc<crate::database::ThingsDatabase>) -> Arc<Self> {
41 Arc::new(Self {
42 cache: Arc::downgrade(cache),
43 db,
44 })
45 }
46}
47
48impl CachePreloader for DefaultPreloader {
49 fn predict(&self, accessed_key: &str) -> Vec<(String, u32)> {
50 match accessed_key {
51 "inbox:all" => vec![("today:all".to_string(), 8)],
52 "today:all" => vec![("inbox:all".to_string(), 10)],
53 "areas:all" => vec![("projects:all".to_string(), 7)],
54 _ => vec![],
55 }
56 }
57
58 fn warm(&self, key: &str) {
59 let Some(cache) = self.cache.upgrade() else {
60 return;
61 };
62 let db = Arc::clone(&self.db);
63 let key = key.to_string();
64 tokio::spawn(async move {
65 let result: Result<()> = match key.as_str() {
66 "inbox:all" => cache
67 .get_tasks(&key, || async {
68 db.get_inbox(None).await.map_err(anyhow::Error::from)
69 })
70 .await
71 .map(|_| ()),
72 "today:all" => cache
73 .get_tasks(&key, || async {
74 db.get_today(None).await.map_err(anyhow::Error::from)
75 })
76 .await
77 .map(|_| ()),
78 "areas:all" => cache
79 .get_areas(&key, || async {
80 db.get_areas().await.map_err(anyhow::Error::from)
81 })
82 .await
83 .map(|_| ()),
84 "projects:all" => cache
85 .get_projects(&key, || async {
86 db.get_projects(None).await.map_err(anyhow::Error::from)
87 })
88 .await
89 .map(|_| ()),
90 _ => Ok(()),
91 };
92 if let Err(e) = result {
93 tracing::warn!("DefaultPreloader::warm({key}) failed: {e}");
94 }
95 });
96 }
97}
98
99pub mod keys {
101 #[must_use]
103 pub fn inbox(limit: Option<usize>) -> String {
104 format!(
105 "inbox:{}",
106 limit.map_or("all".to_string(), |l| l.to_string())
107 )
108 }
109
110 #[must_use]
112 pub fn today(limit: Option<usize>) -> String {
113 format!(
114 "today:{}",
115 limit.map_or("all".to_string(), |l| l.to_string())
116 )
117 }
118
119 #[must_use]
121 pub fn projects(area_uuid: Option<&str>) -> String {
122 format!("projects:{}", area_uuid.unwrap_or("all"))
123 }
124
125 #[must_use]
127 pub fn areas() -> String {
128 "areas:all".to_string()
129 }
130
131 #[must_use]
133 pub fn search(query: &str, limit: Option<usize>) -> String {
134 format!(
135 "search:{}:{}",
136 query,
137 limit.map_or("all".to_string(), |l| l.to_string())
138 )
139 }
140}