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