lean_ctx/core/property_graph/
edge.rs1use 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 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 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 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 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}