/// Generic compaction operation executor /// /// Eliminates mode-based branching duplication. /// Centralizes DryRun vs Execute logic. use crate::compaction::CompactionMode; use tracing::debug; /// Generic compaction operation result #[derive(Debug, Clone, Copy)] pub struct OperationResult { pub executed: bool, pub count: usize, pub bytes: usize, } /// Execute a compaction operation (generically handles DryRun vs Execute) /// /// # Example /// ```ignore /// let result = execute_operation( /// mode, /// "duplicate deletion", /// 10, // count /// |_| async { /* actual DB operation */ }, /// ).await?; /// ``` pub async fn execute_operation( mode: CompactionMode, operation_name: &str, count: usize, bytes: usize, execute_fn: F, ) -> anyhow::Result where F: std::future::Future>, { match mode { CompactionMode::DryRun => { debug!("DRY-RUN: Would {} ({} items, {} bytes)", operation_name, count, bytes); Ok(OperationResult { executed: false, count, bytes, }) } CompactionMode::Execute => { execute_fn.await?; debug!("EXECUTED: {} ({} items, {} bytes)", operation_name, count, bytes); Ok(OperationResult { executed: true, count, bytes, }) } } } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_operation_result_dry_run() { let result = execute_operation( CompactionMode::DryRun, "test", 5, 1024, async { Ok(()) }, ) .await .unwrap(); assert!(!result.executed); assert_eq!(result.count, 5); assert_eq!(result.bytes, 1024); } #[tokio::test] async fn test_operation_result_execute() { let result = execute_operation( CompactionMode::Execute, "test", 5, 1024, async { Ok(()) }, ) .await .unwrap(); assert!(result.executed); assert_eq!(result.count, 5); assert_eq!(result.bytes, 1024); } #[tokio::test] async fn test_operation_result_error_handling() { let result = execute_operation( CompactionMode::Execute, "test", 5, 1024, async { Err(anyhow::anyhow!("test error")) }, ) .await; assert!(result.is_err()); } }