turbovault_tools/
analysis_tools.rs1use serde_json::json;
4use std::sync::Arc;
5use turbovault_core::prelude::*;
6use turbovault_vault::VaultManager;
7
8pub struct AnalysisTools {
10 pub manager: Arc<VaultManager>,
11}
12
13#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
15pub struct VaultStats {
16 pub total_files: usize,
17 pub total_links: usize,
18 pub orphaned_files: usize,
19 pub average_links_per_file: f64,
20}
21
22impl AnalysisTools {
23 pub fn new(manager: Arc<VaultManager>) -> Self {
25 Self { manager }
26 }
27
28 pub async fn get_vault_stats(&self) -> Result<VaultStats> {
30 let stats = self.manager.get_stats().await?;
31
32 Ok(VaultStats {
33 total_files: stats.total_files,
34 total_links: stats.total_links,
35 orphaned_files: stats.orphaned_files,
36 average_links_per_file: stats.average_links_per_file,
37 })
38 }
39
40 pub async fn list_orphaned_notes(&self) -> Result<Vec<String>> {
42 let orphans = self.manager.get_orphaned_notes().await?;
43
44 Ok(orphans
45 .into_iter()
46 .filter_map(|p| p.to_str().map(|s| s.to_string()))
47 .collect())
48 }
49
50 pub async fn detect_cycles(&self) -> Result<Vec<Vec<String>>> {
52 let graph = self.manager.link_graph();
53 let graph_read = graph.read().await;
54
55 let cycles = graph_read
56 .cycles()
57 .into_iter()
58 .map(|cycle| {
59 cycle
60 .into_iter()
61 .filter_map(|p| p.to_str().map(|s| s.to_string()))
62 .collect()
63 })
64 .collect();
65
66 Ok(cycles)
67 }
68
69 pub async fn get_link_density(&self) -> Result<f64> {
71 let stats = self.manager.get_stats().await?;
72
73 if stats.total_files <= 1 {
76 return Ok(0.0);
77 }
78
79 let possible_links = (stats.total_files as f64) * ((stats.total_files as f64) - 1.0);
80 let density = (stats.total_links as f64) / possible_links;
81
82 Ok(density)
83 }
84
85 pub async fn get_connectivity_metrics(&self) -> Result<serde_json::Value> {
87 let stats = self.manager.get_stats().await?;
88 let density = self.get_link_density().await?;
89
90 Ok(json!({
91 "total_files": stats.total_files,
92 "total_links": stats.total_links,
93 "orphaned_files": stats.orphaned_files,
94 "connected_files": stats.total_files - stats.orphaned_files,
95 "average_links_per_file": stats.average_links_per_file,
96 "link_density": density,
97 "connectivity_rate": if stats.total_files > 0 {
98 (stats.total_files - stats.orphaned_files) as f64 / stats.total_files as f64
99 } else {
100 0.0
101 }
102 }))
103 }
104}