use crate::spec::{SnapshotRef, TableMetadataRef};
struct Ancestors {
next: Option<SnapshotRef>,
get_snapshot: Box<dyn Fn(i64) -> Option<SnapshotRef> + Send>,
}
impl Iterator for Ancestors {
type Item = SnapshotRef;
fn next(&mut self) -> Option<Self::Item> {
let snapshot = self.next.take()?;
self.next = snapshot
.parent_snapshot_id()
.and_then(|id| (self.get_snapshot)(id));
Some(snapshot)
}
}
pub fn ancestors_of(
table_metadata: &TableMetadataRef,
snapshot_id: i64,
) -> impl Iterator<Item = SnapshotRef> + Send {
let initial = table_metadata.snapshot_by_id(snapshot_id).cloned();
let table_metadata = table_metadata.clone();
Ancestors {
next: initial,
get_snapshot: Box::new(move |id| table_metadata.snapshot_by_id(id).cloned()),
}
}
pub fn ancestors_between(
table_metadata: &TableMetadataRef,
latest_snapshot_id: i64,
oldest_snapshot_id: Option<i64>,
) -> impl Iterator<Item = SnapshotRef> + Send {
ancestors_of(table_metadata, latest_snapshot_id).take_while(move |snapshot| {
oldest_snapshot_id
.map(|id| snapshot.snapshot_id() != id)
.unwrap_or(true)
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scan::tests::TableTestFixture;
const S1: i64 = 3051729675574597004;
const S2: i64 = 3055729675574597004;
const S3: i64 = 3056729675574597004;
const S4: i64 = 3057729675574597004;
const S5: i64 = 3059729675574597004;
fn metadata() -> TableMetadataRef {
let fixture = TableTestFixture::new_with_deep_history();
std::sync::Arc::new(fixture.table.metadata().clone())
}
#[test]
fn test_ancestors_of_nonexistent_snapshot_returns_empty() {
let meta = metadata();
let ids: Vec<i64> = ancestors_of(&meta, 999).map(|s| s.snapshot_id()).collect();
assert!(ids.is_empty());
}
#[test]
fn test_ancestors_of_root_returns_only_root() {
let meta = metadata();
let ids: Vec<i64> = ancestors_of(&meta, S1).map(|s| s.snapshot_id()).collect();
assert_eq!(ids, vec![S1]);
}
#[test]
fn test_ancestors_of_leaf_returns_full_chain() {
let meta = metadata();
let ids: Vec<i64> = ancestors_of(&meta, S5).map(|s| s.snapshot_id()).collect();
assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
}
#[test]
fn test_ancestors_of_mid_chain_returns_partial_chain() {
let meta = metadata();
let ids: Vec<i64> = ancestors_of(&meta, S3).map(|s| s.snapshot_id()).collect();
assert_eq!(ids, vec![S3, S2, S1]);
}
#[test]
fn test_ancestors_of_second_snapshot() {
let meta = metadata();
let ids: Vec<i64> = ancestors_of(&meta, S2).map(|s| s.snapshot_id()).collect();
assert_eq!(ids, vec![S2, S1]);
}
#[test]
fn test_ancestors_between_same_id_returns_empty() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S3, Some(S3))
.map(|s| s.snapshot_id())
.collect();
assert!(ids.is_empty());
}
#[test]
fn test_ancestors_between_no_oldest_returns_all_ancestors() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S5, None)
.map(|s| s.snapshot_id())
.collect();
assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
}
#[test]
fn test_ancestors_between_excludes_oldest_snapshot() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S5, Some(S2))
.map(|s| s.snapshot_id())
.collect();
assert_eq!(ids, vec![S5, S4, S3]);
}
#[test]
fn test_ancestors_between_adjacent_snapshots() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S3, Some(S2))
.map(|s| s.snapshot_id())
.collect();
assert_eq!(ids, vec![S3]);
}
#[test]
fn test_ancestors_between_leaf_and_root() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S5, Some(S1))
.map(|s| s.snapshot_id())
.collect();
assert_eq!(ids, vec![S5, S4, S3, S2]);
}
#[test]
fn test_ancestors_between_nonexistent_oldest_returns_full_chain() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, S5, Some(999))
.map(|s| s.snapshot_id())
.collect();
assert_eq!(ids, vec![S5, S4, S3, S2, S1]);
}
#[test]
fn test_ancestors_between_nonexistent_latest_returns_empty() {
let meta = metadata();
let ids: Vec<i64> = ancestors_between(&meta, 999, Some(S1))
.map(|s| s.snapshot_id())
.collect();
assert!(ids.is_empty());
}
}