kopiur_kopia/
selection.rs1use chrono::{DateTime, Utc};
13
14use crate::SnapshotListEntry;
15
16pub fn filter_as_of(
20 mut snapshots: Vec<SnapshotListEntry>,
21 cutoff: Option<DateTime<Utc>>,
22) -> Vec<SnapshotListEntry> {
23 if let Some(cutoff) = cutoff {
24 snapshots.retain(|e| e.end_time <= cutoff);
25 }
26 snapshots
27}
28
29pub fn pick_offset(snapshots: Vec<SnapshotListEntry>, offset: i64) -> Option<SnapshotListEntry> {
33 let idx = offset.max(0) as usize;
34 snapshots.into_iter().nth(idx)
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 fn list_entry(id: &str, end_time: &str) -> SnapshotListEntry {
42 serde_json::from_value(serde_json::json!({
43 "id": id,
44 "source": { "host": "h", "userName": "u", "path": "/data" },
45 "startTime": end_time,
46 "endTime": end_time,
47 }))
48 .expect("valid SnapshotListEntry")
49 }
50
51 fn three_snapshots() -> Vec<SnapshotListEntry> {
53 vec![
54 list_entry("k3", "2026-06-03T00:00:00Z"),
55 list_entry("k2", "2026-06-02T00:00:00Z"),
56 list_entry("k1", "2026-06-01T00:00:00Z"),
57 ]
58 }
59
60 fn cutoff(s: &str) -> DateTime<Utc> {
61 DateTime::parse_from_rfc3339(s).unwrap().with_timezone(&Utc)
62 }
63
64 #[test]
65 fn filter_as_of_keeps_snapshots_at_or_before_the_instant() {
66 let kept = filter_as_of(three_snapshots(), Some(cutoff("2026-06-02T12:00:00Z")));
68 assert_eq!(
69 kept.iter().map(|e| e.id.as_str()).collect::<Vec<_>>(),
70 ["k2", "k1"]
71 );
72 let kept = filter_as_of(three_snapshots(), Some(cutoff("2026-06-02T00:00:00Z")));
74 assert_eq!(kept.first().map(|e| e.id.as_str()), Some("k2"));
75 let kept = filter_as_of(three_snapshots(), Some(cutoff("2026-05-01T00:00:00Z")));
77 assert!(kept.is_empty());
78 let kept = filter_as_of(three_snapshots(), None);
80 assert_eq!(kept.len(), 3);
81 }
82
83 #[test]
84 fn as_of_composes_with_offset() {
85 let kept = filter_as_of(three_snapshots(), Some(cutoff("2026-06-02T12:00:00Z")));
88 assert_eq!(pick_offset(kept, 1).map(|e| e.id), Some("k1".to_string()));
89 }
90
91 #[test]
92 fn pick_offset_zero_is_newest_and_out_of_range_is_none() {
93 assert_eq!(
94 pick_offset(three_snapshots(), 0).map(|e| e.id),
95 Some("k3".to_string())
96 );
97 assert_eq!(
98 pick_offset(three_snapshots(), 2).map(|e| e.id),
99 Some("k1".to_string())
100 );
101 assert_eq!(pick_offset(three_snapshots(), 3).map(|e| e.id), None);
102 assert_eq!(
104 pick_offset(three_snapshots(), -1).map(|e| e.id),
105 Some("k3".to_string())
106 );
107 }
108}