Skip to main content

lean_ctx/core/property_graph/
edge.rs

1//! Edge types and CRUD operations for graph edges.
2
3use rusqlite::{params, Connection};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum EdgeKind {
7    Imports,
8    Calls,
9    Defines,
10    Exports,
11    TypeRef,
12    TestedBy,
13    ChangedIn,
14    BuiltIn,
15    MentionedIn,
16    Affects,
17    Breaks,
18}
19
20impl EdgeKind {
21    pub fn as_str(&self) -> &'static str {
22        match self {
23            Self::Imports => "imports",
24            Self::Calls => "calls",
25            Self::Defines => "defines",
26            Self::Exports => "exports",
27            Self::TypeRef => "type_ref",
28            Self::TestedBy => "tested_by",
29            Self::ChangedIn => "changed_in",
30            Self::BuiltIn => "built_in",
31            Self::MentionedIn => "mentioned_in",
32            Self::Affects => "affects",
33            Self::Breaks => "breaks",
34        }
35    }
36
37    pub fn parse(s: &str) -> Self {
38        match s {
39            "calls" => Self::Calls,
40            "defines" => Self::Defines,
41            "exports" => Self::Exports,
42            "type_ref" => Self::TypeRef,
43            "tested_by" => Self::TestedBy,
44            "changed_in" => Self::ChangedIn,
45            "built_in" => Self::BuiltIn,
46            "mentioned_in" => Self::MentionedIn,
47            "affects" => Self::Affects,
48            "breaks" => Self::Breaks,
49            _ => Self::Imports,
50        }
51    }
52}
53
54#[derive(Debug, Clone)]
55pub struct Edge {
56    pub id: Option<i64>,
57    pub source_id: i64,
58    pub target_id: i64,
59    pub kind: EdgeKind,
60    pub metadata: Option<String>,
61}
62
63impl Edge {
64    pub fn new(source_id: i64, target_id: i64, kind: EdgeKind) -> Self {
65        Self {
66            id: None,
67            source_id,
68            target_id,
69            kind,
70            metadata: None,
71        }
72    }
73
74    pub fn with_metadata(mut self, meta: &str) -> Self {
75        self.metadata = Some(meta.to_string());
76        self
77    }
78}
79
80pub(super) fn upsert(conn: &Connection, edge: &Edge) -> anyhow::Result<()> {
81    conn.execute(
82        "INSERT INTO edges (source_id, target_id, kind, metadata)
83         VALUES (?1, ?2, ?3, ?4)
84         ON CONFLICT(source_id, target_id, kind) DO UPDATE SET
85            metadata = excluded.metadata",
86        params![
87            edge.source_id,
88            edge.target_id,
89            edge.kind.as_str(),
90            edge.metadata,
91        ],
92    )?;
93    Ok(())
94}
95
96pub(super) fn from_node(conn: &Connection, node_id: i64) -> anyhow::Result<Vec<Edge>> {
97    let mut stmt = conn.prepare(
98        "SELECT id, source_id, target_id, kind, metadata
99         FROM edges WHERE source_id = ?1",
100    )?;
101    let edges = stmt
102        .query_map(params![node_id], |row| {
103            Ok(Edge {
104                id: Some(row.get(0)?),
105                source_id: row.get(1)?,
106                target_id: row.get(2)?,
107                kind: EdgeKind::parse(&row.get::<_, String>(3)?),
108                metadata: row.get(4)?,
109            })
110        })?
111        .filter_map(std::result::Result::ok)
112        .collect();
113    Ok(edges)
114}
115
116pub(super) fn to_node(conn: &Connection, node_id: i64) -> anyhow::Result<Vec<Edge>> {
117    let mut stmt = conn.prepare(
118        "SELECT id, source_id, target_id, kind, metadata
119         FROM edges WHERE target_id = ?1",
120    )?;
121    let edges = stmt
122        .query_map(params![node_id], |row| {
123            Ok(Edge {
124                id: Some(row.get(0)?),
125                source_id: row.get(1)?,
126                target_id: row.get(2)?,
127                kind: EdgeKind::parse(&row.get::<_, String>(3)?),
128                metadata: row.get(4)?,
129            })
130        })?
131        .filter_map(std::result::Result::ok)
132        .collect();
133    Ok(edges)
134}
135
136pub(super) fn count(conn: &Connection) -> anyhow::Result<usize> {
137    let c: i64 = conn.query_row("SELECT COUNT(*) FROM edges", [], |row| row.get(0))?;
138    Ok(c as usize)
139}