the_code_graph_domain/use_cases/
community.rs1use crate::analysis::community::detect_communities;
2use crate::error::Result;
3use crate::model::{Community, CommunityAnalysis, CommunityConfig};
4use crate::ports::GraphStore;
5
6pub struct CommunityUseCase<S> {
7 store: S,
8}
9
10impl<S: GraphStore> CommunityUseCase<S> {
11 pub fn new(store: S) -> Self {
12 Self { store }
13 }
14
15 pub fn analyze(&self, config: &CommunityConfig) -> Result<CommunityAnalysis> {
16 let symbols = self.store.all_symbols()?;
17 let edges = self.store.all_edges()?;
18 Ok(detect_communities(&symbols, &edges, config))
19 }
20
21 pub fn community_of(
22 &self,
23 symbol: &str,
24 config: &CommunityConfig,
25 ) -> Result<Option<Community>> {
26 let analysis = self.analyze(config)?;
27 Ok(analysis
28 .communities
29 .into_iter()
30 .find(|c| c.members.contains(&symbol.to_string())))
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::model::*;
38 use crate::test_support::InMemoryGraphStore;
39
40 fn build_test_store() -> InMemoryGraphStore {
41 let mut store = InMemoryGraphStore::new();
42 for i in 0..3 {
43 store.insert_symbol(SymbolNode {
44 name: format!("a{i}"),
45 qualified_name: format!("src/auth.rs::a{i}"),
46 kind: SymbolKind::Function,
47 location: Location {
48 file: "src/auth.rs".into(),
49 line_start: i * 10 + 1,
50 line_end: i * 10 + 10,
51 col_start: 0,
52 col_end: 0,
53 },
54 visibility: Visibility::Public,
55 is_exported: true,
56 is_async: false,
57 is_test: false,
58 decorators: vec![],
59 signature: None,
60 });
61 }
62 for i in 0..3 {
63 for j in (i + 1)..3 {
64 store.insert_edge(Edge {
65 kind: EdgeKind::Calls,
66 source: format!("src/auth.rs::a{i}"),
67 target: format!("src/auth.rs::a{j}"),
68 metadata: None,
69 });
70 }
71 }
72 store
73 }
74
75 #[test]
76 fn analyze_returns_communities() {
77 let store = build_test_store();
78 let uc = CommunityUseCase::new(store);
79 let result = uc.analyze(&CommunityConfig::default()).unwrap();
80 assert!(result.stats.count > 0 || result.stats.isolated_nodes > 0);
81 }
82
83 #[test]
84 fn community_of_finds_symbol() {
85 let store = build_test_store();
86 let uc = CommunityUseCase::new(store);
87 let c = uc
88 .community_of("src/auth.rs::a0", &CommunityConfig::default())
89 .unwrap();
90 assert!(c.is_some());
91 assert!(c.unwrap().members.contains(&"src/auth.rs::a0".to_string()));
92 }
93
94 #[test]
95 fn community_of_returns_none_for_unknown() {
96 let store = build_test_store();
97 let uc = CommunityUseCase::new(store);
98 let c = uc
99 .community_of("nonexistent::symbol", &CommunityConfig::default())
100 .unwrap();
101 assert!(c.is_none());
102 }
103}