Skip to main content

lean_ctx/core/property_graph/
meta.rs

1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(default)]
6pub struct PropertyGraphMetaV1 {
7    pub schema_version: u32,
8    /// Property-graph engine generation that produced this graph (see
9    /// [`super::GRAPH_ENGINE_VERSION`]). Bumped whenever edge extraction
10    /// changes, so a graph built by an older engine — e.g. before the C#/Java
11    /// `type_ref` edges existed (GH #398) — is rebuilt instead of silently
12    /// served without the new edges. Graphs written before this field existed
13    /// deserialize to `0`.
14    pub engine_version: u32,
15    /// lean-ctx version (`CARGO_PKG_VERSION`) that built this graph, recorded
16    /// for diagnostics. Empty for graphs written before the stamp existed.
17    pub built_with: String,
18    /// RFC3339 timestamp (UTC) of the last successful build.
19    pub built_at: String,
20    /// Git HEAD (short) at build time, if available.
21    pub git_head: Option<String>,
22    /// Git dirty flag at build time, if available.
23    pub git_dirty: Option<bool>,
24    /// Node count after build.
25    pub nodes: Option<usize>,
26    /// Edge count after build.
27    pub edges: Option<usize>,
28    /// Number of source files processed during build (before filtering).
29    pub files_indexed: Option<usize>,
30    /// Build duration in milliseconds (best-effort).
31    pub build_time_ms: Option<u64>,
32}
33
34impl Default for PropertyGraphMetaV1 {
35    fn default() -> Self {
36        Self {
37            schema_version: 1,
38            engine_version: 0,
39            built_with: String::new(),
40            built_at: String::new(),
41            git_head: None,
42            git_dirty: None,
43            nodes: None,
44            edges: None,
45            files_indexed: None,
46            build_time_ms: None,
47        }
48    }
49}
50
51pub fn meta_path(project_root: &str) -> PathBuf {
52    super::graph_dir(project_root).join("graph.meta.json")
53}
54
55pub fn load_meta(project_root: &str) -> Option<PropertyGraphMetaV1> {
56    let path = meta_path(project_root);
57    let s = std::fs::read_to_string(path).ok()?;
58    let meta: PropertyGraphMetaV1 = serde_json::from_str(&s).ok()?;
59    if meta.schema_version != 1 || meta.built_at.trim().is_empty() {
60        return None;
61    }
62    Some(meta)
63}
64
65pub fn write_meta(project_root: &str, meta: &PropertyGraphMetaV1) -> Result<PathBuf, String> {
66    let path = meta_path(project_root);
67    if let Some(parent) = path.parent() {
68        std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
69    }
70    let json = serde_json::to_string_pretty(meta).map_err(|e| e.to_string())?;
71    crate::config_io::write_atomic(&path, &json)?;
72    Ok(path)
73}