use std::path::Path; // This is a test/example file demonstrating how to use the new repository functions // Note: This requires the database to be set up and proper imports #[cfg(test)] mod tests { use chrono::Utc; use sqlx::SqlitePool; use crate::models::{ exercise::Exercise, node::Node, path::{Metadata, Path}, }; use crate::repositories::{ path_json_utils::PathJsonUtils, repository_manager::RepositoryManager, }; async fn setup_test_database() -> SqlitePool { // This would normally connect to a test database // For demonstration purposes only todo!("Setup test database connection") } #[tokio::test] async fn test_save_and_retrieve_path() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create a test path let test_path = create_sample_path(); // Save the path let saved_path_id = repo_manager .paths() .save_path(test_path.clone()) .await .expect("Failed to save path"); println!("Saved path with ID: {}", saved_path_id); // Retrieve the path let path_id_int = saved_path_id.parse::().expect("Invalid path ID"); let retrieved_path = repo_manager .paths() .get_path_by_id(path_id_int) .await .expect("Failed to retrieve path"); // Verify the data assert_eq!(retrieved_path.id, test_path.id); assert_eq!(retrieved_path.title, test_path.title); assert_eq!(retrieved_path.nodes.len(), test_path.nodes.len()); println!("✅ Successfully saved and retrieved path!"); } #[tokio::test] async fn test_update_path() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save initial path let mut test_path = create_sample_path(); let path_id = repo_manager .paths() .save_path(test_path.clone()) .await .expect("Failed to save path"); // Modify the path test_path.title = "Updated Path Title".to_string(); test_path.description = "Updated description with new content".to_string(); // Add a new node let new_node = Node { id: 999, // This will be auto-assigned title: "New Node".to_string(), description: "A newly added node".to_string(), path_id: test_path.id.clone(), exercises: vec![Exercise { id: 999, ex_type: "vocabulary".to_string(), content: r#"{"word": "neu", "translation": "new", "example": "Das ist neu."}"# .to_string(), node_id: 999, }], }; test_path.nodes.push(new_node); // Update the path repo_manager .paths() .update_path(test_path.clone()) .await .expect("Failed to update path"); // Retrieve and verify let path_id_int = path_id.parse::().expect("Invalid path ID"); let updated_path = repo_manager .paths() .get_path_by_id(path_id_int) .await .expect("Failed to retrieve updated path"); assert_eq!(updated_path.title, "Updated Path Title"); assert_eq!(updated_path.nodes.len(), 3); // Original 2 + 1 new println!("✅ Successfully updated path!"); } #[tokio::test] async fn test_clone_path() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save original path let original_path = create_sample_path(); let original_path_id = repo_manager .paths() .save_path(original_path.clone()) .await .expect("Failed to save original path"); // Clone the path let original_id_int = original_path_id.parse::().expect("Invalid path ID"); let cloned_path_id = repo_manager .clone_path_complete( original_id_int, "cloned_path_001", "Cloned German Basics", ) .await .expect("Failed to clone path"); // Retrieve the cloned path let cloned_id_int = cloned_path_id.parse::().unwrap_or(0); let cloned_path = repo_manager .paths() .get_path_by_id(cloned_id_int) .await .expect("Failed to retrieve cloned path"); // Verify clone assert_eq!(cloned_path.id, "cloned_path_001"); assert_eq!(cloned_path.title, "Cloned German Basics"); assert_eq!(cloned_path.nodes.len(), original_path.nodes.len()); println!("✅ Successfully cloned path!"); } #[tokio::test] async fn test_json_import_export() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create sample JSON let json_content = r#" { "id": "test_json_path", "title": "JSON Test Path", "description": "Testing JSON import/export functionality", "metadata": [ { "path_id": "test_json_path", "version": "1.0.0", "created_at": "2024-01-01T12:00:00Z", "updated_at": "2024-01-01T12:00:00Z" } ], "nodes": [ { "id": 1, "title": "JSON Test Node", "description": "Testing node from JSON", "path_id": "test_json_path", "exercises": [ { "id": 1, "ex_type": "vocabulary", "content": "{\"word\": \"Test\", \"translation\": \"Test\", \"example\": \"This is a test.\"}", "node_id": 1 } ] } ] } "#; // Import from JSON let imported_path_id = repo_manager .import_path_from_json(json_content) .await .expect("Failed to import path from JSON"); println!("Imported path ID: {}", imported_path_id); // Export back to JSON let path_id_int = imported_path_id.parse::().expect("Invalid path ID"); let exported_json = repo_manager .export_path_to_json(path_id_int) .await .expect("Failed to export path to JSON"); println!("Exported JSON length: {} characters", exported_json.len()); // Verify the exported JSON contains expected content assert!(exported_json.contains("JSON Test Path")); assert!(exported_json.contains("test_json_path")); println!("✅ Successfully imported and exported JSON!"); } #[tokio::test] async fn test_path_statistics() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save path let test_path = create_sample_path(); let path_id = repo_manager .paths() .save_path(test_path) .await .expect("Failed to save path"); // Get statistics let path_id_int = path_id.parse::().expect("Invalid path ID"); let stats = repo_manager .get_path_statistics(path_id_int) .await .expect("Failed to get path statistics"); // Print statistics stats.print_detailed_summary(); // Verify statistics assert_eq!(stats.node_count, 2); assert_eq!(stats.total_exercises, 3); assert!(stats.exercise_types.contains_key("vocabulary")); assert!(stats.exercise_types.contains_key("multiple_choice")); println!("✅ Successfully generated path statistics!"); } #[tokio::test] async fn test_path_validation() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save path let test_path = create_sample_path(); let path_id = repo_manager .paths() .save_path(test_path) .await .expect("Failed to save path"); // Validate path integrity let path_id_int = path_id.parse::().expect("Invalid path ID"); let issues = repo_manager .validate_path_integrity(path_id_int) .await .expect("Failed to validate path"); if issues.is_empty() { println!("✅ Path validation passed - no issues found!"); } else { println!("⚠️ Path validation found issues:"); for issue in &issues { println!(" - {}", issue); } } } #[tokio::test] async fn test_search_functionality() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save multiple paths for searching let path1 = create_sample_path(); let mut path2 = create_sample_path(); path2.id = "search_test_002".to_string(); path2.title = "Advanced German Grammar".to_string(); path2.description = "Complex grammatical structures and advanced vocabulary".to_string(); repo_manager .paths() .save_path(path1) .await .expect("Failed to save path1"); repo_manager .paths() .save_path(path2) .await .expect("Failed to save path2"); // Search for paths let search_results = repo_manager .search_paths("German") .await .expect("Failed to search paths"); println!("Search results for 'German':"); for result in &search_results { result.print_summary(); println!(); } assert!(!search_results.is_empty()); println!("✅ Search functionality working correctly!"); } #[tokio::test] async fn test_delete_operations() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Create and save path let test_path = create_sample_path(); let path_id = repo_manager .paths() .save_path(test_path) .await .expect("Failed to save path"); // Verify path exists let path_id_int = path_id.parse::().expect("Invalid path ID"); let path_exists = repo_manager .paths() .path_exists(path_id_int) .await .expect("Failed to check path existence"); assert!(path_exists); // Delete the path repo_manager .paths() .delete_path(path_id_int) .await .expect("Failed to delete path"); // Verify path no longer exists let path_still_exists = repo_manager .paths() .path_exists(path_id_int) .await .expect("Failed to check path existence after deletion"); assert!(!path_still_exists); println!("✅ Successfully deleted path and verified removal!"); } #[tokio::test] async fn test_database_statistics() { let pool = setup_test_database().await; let repo_manager = RepositoryManager::new(&pool); // Get database statistics let stats = repo_manager .get_stats() .await .expect("Failed to get database statistics"); println!("=== Database Statistics ==="); println!("Total paths: {}", stats.path_count); println!("Total nodes: {}", stats.node_count); println!("Total exercises: {}", stats.exercise_count); println!("Total metadata records: {}", stats.metadata_count); println!("Total records: {}", stats.total_records()); println!("Database empty: {}", stats.is_empty()); println!("✅ Successfully retrieved database statistics!"); } // Helper function to create a sample path for testing fn create_sample_path() -> Path { let now = Utc::now(); let metadata = vec![Metadata { path_id: "test_path_001".to_string(), version: "1.0.0".to_string(), created_at: now, updated_at: now, }]; let exercises1 = vec![ Exercise { id: 1, ex_type: "vocabulary".to_string(), content: r#"{"word": "Hallo", "translation": "Hello", "audio": "/audio/hallo.mp3", "example": "Hallo, wie geht's?"}"#.to_string(), node_id: 1, }, Exercise { id: 2, ex_type: "multiple_choice".to_string(), content: r#"{"question": "How do you say 'goodbye' in German?", "options": ["Tschüss", "Hallo", "Bitte", "Danke"], "correct": 0, "explanation": "Tschüss is the informal way to say goodbye."}"#.to_string(), node_id: 1, } ]; let exercises2 = vec![Exercise { id: 3, ex_type: "vocabulary".to_string(), content: r#"{"word": "Danke", "translation": "Thank you", "audio": "/audio/danke.mp3", "example": "Danke schön!"}"#.to_string(), node_id: 2, }]; let nodes = vec![ Node { id: 1, title: "Basic Greetings".to_string(), description: "Learn essential German greetings".to_string(), path_id: "test_path_001".to_string(), exercises: exercises1, }, Node { id: 2, title: "Politeness".to_string(), description: "Learn polite expressions".to_string(), path_id: "test_path_001".to_string(), exercises: exercises2, }, ]; Path { id: "test_path_001".to_string(), title: "German Basics Test".to_string(), description: "A test path for demonstrating repository functionality".to_string(), metadata, nodes, } } } // Example usage functions (not tests) pub mod examples { use super::*; /// Example: How to use the repository manager in your application pub async fn example_basic_usage() { println!("=== Basic Repository Usage Example ==="); // This would normally use your actual database connection // let pool = get_database_pool().await; // let repo_manager = RepositoryManager::new(&pool); // Example operations: println!("1. Create repository manager"); println!("2. Save a new path"); println!("3. Retrieve and display path"); println!("4. Update path content"); println!("5. Search for paths"); println!("6. Generate statistics"); println!("7. Export to JSON"); println!("8. Cleanup/delete if needed"); } /// Example: How to work with JSON imports pub async fn example_json_workflow() { println!("=== JSON Import/Export Workflow ==="); // Steps for JSON workflow: println!("1. Validate JSON file structure"); println!("2. Import path from JSON"); println!("3. Verify import success"); println!("4. Make modifications if needed"); println!("5. Export updated version"); println!("6. Backup all paths to JSON files"); } /// Example: How to perform bulk operations pub async fn example_bulk_operations() { println!("=== Bulk Operations Example ==="); // Bulk operation examples: println!("1. Import multiple paths from directory"); println!("2. Validate all paths in database"); println!("3. Generate statistics for all paths"); println!("4. Search across all content"); println!("5. Export all paths to backup directory"); } }