prax_query/data_cache/
options.rs1use std::time::Duration;
4
5use super::invalidation::EntityTag;
6
7#[derive(Debug, Clone)]
9pub struct CacheOptions {
10 pub ttl: Option<Duration>,
12 pub policy: CachePolicy,
14 pub write_policy: WritePolicy,
16 pub tags: Vec<EntityTag>,
18 pub max_size: Option<usize>,
20 pub cache_empty: bool,
22 pub bypass: bool,
24 pub stale_while_revalidate: Option<Duration>,
26}
27
28impl Default for CacheOptions {
29 fn default() -> Self {
30 Self {
31 ttl: Some(Duration::from_secs(300)), policy: CachePolicy::CacheFirst,
33 write_policy: WritePolicy::WriteThrough,
34 tags: Vec::new(),
35 max_size: Some(1024 * 1024), cache_empty: true,
37 bypass: false,
38 stale_while_revalidate: None,
39 }
40 }
41}
42
43impl CacheOptions {
44 pub fn ttl(duration: Duration) -> Self {
46 Self {
47 ttl: Some(duration),
48 ..Default::default()
49 }
50 }
51
52 pub fn no_expire() -> Self {
54 Self {
55 ttl: None,
56 ..Default::default()
57 }
58 }
59
60 pub fn bypass() -> Self {
62 Self {
63 bypass: true,
64 ..Default::default()
65 }
66 }
67
68 pub fn with_ttl(mut self, duration: Duration) -> Self {
70 self.ttl = Some(duration);
71 self
72 }
73
74 pub fn with_policy(mut self, policy: CachePolicy) -> Self {
76 self.policy = policy;
77 self
78 }
79
80 pub fn with_write_policy(mut self, policy: WritePolicy) -> Self {
82 self.write_policy = policy;
83 self
84 }
85
86 pub fn with_tag(mut self, tag: impl Into<EntityTag>) -> Self {
88 self.tags.push(tag.into());
89 self
90 }
91
92 pub fn with_tags(mut self, tags: impl IntoIterator<Item = EntityTag>) -> Self {
94 self.tags.extend(tags);
95 self
96 }
97
98 pub fn with_max_size(mut self, size: usize) -> Self {
100 self.max_size = Some(size);
101 self
102 }
103
104 pub fn no_size_limit(mut self) -> Self {
106 self.max_size = None;
107 self
108 }
109
110 pub fn no_cache_empty(mut self) -> Self {
112 self.cache_empty = false;
113 self
114 }
115
116 pub fn stale_while_revalidate(mut self, duration: Duration) -> Self {
118 self.stale_while_revalidate = Some(duration);
119 self
120 }
121
122 pub fn short() -> Self {
124 Self::ttl(Duration::from_secs(60))
125 }
126
127 pub fn medium() -> Self {
129 Self::ttl(Duration::from_secs(300))
130 }
131
132 pub fn long() -> Self {
134 Self::ttl(Duration::from_secs(3600))
135 }
136
137 pub fn daily() -> Self {
139 Self::ttl(Duration::from_secs(86400))
140 }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
145pub enum CachePolicy {
146 #[default]
148 CacheFirst,
149
150 NetworkFirst,
152
153 CacheOnly,
155
156 NetworkOnly,
158
159 StaleWhileRevalidate,
161}
162
163impl CachePolicy {
164 pub fn should_check_cache(&self) -> bool {
166 matches!(
167 self,
168 Self::CacheFirst | Self::CacheOnly | Self::StaleWhileRevalidate
169 )
170 }
171
172 pub fn should_fetch(&self) -> bool {
174 matches!(
175 self,
176 Self::CacheFirst | Self::NetworkFirst | Self::NetworkOnly | Self::StaleWhileRevalidate
177 )
178 }
179
180 pub fn should_update_cache(&self) -> bool {
182 matches!(
183 self,
184 Self::CacheFirst | Self::NetworkFirst | Self::StaleWhileRevalidate
185 )
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
191pub enum WritePolicy {
192 #[default]
194 WriteThrough,
195
196 WriteBack,
198
199 WriteDelayed,
201}
202
203pub mod presets {
205 use super::*;
206
207 pub fn volatile() -> CacheOptions {
209 CacheOptions::ttl(Duration::from_secs(30))
210 .with_policy(CachePolicy::StaleWhileRevalidate)
211 .stale_while_revalidate(Duration::from_secs(60))
212 }
213
214 pub fn user_data() -> CacheOptions {
216 CacheOptions::ttl(Duration::from_secs(300))
217 .with_policy(CachePolicy::CacheFirst)
218 }
219
220 pub fn reference_data() -> CacheOptions {
222 CacheOptions::ttl(Duration::from_secs(3600))
223 .with_policy(CachePolicy::CacheFirst)
224 }
225
226 pub fn static_data() -> CacheOptions {
228 CacheOptions::ttl(Duration::from_secs(86400))
229 .with_policy(CachePolicy::CacheFirst)
230 }
231
232 pub fn session() -> CacheOptions {
234 CacheOptions::ttl(Duration::from_secs(1800)) .with_policy(CachePolicy::CacheFirst)
236 }
237
238 pub fn realtime() -> CacheOptions {
240 CacheOptions::bypass()
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn test_default_options() {
250 let opts = CacheOptions::default();
251 assert_eq!(opts.ttl, Some(Duration::from_secs(300)));
252 assert_eq!(opts.policy, CachePolicy::CacheFirst);
253 assert!(opts.cache_empty);
254 assert!(!opts.bypass);
255 }
256
257 #[test]
258 fn test_options_builder() {
259 let opts = CacheOptions::ttl(Duration::from_secs(60))
260 .with_policy(CachePolicy::NetworkFirst)
261 .with_tag(EntityTag::new("User"))
262 .no_cache_empty();
263
264 assert_eq!(opts.ttl, Some(Duration::from_secs(60)));
265 assert_eq!(opts.policy, CachePolicy::NetworkFirst);
266 assert_eq!(opts.tags.len(), 1);
267 assert!(!opts.cache_empty);
268 }
269
270 #[test]
271 fn test_cache_policy() {
272 assert!(CachePolicy::CacheFirst.should_check_cache());
273 assert!(CachePolicy::CacheFirst.should_fetch());
274 assert!(CachePolicy::CacheFirst.should_update_cache());
275
276 assert!(!CachePolicy::NetworkOnly.should_check_cache());
277 assert!(CachePolicy::NetworkOnly.should_fetch());
278 assert!(!CachePolicy::NetworkOnly.should_update_cache());
279
280 assert!(CachePolicy::CacheOnly.should_check_cache());
281 assert!(!CachePolicy::CacheOnly.should_fetch());
282 assert!(!CachePolicy::CacheOnly.should_update_cache());
283 }
284
285 #[test]
286 fn test_presets() {
287 let volatile = presets::volatile();
288 assert_eq!(volatile.ttl, Some(Duration::from_secs(30)));
289
290 let reference = presets::reference_data();
291 assert_eq!(reference.ttl, Some(Duration::from_secs(3600)));
292
293 let realtime = presets::realtime();
294 assert!(realtime.bypass);
295 }
296}
297
298