sqlitegraph/backend/sqlite/
impl_.rs1use rusqlite::params;
7
8use crate::{
9 SqliteGraphError,
10 backend::sqlite::types::{BackendDirection, EdgeSpec, NeighborQuery, NodeSpec},
11 bfs::{bfs_neighbors, shortest_path},
12 graph::{GraphEdge, GraphEntity, SqliteGraph},
13 multi_hop,
14 pattern::{self, PatternMatch, PatternQuery},
15};
16
17pub struct SqliteGraphBackend {
22 graph: SqliteGraph,
23}
24
25impl SqliteGraphBackend {
26 pub fn in_memory() -> Result<Self, SqliteGraphError> {
28 Ok(Self {
29 graph: SqliteGraph::open_in_memory()?,
30 })
31 }
32
33 pub fn from_graph(graph: SqliteGraph) -> Self {
35 Self { graph }
36 }
37
38 pub fn graph(&self) -> &SqliteGraph {
40 &self.graph
41 }
42
43 pub fn entity_ids(&self) -> Result<Vec<i64>, SqliteGraphError> {
45 self.graph.all_entity_ids()
46 }
47
48 fn query_neighbors(
50 &self,
51 node: i64,
52 direction: BackendDirection,
53 edge_type: &Option<String>,
54 ) -> Result<Vec<i64>, SqliteGraphError> {
55 match (direction, edge_type) {
56 (BackendDirection::Outgoing, None) => self.graph.fetch_outgoing(node),
57 (BackendDirection::Incoming, None) => self.graph.fetch_incoming(node),
58 (BackendDirection::Outgoing, Some(edge_type)) => {
59 let conn = self.graph.connection();
60 let mut stmt = conn
61 .prepare_cached(
62 "SELECT to_id FROM graph_edges WHERE from_id=?1 AND edge_type=?2 ORDER BY to_id, id",
63 )
64 .map_err(|e| SqliteGraphError::query(e.to_string()))?;
65 let rows = stmt
66 .query_map(params![node, edge_type], |row| row.get(0))
67 .map_err(|e| SqliteGraphError::query(e.to_string()))?;
68 let mut values = Vec::new();
69 for value in rows {
70 values.push(value.map_err(|e| SqliteGraphError::query(e.to_string()))?);
71 }
72 Ok(values)
73 }
74 (BackendDirection::Incoming, Some(edge_type)) => {
75 let conn = self.graph.connection();
76 let mut stmt = conn
77 .prepare_cached(
78 "SELECT from_id FROM graph_edges WHERE to_id=?1 AND edge_type=?2 ORDER BY from_id, id",
79 )
80 .map_err(|e| SqliteGraphError::query(e.to_string()))?;
81 let rows = stmt
82 .query_map(params![node, edge_type], |row| row.get(0))
83 .map_err(|e| SqliteGraphError::query(e.to_string()))?;
84 let mut values = Vec::new();
85 for value in rows {
86 values.push(value.map_err(|e| SqliteGraphError::query(e.to_string()))?);
87 }
88 Ok(values)
89 }
90 }
91 }
92}
93
94impl crate::backend::GraphBackend for SqliteGraphBackend {
95 fn insert_node(&self, node: NodeSpec) -> Result<i64, SqliteGraphError> {
96 self.graph.insert_entity(&GraphEntity {
97 id: 0,
98 kind: node.kind,
99 name: node.name,
100 file_path: node.file_path,
101 data: node.data,
102 })
103 }
104
105 fn get_node(&self, id: i64) -> Result<GraphEntity, SqliteGraphError> {
106 self.graph.get_entity(id)
107 }
108
109 fn insert_edge(&self, edge: EdgeSpec) -> Result<i64, SqliteGraphError> {
110 self.graph.insert_edge(&GraphEdge {
111 id: 0,
112 from_id: edge.from,
113 to_id: edge.to,
114 edge_type: edge.edge_type,
115 data: edge.data,
116 })
117 }
118
119 fn neighbors(&self, node: i64, query: NeighborQuery) -> Result<Vec<i64>, SqliteGraphError> {
120 self.query_neighbors(node, query.direction, &query.edge_type)
121 }
122
123 fn bfs(&self, start: i64, depth: u32) -> Result<Vec<i64>, SqliteGraphError> {
124 if let Some(cached_result) = self.graph.query_cache.get_bfs(start, depth) {
126 return Ok(cached_result);
127 }
128
129 let result = bfs_neighbors(&self.graph, start, depth)?;
131 self.graph.query_cache.put_bfs(start, depth, result.clone());
132 Ok(result)
133 }
134
135 fn shortest_path(&self, start: i64, end: i64) -> Result<Option<Vec<i64>>, SqliteGraphError> {
136 if let Some(cached_result) = self.graph.query_cache.get_shortest_path(start, end) {
138 return Ok(cached_result);
139 }
140
141 let result = shortest_path(&self.graph, start, end)?;
143 self.graph
144 .query_cache
145 .put_shortest_path(start, end, result.clone());
146 Ok(result)
147 }
148
149 fn node_degree(&self, node: i64) -> Result<(usize, usize), SqliteGraphError> {
150 let out = self.graph.fetch_outgoing(node)?.len();
151 let incoming = self.graph.fetch_incoming(node)?.len();
152 Ok((out, incoming))
153 }
154
155 fn k_hop(
156 &self,
157 start: i64,
158 depth: u32,
159 direction: BackendDirection,
160 ) -> Result<Vec<i64>, SqliteGraphError> {
161 if let Some(cached_result) = self.graph.query_cache.get_k_hop(start, depth, direction) {
163 return Ok(cached_result);
164 }
165
166 let result = multi_hop::k_hop(&self.graph, start, depth, direction)?;
168 self.graph
169 .query_cache
170 .put_k_hop(start, depth, direction, result.clone());
171 Ok(result)
172 }
173
174 fn k_hop_filtered(
175 &self,
176 start: i64,
177 depth: u32,
178 direction: BackendDirection,
179 allowed_edge_types: &[&str],
180 ) -> Result<Vec<i64>, SqliteGraphError> {
181 if let Some(cached_result) =
183 self.graph
184 .query_cache
185 .get_k_hop_filtered(start, depth, direction, allowed_edge_types)
186 {
187 return Ok(cached_result);
188 }
189
190 let result =
192 multi_hop::k_hop_filtered(&self.graph, start, depth, direction, allowed_edge_types)?;
193 self.graph.query_cache.put_k_hop_filtered(
194 start,
195 depth,
196 direction,
197 allowed_edge_types,
198 result.clone(),
199 );
200 Ok(result)
201 }
202
203 fn chain_query(
204 &self,
205 start: i64,
206 chain: &[crate::multi_hop::ChainStep],
207 ) -> Result<Vec<i64>, SqliteGraphError> {
208 multi_hop::chain_query(&self.graph, start, chain)
209 }
210
211 fn pattern_search(
212 &self,
213 start: i64,
214 pattern: &PatternQuery,
215 ) -> Result<Vec<PatternMatch>, SqliteGraphError> {
216 pattern::execute_pattern(&self.graph, start, pattern)
217 }
218}