use crate::database::{ExifDao, FavoriteDao}; use crate::tags::TagDao; use anyhow::Result; use log::{error, info}; use opentelemetry; use std::sync::{Arc, Mutex}; pub struct DatabaseUpdater { tag_dao: Arc>, exif_dao: Arc>, favorites_dao: Arc>, } impl DatabaseUpdater { pub fn new( tag_dao: Arc>, exif_dao: Arc>, favorites_dao: Arc>, ) -> Self { Self { tag_dao, exif_dao, favorites_dao, } } /// Update file path across all three database tables /// Returns Ok(()) if successful, continues on partial failures but logs errors pub fn update_file_path(&mut self, old_path: &str, new_path: &str) -> Result<()> { let context = opentelemetry::Context::current(); let mut success_count = 0; let mut error_count = 0; // Update tagged_photo table if let Ok(mut dao) = self.tag_dao.lock() { match dao.update_photo_name(old_path, new_path, &context) { Ok(_) => { info!("Updated tagged_photo: {} -> {}", old_path, new_path); success_count += 1; } Err(e) => { error!("Failed to update tagged_photo for {}: {:?}", old_path, e); error_count += 1; } } } else { error!("Failed to acquire lock on TagDao"); error_count += 1; } // Update image_exif table if let Ok(mut dao) = self.exif_dao.lock() { match dao.update_file_path(&context, old_path, new_path) { Ok(_) => { info!("Updated image_exif: {} -> {}", old_path, new_path); success_count += 1; } Err(e) => { error!("Failed to update image_exif for {}: {:?}", old_path, e); error_count += 1; } } } else { error!("Failed to acquire lock on ExifDao"); error_count += 1; } // Update favorites table if let Ok(mut dao) = self.favorites_dao.lock() { match dao.update_path(old_path, new_path) { Ok(_) => { info!("Updated favorites: {} -> {}", old_path, new_path); success_count += 1; } Err(e) => { error!("Failed to update favorites for {}: {:?}", old_path, e); error_count += 1; } } } else { error!("Failed to acquire lock on FavoriteDao"); error_count += 1; } if success_count > 0 { info!( "Updated {}/{} tables for {} -> {}", success_count, success_count + error_count, old_path, new_path ); Ok(()) } else { Err(anyhow::anyhow!( "Failed to update any tables for {} -> {}", old_path, new_path )) } } /// Get all file paths from all three database tables pub fn get_all_file_paths(&mut self) -> Result> { let context = opentelemetry::Context::current(); let mut all_paths = Vec::new(); // Get from tagged_photo if let Ok(mut dao) = self.tag_dao.lock() { match dao.get_all_photo_names(&context) { Ok(paths) => { info!("Found {} paths in tagged_photo", paths.len()); all_paths.extend(paths); } Err(e) => { error!("Failed to get paths from tagged_photo: {:?}", e); } } } // Get from image_exif if let Ok(mut dao) = self.exif_dao.lock() { match dao.get_all_file_paths(&context) { Ok(paths) => { info!("Found {} paths in image_exif", paths.len()); all_paths.extend(paths); } Err(e) => { error!("Failed to get paths from image_exif: {:?}", e); } } } // Get from favorites if let Ok(mut dao) = self.favorites_dao.lock() { match dao.get_all_paths() { Ok(paths) => { info!("Found {} paths in favorites", paths.len()); all_paths.extend(paths); } Err(e) => { error!("Failed to get paths from favorites: {:?}", e); } } } // Deduplicate all_paths.sort(); all_paths.dedup(); info!("Total unique paths across all tables: {}", all_paths.len()); Ok(all_paths) } }