1use std::cmp::{max, min};
10
11use super::error::ConstraintError;
12use super::revision::{Range, Revision};
13use super::selectors::EventSelector;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
22pub enum AppendCondition {
23 Min(EventSelector, Revision),
25 Max(EventSelector, Revision),
27 Range(EventSelector, Range),
29}
30
31impl AppendCondition {
32 pub fn min(selector: EventSelector, revision: Revision) -> Self {
37 AppendCondition::Min(selector, revision)
38 }
39
40 pub fn max(selector: EventSelector, revision: Revision) -> Self {
45 AppendCondition::Max(selector, revision)
46 }
47
48 pub fn range(selector: EventSelector, range: Range) -> Self {
50 AppendCondition::Range(selector, range)
51 }
52
53 pub fn fail_if_events_match(selector: EventSelector) -> Self {
69 AppendCondition::Max(selector, 0)
70 }
71
72 pub fn must_not_exist(selector: EventSelector) -> Self {
86 AppendCondition::Max(selector, 0)
87 }
88
89 pub fn must_exist(selector: EventSelector) -> Self {
103 AppendCondition::Min(selector, 1)
104 }
105
106 pub fn at_revision(
125 selector: EventSelector,
126 revision: Revision,
127 ) -> Result<Self, ConstraintError> {
128 Range::new(revision, revision)
129 .map(|range| AppendCondition::Range(selector, range))
130 .map_err(|_| ConstraintError::InvalidRange {
131 min: revision,
132 max: revision,
133 })
134 }
135
136 pub fn unchanged_since(selector: EventSelector, last_seen_revision: Revision) -> Self {
152 AppendCondition::Max(selector, last_seen_revision)
153 }
154
155 pub fn selector(&self) -> &EventSelector {
157 match self {
158 AppendCondition::Min(selector, _)
159 | AppendCondition::Max(selector, _)
160 | AppendCondition::Range(selector, _) => selector,
161 }
162 }
163
164 pub fn min_revision(&self) -> Option<Revision> {
166 match self {
167 AppendCondition::Min(_, min) => Some(*min),
168 AppendCondition::Range(_, range) => Some(range.min()),
169 AppendCondition::Max(_, _) => None,
170 }
171 }
172
173 pub fn max_revision(&self) -> Option<Revision> {
175 match self {
176 AppendCondition::Max(_, max) => Some(*max),
177 AppendCondition::Range(_, range) => Some(range.max()),
178 AppendCondition::Min(_, _) => None,
179 }
180 }
181
182 pub fn combine(&self, rhs: &Self) -> Result<Self, ConstraintError> {
195 let lselector = self.selector();
196 let rselector = rhs.selector();
197
198 if lselector != rselector {
199 return Err(ConstraintError::IncompatibleSelectors);
200 }
201
202 let selector = lselector.clone();
203
204 match (self, rhs) {
205 (AppendCondition::Min(_, lmin), AppendCondition::Min(_, rmin)) => {
207 Ok(AppendCondition::Min(selector, min(*lmin, *rmin)))
208 }
209
210 (AppendCondition::Max(_, lmax), AppendCondition::Max(_, rmax)) => {
212 Ok(AppendCondition::Max(selector, max(*lmax, *rmax)))
213 }
214
215 (AppendCondition::Min(_, min_val), AppendCondition::Max(_, max_val))
217 | (AppendCondition::Max(_, max_val), AppendCondition::Min(_, min_val)) => {
218 Range::new(*min_val, *max_val)
219 .map(|range| AppendCondition::Range(selector, range))
220 .map_err(|_| ConstraintError::Conflict {
221 left: format!("{:?}", self),
222 right: format!("{:?}", rhs),
223 })
224 }
225
226 (AppendCondition::Range(_, range), AppendCondition::Min(_, rmin))
228 | (AppendCondition::Min(_, rmin), AppendCondition::Range(_, range)) => {
229 Range::new(min(range.min(), *rmin), range.max())
230 .map(|new_range| AppendCondition::Range(selector, new_range))
231 .map_err(|_| ConstraintError::Conflict {
232 left: format!("{:?}", self),
233 right: format!("{:?}", rhs),
234 })
235 }
236
237 (AppendCondition::Range(_, range), AppendCondition::Max(_, rmax))
239 | (AppendCondition::Max(_, rmax), AppendCondition::Range(_, range)) => {
240 Range::new(range.min(), max(range.max(), *rmax))
241 .map(|new_range| AppendCondition::Range(selector, new_range))
242 .map_err(|_| ConstraintError::Conflict {
243 left: format!("{:?}", self),
244 right: format!("{:?}", rhs),
245 })
246 }
247
248 (AppendCondition::Range(_, lrange), AppendCondition::Range(_, rrange)) => Range::new(
250 min(lrange.min(), rrange.min()),
251 max(lrange.max(), rrange.max()),
252 )
253 .map(|new_range| AppendCondition::Range(selector, new_range))
254 .map_err(|_| ConstraintError::Conflict {
255 left: format!("{:?}", self),
256 right: format!("{:?}", rhs),
257 }),
258 }
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265
266 fn make_selector(name: &str) -> EventSelector {
267 EventSelector::event_type_equals(name).unwrap()
268 }
269
270 #[test]
271 fn test_convenience_constructors() {
272 let selector = make_selector("test");
273
274 let min_c = AppendCondition::min(selector.clone(), 5);
275 assert!(matches!(min_c, AppendCondition::Min(_, 5)));
276
277 let max_c = AppendCondition::max(selector.clone(), 10);
278 assert!(matches!(max_c, AppendCondition::Max(_, 10)));
279
280 let range = Range::new(5, 10).unwrap();
281 let range_c = AppendCondition::range(selector.clone(), range);
282 assert!(matches!(range_c, AppendCondition::Range(_, _)));
283 }
284
285 #[test]
286 fn test_combine_min_min() {
287 let selector = make_selector("test");
288 let c1 = AppendCondition::min(selector.clone(), 10);
289 let c2 = AppendCondition::min(selector.clone(), 5);
290
291 let combined = c1.combine(&c2).unwrap();
292 assert!(matches!(combined, AppendCondition::Min(_, 5)));
293 }
294
295 #[test]
296 fn test_combine_max_max() {
297 let selector = make_selector("test");
298 let c1 = AppendCondition::max(selector.clone(), 10);
299 let c2 = AppendCondition::max(selector.clone(), 15);
300
301 let combined = c1.combine(&c2).unwrap();
302 assert!(matches!(combined, AppendCondition::Max(_, 15)));
303 }
304
305 #[test]
306 fn test_combine_min_max_valid() {
307 let selector = make_selector("test");
308 let c1 = AppendCondition::min(selector.clone(), 5);
309 let c2 = AppendCondition::max(selector.clone(), 10);
310
311 let combined = c1.combine(&c2).unwrap();
312 match combined {
313 AppendCondition::Range(_, range) => {
314 assert_eq!(range.min(), 5);
315 assert_eq!(range.max(), 10);
316 }
317 _ => panic!("Expected Range"),
318 }
319 }
320
321 #[test]
322 fn test_combine_min_max_conflict() {
323 let selector = make_selector("test");
324 let c1 = AppendCondition::min(selector.clone(), 10);
325 let c2 = AppendCondition::max(selector.clone(), 5);
326
327 let result = c1.combine(&c2);
328 assert!(matches!(result, Err(ConstraintError::Conflict { .. })));
329 }
330
331 #[test]
332 fn test_combine_different_selectors() {
333 let selector1 = make_selector("type1");
334 let selector2 = make_selector("type2");
335 let c1 = AppendCondition::min(selector1, 5);
336 let c2 = AppendCondition::min(selector2, 5);
337
338 let result = c1.combine(&c2);
339 assert!(matches!(
340 result,
341 Err(ConstraintError::IncompatibleSelectors)
342 ));
343 }
344
345 #[test]
346 fn test_combine_range_min() {
347 let selector = make_selector("test");
348 let range = Range::new(5, 10).unwrap();
349 let c1 = AppendCondition::range(selector.clone(), range);
350 let c2 = AppendCondition::min(selector.clone(), 3);
351
352 let combined = c1.combine(&c2).unwrap();
353 match combined {
354 AppendCondition::Range(_, range) => {
355 assert_eq!(range.min(), 3);
356 assert_eq!(range.max(), 10);
357 }
358 _ => panic!("Expected Range"),
359 }
360 }
361
362 #[test]
363 fn test_selector_accessor() {
364 let selector = make_selector("test");
365 let condition = AppendCondition::min(selector.clone(), 5);
366 assert_eq!(condition.selector(), &selector);
367 }
368
369 #[test]
370 fn test_fail_if_events_match() {
371 let selector = make_selector("test");
372 let condition = AppendCondition::fail_if_events_match(selector.clone());
373
374 assert!(matches!(condition, AppendCondition::Max(_, 0)));
376 assert_eq!(condition.max_revision(), Some(0));
377 }
378
379 #[test]
380 fn test_must_not_exist() {
381 let selector = make_selector("test");
382 let condition = AppendCondition::must_not_exist(selector.clone());
383
384 assert!(matches!(condition, AppendCondition::Max(_, 0)));
386 assert_eq!(condition.max_revision(), Some(0));
387 }
388
389 #[test]
390 fn test_must_exist() {
391 let selector = make_selector("test");
392 let condition = AppendCondition::must_exist(selector.clone());
393
394 assert!(matches!(condition, AppendCondition::Min(_, 1)));
396 assert_eq!(condition.min_revision(), Some(1));
397 }
398
399 #[test]
400 fn test_at_revision() {
401 let selector = make_selector("test");
402 let condition = AppendCondition::at_revision(selector.clone(), 42).unwrap();
403
404 match condition {
406 AppendCondition::Range(_, range) => {
407 assert_eq!(range.min(), 42);
408 assert_eq!(range.max(), 42);
409 }
410 _ => panic!("Expected Range"),
411 }
412 }
413
414 #[test]
415 fn test_unchanged_since() {
416 let selector = make_selector("test");
417 let condition = AppendCondition::unchanged_since(selector.clone(), 100);
418
419 assert!(matches!(condition, AppendCondition::Max(_, 100)));
421 assert_eq!(condition.max_revision(), Some(100));
422 }
423}