1use crate::spec::{SnapshotRef, TableMetadataRef};
19
20struct Ancestors {
21 next: Option<SnapshotRef>,
22 get_snapshot: Box<dyn Fn(i64) -> Option<SnapshotRef> + Send>,
23}
24
25impl Iterator for Ancestors {
26 type Item = SnapshotRef;
27
28 fn next(&mut self) -> Option<Self::Item> {
29 let snapshot = self.next.take()?;
30 self.next = snapshot
31 .parent_snapshot_id()
32 .and_then(|id| (self.get_snapshot)(id));
33 Some(snapshot)
34 }
35}
36
37pub fn ancestors_of(
39 table_metadata: &TableMetadataRef,
40 snapshot_id: i64,
41) -> impl Iterator<Item = SnapshotRef> + Send {
42 let initial = table_metadata.snapshot_by_id(snapshot_id).cloned();
43 let table_metadata = table_metadata.clone();
44 Ancestors {
45 next: initial,
46 get_snapshot: Box::new(move |id| table_metadata.snapshot_by_id(id).cloned()),
47 }
48}
49
50pub fn ancestors_between(
57 table_metadata: &TableMetadataRef,
58 latest_snapshot_id: i64,
59 oldest_snapshot_id: Option<i64>,
60) -> impl Iterator<Item = SnapshotRef> + Send {
61 ancestors_of(table_metadata, latest_snapshot_id).take_while(move |snapshot| {
62 oldest_snapshot_id
63 .map(|id| snapshot.snapshot_id() != id)
64 .unwrap_or(true)
65 })
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::scan::tests::TableTestFixture;
72
73 const S1: i64 = 3051729675574597004;
75 const S2: i64 = 3055729675574597004;
76 const S3: i64 = 3056729675574597004;
77 const S4: i64 = 3057729675574597004;
78 const S5: i64 = 3059729675574597004;
79
80 fn metadata() -> TableMetadataRef {
81 let fixture = TableTestFixture::new_with_deep_history();
82 std::sync::Arc::new(fixture.table.metadata().clone())
83 }
84
85 #[test]
88 fn test_ancestors_of_nonexistent_snapshot_returns_empty() {
89 let meta = metadata();
90 let ids: Vec<i64> = ancestors_of(&meta, 999).map(|s| s.snapshot_id()).collect();
91 assert!(ids.is_empty());
92 }
93
94 #[test]
95 fn test_ancestors_of_root_returns_only_root() {
96 let meta = metadata();
97 let ids: Vec<i64> = ancestors_of(&meta, S1).map(|s| s.snapshot_id()).collect();
98 assert_eq!(ids, vec![S1]);
99 }
100
101 #[test]
102 fn test_ancestors_of_leaf_returns_full_chain() {
103 let meta = metadata();
104 let ids: Vec<i64> = ancestors_of(&meta, S5).map(|s| s.snapshot_id()).collect();
105 assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
106 }
107
108 #[test]
109 fn test_ancestors_of_mid_chain_returns_partial_chain() {
110 let meta = metadata();
111 let ids: Vec<i64> = ancestors_of(&meta, S3).map(|s| s.snapshot_id()).collect();
112 assert_eq!(ids, vec![S3, S2, S1]);
113 }
114
115 #[test]
116 fn test_ancestors_of_second_snapshot() {
117 let meta = metadata();
118 let ids: Vec<i64> = ancestors_of(&meta, S2).map(|s| s.snapshot_id()).collect();
119 assert_eq!(ids, vec![S2, S1]);
120 }
121
122 #[test]
125 fn test_ancestors_between_same_id_returns_empty() {
126 let meta = metadata();
127 let ids: Vec<i64> = ancestors_between(&meta, S3, Some(S3))
128 .map(|s| s.snapshot_id())
129 .collect();
130 assert!(ids.is_empty());
131 }
132
133 #[test]
134 fn test_ancestors_between_no_oldest_returns_all_ancestors() {
135 let meta = metadata();
136 let ids: Vec<i64> = ancestors_between(&meta, S5, None)
137 .map(|s| s.snapshot_id())
138 .collect();
139 assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
140 }
141
142 #[test]
143 fn test_ancestors_between_excludes_oldest_snapshot() {
144 let meta = metadata();
145 let ids: Vec<i64> = ancestors_between(&meta, S5, Some(S2))
147 .map(|s| s.snapshot_id())
148 .collect();
149 assert_eq!(ids, vec![S5, S4, S3]);
150 }
151
152 #[test]
153 fn test_ancestors_between_adjacent_snapshots() {
154 let meta = metadata();
155 let ids: Vec<i64> = ancestors_between(&meta, S3, Some(S2))
157 .map(|s| s.snapshot_id())
158 .collect();
159 assert_eq!(ids, vec![S3]);
160 }
161
162 #[test]
163 fn test_ancestors_between_leaf_and_root() {
164 let meta = metadata();
165 let ids: Vec<i64> = ancestors_between(&meta, S5, Some(S1))
167 .map(|s| s.snapshot_id())
168 .collect();
169 assert_eq!(ids, vec![S5, S4, S3, S2]);
170 }
171
172 #[test]
173 fn test_ancestors_between_nonexistent_oldest_returns_full_chain() {
174 let meta = metadata();
175 let ids: Vec<i64> = ancestors_between(&meta, S5, Some(999))
177 .map(|s| s.snapshot_id())
178 .collect();
179 assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
180 }
181
182 #[test]
183 fn test_ancestors_between_nonexistent_latest_returns_empty() {
184 let meta = metadata();
185 let ids: Vec<i64> = ancestors_between(&meta, 999, Some(S1))
186 .map(|s| s.snapshot_id())
187 .collect();
188 assert!(ids.is_empty());
189 }
190}