reifydb_value/config/
window.rs1use super::Config;
5use crate::value::duration::Duration;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct WindowSealing {
9 pub lateness: Option<Duration>,
10 pub immutable: Option<Duration>,
11}
12
13impl Config {
14 pub fn sealing(&self) -> Option<WindowSealing> {
15 self.resolve_sealing().ok()
16 }
17
18 pub fn validated_sealing(&self) -> WindowSealing {
19 match self.resolve_sealing() {
20 Ok(sealing) => sealing,
21 Err(violation) => panic!("{}: {}", self.name, violation),
22 }
23 }
24
25 fn resolve_immutable(&self) -> Option<Duration> {
26 match self.bool("immutable") {
27 Some(true) => Some(Duration::zero()),
28 Some(false) => None,
29 None => self.duration("immutable"),
30 }
31 }
32
33 fn resolve_sealing(&self) -> Result<WindowSealing, String> {
34 let sealing = WindowSealing {
35 lateness: self.duration("lateness"),
36 immutable: self.resolve_immutable(),
37 };
38 if let (Some(lateness), Some(immutable)) = (sealing.lateness, sealing.immutable)
39 && immutable >= lateness
40 {
41 return Err(format!("immutable {immutable} must be strictly less than lateness {lateness}"));
42 }
43 Ok(sealing)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::{super::testutil::config, WindowSealing};
50 use crate::value::{Value, duration::Duration};
51
52 fn secs(n: i64) -> Duration {
53 Duration::from_seconds(n).unwrap()
54 }
55
56 #[test]
57 fn declared_immutable_below_lateness_is_kept_verbatim() {
58 let cfg =
59 config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Duration(secs(15)))]);
60 assert_eq!(
61 cfg.sealing(),
62 Some(WindowSealing {
63 lateness: Some(secs(20)),
64 immutable: Some(secs(15)),
65 })
66 );
67 }
68
69 #[test]
70 fn lateness_without_immutable_resolves_with_no_immutable() {
71 let cfg = config(vec![("lateness", Value::Duration(secs(20)))]);
73 assert_eq!(
74 cfg.sealing(),
75 Some(WindowSealing {
76 lateness: Some(secs(20)),
77 immutable: None,
78 })
79 );
80 }
81
82 #[test]
83 fn declared_immutable_equal_to_lateness_is_rejected() {
84 let cfg =
86 config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Duration(secs(20)))]);
87 assert_eq!(cfg.sealing(), None);
88 }
89
90 #[test]
91 fn declared_immutable_above_lateness_is_rejected() {
92 let cfg =
93 config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Duration(secs(30)))]);
94 assert_eq!(cfg.sealing(), None);
95 }
96
97 #[test]
98 fn immutable_without_lateness_is_accepted() {
99 let cfg = config(vec![("immutable", Value::Duration(secs(15)))]);
101 assert_eq!(
102 cfg.sealing(),
103 Some(WindowSealing {
104 lateness: None,
105 immutable: Some(secs(15)),
106 })
107 );
108 }
109
110 #[test]
111 fn neither_knob_declared_leaves_both_absent() {
112 let cfg = config(vec![("duration", Value::Duration(secs(60)))]);
114 assert_eq!(
115 cfg.sealing(),
116 Some(WindowSealing {
117 lateness: None,
118 immutable: None,
119 })
120 );
121 }
122
123 #[test]
124 fn validated_returns_both_when_declared() {
125 let cfg =
126 config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Duration(secs(15)))]);
127 assert_eq!(
128 cfg.validated_sealing(),
129 WindowSealing {
130 lateness: Some(secs(20)),
131 immutable: Some(secs(15)),
132 }
133 );
134 }
135
136 #[test]
137 fn validated_returns_no_immutable_when_only_the_lateness_is_declared() {
138 let cfg = config(vec![("lateness", Value::Duration(secs(20)))]);
140 assert_eq!(
141 cfg.validated_sealing(),
142 WindowSealing {
143 lateness: Some(secs(20)),
144 immutable: None,
145 }
146 );
147 }
148
149 #[test]
150 #[should_panic(expected = "must be strictly less than lateness")]
151 fn validated_names_the_ordering_violation() {
152 let cfg =
153 config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Duration(secs(20)))]);
154 cfg.validated_sealing();
155 }
156
157 #[test]
158 fn validated_accepts_an_immutable_without_a_lateness() {
159 let cfg = config(vec![("immutable", Value::Duration(secs(15)))]);
161 assert_eq!(
162 cfg.validated_sealing(),
163 WindowSealing {
164 lateness: None,
165 immutable: Some(secs(15)),
166 }
167 );
168 }
169
170 #[test]
171 fn validated_accepts_a_window_that_declares_no_knob_at_all() {
172 let cfg = config(vec![("duration", Value::Duration(secs(60)))]);
173 assert_eq!(
174 cfg.validated_sealing(),
175 WindowSealing {
176 lateness: None,
177 immutable: None,
178 }
179 );
180 }
181
182 #[test]
183 fn boolean_true_resolves_to_a_zero_duration() {
184 let cfg = config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Boolean(true))]);
185 assert_eq!(
186 cfg.sealing(),
187 Some(WindowSealing {
188 lateness: Some(secs(20)),
189 immutable: Some(Duration::zero()),
190 })
191 );
192 }
193
194 #[test]
195 fn boolean_false_resolves_as_if_absent() {
196 let cfg = config(vec![("lateness", Value::Duration(secs(20))), ("immutable", Value::Boolean(false))]);
197 assert_eq!(
198 cfg.sealing(),
199 Some(WindowSealing {
200 lateness: Some(secs(20)),
201 immutable: None,
202 })
203 );
204 }
205}