Skip to main content

noxu_db/
write_options.rs

1//! Write operation options.
2//!
3
4use crate::cache_mode::CacheMode;
5
6/// Options for write operations.
7///
8/// Specifies optional parameters that control write behavior, including
9/// caching and time-to-live (TTL) expiration.
10///
11///
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct WriteOptions {
14    /// Cache mode for the write operation.
15    pub cache_mode: Option<CacheMode>,
16
17    /// Time-to-live in hours (0 = no expiration).
18    pub ttl: u64,
19
20    /// Whether to update TTL on existing records.
21    pub update_ttl: bool,
22}
23
24impl WriteOptions {
25    /// Creates a new WriteOptions with default settings.
26    pub fn new() -> Self {
27        Self { cache_mode: None, ttl: 0, update_ttl: false }
28    }
29
30    /// Sets the cache mode.
31    pub fn with_cache_mode(mut self, cache_mode: CacheMode) -> Self {
32        self.cache_mode = Some(cache_mode);
33        self
34    }
35
36    /// Sets the time-to-live in hours.
37    pub fn with_ttl(mut self, ttl_hours: u64) -> Self {
38        self.ttl = ttl_hours;
39        self
40    }
41
42    /// Sets whether to update TTL on existing records.
43    pub fn with_update_ttl(mut self, update_ttl: bool) -> Self {
44        self.update_ttl = update_ttl;
45        self
46    }
47
48    /// Creates WriteOptions with evict-after-write cache mode.
49    pub fn evict_after_write() -> Self {
50        Self { cache_mode: Some(CacheMode::EvictLn), ttl: 0, update_ttl: false }
51    }
52
53    /// Creates WriteOptions with a TTL.
54    pub fn with_expiration(ttl_hours: u64) -> Self {
55        Self { cache_mode: None, ttl: ttl_hours, update_ttl: false }
56    }
57
58    /// Returns the expiration time in milliseconds from now, or 0 if no TTL.
59    pub fn expiration_time_ms(&self, current_time_ms: u64) -> u64 {
60        if self.ttl == 0 {
61            0
62        } else {
63            current_time_ms + (self.ttl * 3600 * 1000)
64        }
65    }
66
67    /// Returns whether a TTL is configured.
68    pub fn has_ttl(&self) -> bool {
69        self.ttl > 0
70    }
71
72    /// Returns the packed expiration_time (hours since epoch) for use in BinEntry.
73    ///
74    /// Returns 0 if no TTL is set.  Uses `noxu_util::ttl_hours_to_expiration`
75    /// to compute the expiration time relative to now.
76    pub fn get_expiration_time(&self) -> u32 {
77        noxu_util::ttl_hours_to_expiration(self.ttl as u32)
78    }
79}
80
81impl Default for WriteOptions {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_new() {
93        let opts = WriteOptions::new();
94        assert_eq!(opts.cache_mode, None);
95        assert_eq!(opts.ttl, 0);
96        assert!(!opts.update_ttl);
97    }
98
99    #[test]
100    fn test_with_cache_mode() {
101        let opts = WriteOptions::new().with_cache_mode(CacheMode::KeepHot);
102        assert_eq!(opts.cache_mode, Some(CacheMode::KeepHot));
103    }
104
105    #[test]
106    fn test_with_ttl() {
107        let opts = WriteOptions::new().with_ttl(24);
108        assert_eq!(opts.ttl, 24);
109    }
110
111    #[test]
112    fn test_with_update_ttl() {
113        let opts = WriteOptions::new().with_update_ttl(true);
114        assert!(opts.update_ttl);
115    }
116
117    #[test]
118    fn test_evict_after_write() {
119        let opts = WriteOptions::evict_after_write();
120        assert_eq!(opts.cache_mode, Some(CacheMode::EvictLn));
121        assert_eq!(opts.ttl, 0);
122    }
123
124    #[test]
125    fn test_with_expiration() {
126        let opts = WriteOptions::with_expiration(48);
127        assert_eq!(opts.ttl, 48);
128        assert!(!opts.update_ttl);
129    }
130
131    #[test]
132    fn test_expiration_time_ms_no_ttl() {
133        let opts = WriteOptions::new();
134        assert_eq!(opts.expiration_time_ms(1000), 0);
135    }
136
137    #[test]
138    fn test_expiration_time_ms_with_ttl() {
139        let opts = WriteOptions::new().with_ttl(1); // 1 hour
140        let current = 1000000;
141        let expected = current + (3600 * 1000);
142        assert_eq!(opts.expiration_time_ms(current), expected);
143    }
144
145    #[test]
146    fn test_expiration_time_ms_24_hours() {
147        let opts = WriteOptions::new().with_ttl(24);
148        let current = 0;
149        let expected = 24 * 3600 * 1000;
150        assert_eq!(opts.expiration_time_ms(current), expected);
151    }
152
153    #[test]
154    fn test_has_ttl() {
155        let opts_no_ttl = WriteOptions::new();
156        let opts_with_ttl = WriteOptions::new().with_ttl(1);
157        assert!(!opts_no_ttl.has_ttl());
158        assert!(opts_with_ttl.has_ttl());
159    }
160
161    #[test]
162    fn test_default() {
163        let opts = WriteOptions::default();
164        assert_eq!(opts.cache_mode, None);
165        assert_eq!(opts.ttl, 0);
166        assert!(!opts.update_ttl);
167    }
168
169    #[test]
170    fn test_clone() {
171        let opts1 = WriteOptions::with_expiration(12);
172        let opts2 = opts1.clone();
173        assert_eq!(opts1, opts2);
174    }
175
176    #[test]
177    fn test_builder_chain() {
178        let opts = WriteOptions::new()
179            .with_cache_mode(CacheMode::EvictBin)
180            .with_ttl(48)
181            .with_update_ttl(true);
182        assert_eq!(opts.cache_mode, Some(CacheMode::EvictBin));
183        assert_eq!(opts.ttl, 48);
184        assert!(opts.update_ttl);
185    }
186
187    #[test]
188    fn test_equality() {
189        let opts1 = WriteOptions::new();
190        let opts2 = WriteOptions::default();
191        assert_eq!(opts1, opts2);
192    }
193
194    #[test]
195    fn test_debug() {
196        let opts = WriteOptions::with_expiration(24);
197        let debug = format!("{:?}", opts);
198        assert!(debug.contains("cache_mode"));
199        assert!(debug.contains("ttl"));
200    }
201}