use std::fmt::{self, Write as _};
use haematite::db::migrate::{MigrationDirection, MigrationOutcome, MigrationReport};
pub fn render(report: &MigrationReport) -> Result<String, fmt::Error> {
let mut out = String::new();
let banner = match report.outcome {
MigrationOutcome::AlreadyInTargetFormat => {
"haematite migrate-chunking — already in target format, nothing to do"
}
MigrationOutcome::MigratedToV2 => {
"haematite migrate-chunking — migrated to v2 (byte-aware)"
}
MigrationOutcome::AbortedToV1 => {
"haematite migrate-chunking — reverted to v1 (count-target)"
}
};
let direction = match report.direction {
MigrationDirection::Forward => "forward (v1 → v2)",
MigrationDirection::Abort => "abort/reverse (v2 → v1)",
};
writeln!(out, "{banner}")?;
writeln!(out, "data dir: {}", report.data_dir.display())?;
writeln!(
out,
"direction: {direction} ({} → {})",
report.source_policy, report.target_policy
)?;
writeln!(
out,
"shard count: {} · duration: {} ms",
report.shard_count, report.duration_ms
)?;
out.push('\n');
writeln!(
out,
"shards: rebuilt {} · unchanged {} · empty {}",
group(report.shards_rebuilt),
group(report.shards_unchanged),
group(report.shards_empty)
)?;
writeln!(
out,
"branch heads: rebuilt {} · unchanged {}",
group(report.branch_heads_rebuilt),
group(report.branch_heads_unchanged)
)?;
out.push('\n');
writeln!(
out,
"vacuum-before-migrate:\n {}",
report.vacuum_before_migrate
)?;
writeln!(out, "manifest bracket:\n {}", report.manifest_bracket)?;
Ok(out)
}
fn group(value: usize) -> String {
let digits = value.to_string();
let mut grouped = String::with_capacity(digits.len() + digits.len() / 3);
for (index, digit) in digits.chars().enumerate() {
if index > 0 && (digits.len() - index).is_multiple_of(3) {
grouped.push(',');
}
grouped.push(digit);
}
grouped
}