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)).with_policy(CachePolicy::CacheFirst)
217 }
218
219 pub fn reference_data() -> CacheOptions {
221 CacheOptions::ttl(Duration::from_secs(3600)).with_policy(CachePolicy::CacheFirst)
222 }
223
224 pub fn static_data() -> CacheOptions {
226 CacheOptions::ttl(Duration::from_secs(86400)).with_policy(CachePolicy::CacheFirst)
227 }
228
229 pub fn session() -> CacheOptions {
231 CacheOptions::ttl(Duration::from_secs(1800)) .with_policy(CachePolicy::CacheFirst)
233 }
234
235 pub fn realtime() -> CacheOptions {
237 CacheOptions::bypass()
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn test_default_options() {
247 let opts = CacheOptions::default();
248 assert_eq!(opts.ttl, Some(Duration::from_secs(300)));
249 assert_eq!(opts.policy, CachePolicy::CacheFirst);
250 assert!(opts.cache_empty);
251 assert!(!opts.bypass);
252 }
253
254 #[test]
255 fn test_options_builder() {
256 let opts = CacheOptions::ttl(Duration::from_secs(60))
257 .with_policy(CachePolicy::NetworkFirst)
258 .with_tag(EntityTag::new("User"))
259 .no_cache_empty();
260
261 assert_eq!(opts.ttl, Some(Duration::from_secs(60)));
262 assert_eq!(opts.policy, CachePolicy::NetworkFirst);
263 assert_eq!(opts.tags.len(), 1);
264 assert!(!opts.cache_empty);
265 }
266
267 #[test]
268 fn test_cache_policy() {
269 assert!(CachePolicy::CacheFirst.should_check_cache());
270 assert!(CachePolicy::CacheFirst.should_fetch());
271 assert!(CachePolicy::CacheFirst.should_update_cache());
272
273 assert!(!CachePolicy::NetworkOnly.should_check_cache());
274 assert!(CachePolicy::NetworkOnly.should_fetch());
275 assert!(!CachePolicy::NetworkOnly.should_update_cache());
276
277 assert!(CachePolicy::CacheOnly.should_check_cache());
278 assert!(!CachePolicy::CacheOnly.should_fetch());
279 assert!(!CachePolicy::CacheOnly.should_update_cache());
280 }
281
282 #[test]
283 fn test_presets() {
284 let volatile = presets::volatile();
285 assert_eq!(volatile.ttl, Some(Duration::from_secs(30)));
286
287 let reference = presets::reference_data();
288 assert_eq!(reference.ttl, Some(Duration::from_secs(3600)));
289
290 let realtime = presets::realtime();
291 assert!(realtime.bypass);
292 }
293}