the-code-graph-domain 0.1.2

Core domain types and traits for The Code Graph
Documentation
use crate::analysis::community::detect_communities;
use crate::error::Result;
use crate::model::{Community, CommunityAnalysis, CommunityConfig};
use crate::ports::GraphStore;

pub struct CommunityUseCase<S> {
    store: S,
}

impl<S: GraphStore> CommunityUseCase<S> {
    pub fn new(store: S) -> Self {
        Self { store }
    }

    pub fn analyze(&self, config: &CommunityConfig) -> Result<CommunityAnalysis> {
        let symbols = self.store.all_symbols()?;
        let edges = self.store.all_edges()?;
        Ok(detect_communities(&symbols, &edges, config))
    }

    pub fn community_of(
        &self,
        symbol: &str,
        config: &CommunityConfig,
    ) -> Result<Option<Community>> {
        let analysis = self.analyze(config)?;
        Ok(analysis
            .communities
            .into_iter()
            .find(|c| c.members.contains(&symbol.to_string())))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::model::*;
    use crate::test_support::InMemoryGraphStore;

    fn build_test_store() -> InMemoryGraphStore {
        let mut store = InMemoryGraphStore::new();
        for i in 0..3 {
            store.insert_symbol(SymbolNode {
                name: format!("a{i}"),
                qualified_name: format!("src/auth.rs::a{i}"),
                kind: SymbolKind::Function,
                location: Location {
                    file: "src/auth.rs".into(),
                    line_start: i * 10 + 1,
                    line_end: i * 10 + 10,
                    col_start: 0,
                    col_end: 0,
                },
                visibility: Visibility::Public,
                is_exported: true,
                is_async: false,
                is_test: false,
                decorators: vec![],
                signature: None,
            });
        }
        for i in 0..3 {
            for j in (i + 1)..3 {
                store.insert_edge(Edge {
                    kind: EdgeKind::Calls,
                    source: format!("src/auth.rs::a{i}"),
                    target: format!("src/auth.rs::a{j}"),
                    metadata: None,
                });
            }
        }
        store
    }

    #[test]
    fn analyze_returns_communities() {
        let store = build_test_store();
        let uc = CommunityUseCase::new(store);
        let result = uc.analyze(&CommunityConfig::default()).unwrap();
        assert!(result.stats.count > 0 || result.stats.isolated_nodes > 0);
    }

    #[test]
    fn community_of_finds_symbol() {
        let store = build_test_store();
        let uc = CommunityUseCase::new(store);
        let c = uc
            .community_of("src/auth.rs::a0", &CommunityConfig::default())
            .unwrap();
        assert!(c.is_some());
        assert!(c.unwrap().members.contains(&"src/auth.rs::a0".to_string()));
    }

    #[test]
    fn community_of_returns_none_for_unknown() {
        let store = build_test_store();
        let uc = CommunityUseCase::new(store);
        let c = uc
            .community_of("nonexistent::symbol", &CommunityConfig::default())
            .unwrap();
        assert!(c.is_none());
    }
}