Skip to main content

graphify_export/
json.rs

1//! NetworkX node_link_data compatible JSON export.
2
3use std::fs;
4use std::io::BufWriter;
5use std::path::{Path, PathBuf};
6
7use graphify_core::graph::KnowledgeGraph;
8use tracing::info;
9
10/// Export graph to `graph.json` in NetworkX `node_link_data` format.
11///
12/// Uses streaming serialization via `BufWriter` to avoid building the entire
13/// JSON string in memory. For large graphs (50K+ nodes) this reduces peak
14/// memory by ~500 MB compared to `to_string_pretty()`.
15pub fn export_json(graph: &KnowledgeGraph, output_dir: &Path) -> anyhow::Result<PathBuf> {
16    fs::create_dir_all(output_dir)?;
17    let path = output_dir.join("graph.json");
18    let file = fs::File::create(&path)?;
19    let writer = BufWriter::new(file);
20    graph.write_node_link_json(writer)?;
21    info!(path = %path.display(), "exported graph JSON");
22    Ok(path)
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28    use graphify_core::confidence::Confidence;
29    use graphify_core::model::{GraphEdge, GraphNode, NodeType};
30    use std::collections::HashMap;
31
32    fn sample_graph() -> KnowledgeGraph {
33        let mut kg = KnowledgeGraph::new();
34        kg.add_node(GraphNode {
35            id: "a".into(),
36            label: "A".into(),
37            source_file: "test.rs".into(),
38            source_location: None,
39            node_type: NodeType::Class,
40            community: None,
41            extra: HashMap::new(),
42        })
43        .unwrap();
44        kg.add_node(GraphNode {
45            id: "b".into(),
46            label: "B".into(),
47            source_file: "test.rs".into(),
48            source_location: None,
49            node_type: NodeType::Function,
50            community: None,
51            extra: HashMap::new(),
52        })
53        .unwrap();
54        kg.add_edge(GraphEdge {
55            source: "a".into(),
56            target: "b".into(),
57            relation: "calls".into(),
58            confidence: Confidence::Extracted,
59            confidence_score: 1.0,
60            source_file: "test.rs".into(),
61            source_location: None,
62            weight: 1.0,
63            extra: HashMap::new(),
64        })
65        .unwrap();
66        kg
67    }
68
69    #[test]
70    fn export_json_creates_file() {
71        let dir = tempfile::tempdir().unwrap();
72        let kg = sample_graph();
73        let path = export_json(&kg, dir.path()).unwrap();
74        assert!(path.exists());
75
76        let content: serde_json::Value =
77            serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap();
78        assert_eq!(content["nodes"].as_array().unwrap().len(), 2);
79        assert_eq!(content["links"].as_array().unwrap().len(), 1);
80    }
81}