1use crate::edge::Edge;
6use crate::hyperedge::{Hyperedge, HyperedgeId};
7use crate::node::Node;
8use crate::types::{EdgeId, NodeId, PropertyValue};
9use dashmap::DashMap;
10use std::collections::HashSet;
11use std::sync::Arc;
12
13#[derive(Debug, Clone)]
15pub struct LabelIndex {
16 index: Arc<DashMap<String, HashSet<NodeId>>>,
18}
19
20impl LabelIndex {
21 pub fn new() -> Self {
23 Self {
24 index: Arc::new(DashMap::new()),
25 }
26 }
27
28 pub fn add_node(&self, node: &Node) {
30 for label in &node.labels {
31 self.index
32 .entry(label.name.clone())
33 .or_insert_with(HashSet::new)
34 .insert(node.id.clone());
35 }
36 }
37
38 pub fn remove_node(&self, node: &Node) {
40 for label in &node.labels {
41 if let Some(mut set) = self.index.get_mut(&label.name) {
42 set.remove(&node.id);
43 }
44 }
45 }
46
47 pub fn get_nodes_by_label(&self, label: &str) -> Vec<NodeId> {
49 self.index
50 .get(label)
51 .map(|set| set.iter().cloned().collect())
52 .unwrap_or_default()
53 }
54
55 pub fn all_labels(&self) -> Vec<String> {
57 self.index.iter().map(|entry| entry.key().clone()).collect()
58 }
59
60 pub fn count_by_label(&self, label: &str) -> usize {
62 self.index.get(label).map(|set| set.len()).unwrap_or(0)
63 }
64
65 pub fn clear(&self) {
67 self.index.clear();
68 }
69}
70
71impl Default for LabelIndex {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct PropertyIndex {
80 index: Arc<DashMap<String, DashMap<String, HashSet<NodeId>>>>,
82}
83
84impl PropertyIndex {
85 pub fn new() -> Self {
87 Self {
88 index: Arc::new(DashMap::new()),
89 }
90 }
91
92 pub fn add_node(&self, node: &Node) {
94 for (key, value) in &node.properties {
95 let value_str = self.property_value_to_string(value);
96 self.index
97 .entry(key.clone())
98 .or_insert_with(DashMap::new)
99 .entry(value_str)
100 .or_insert_with(HashSet::new)
101 .insert(node.id.clone());
102 }
103 }
104
105 pub fn remove_node(&self, node: &Node) {
107 for (key, value) in &node.properties {
108 let value_str = self.property_value_to_string(value);
109 if let Some(value_map) = self.index.get(key) {
110 if let Some(mut set) = value_map.get_mut(&value_str) {
111 set.remove(&node.id);
112 }
113 }
114 }
115 }
116
117 pub fn get_nodes_by_property(&self, key: &str, value: &PropertyValue) -> Vec<NodeId> {
119 let value_str = self.property_value_to_string(value);
120 self.index
121 .get(key)
122 .and_then(|value_map| {
123 value_map
124 .get(&value_str)
125 .map(|set| set.iter().cloned().collect())
126 })
127 .unwrap_or_default()
128 }
129
130 pub fn get_nodes_with_property(&self, key: &str) -> Vec<NodeId> {
132 self.index
133 .get(key)
134 .map(|value_map| {
135 let mut result = HashSet::new();
136 for entry in value_map.iter() {
137 for id in entry.value().iter() {
138 result.insert(id.clone());
139 }
140 }
141 result.into_iter().collect()
142 })
143 .unwrap_or_default()
144 }
145
146 pub fn all_property_keys(&self) -> Vec<String> {
148 self.index.iter().map(|entry| entry.key().clone()).collect()
149 }
150
151 pub fn clear(&self) {
153 self.index.clear();
154 }
155
156 fn property_value_to_string(&self, value: &PropertyValue) -> String {
158 match value {
159 PropertyValue::Null => "null".to_string(),
160 PropertyValue::Boolean(b) => b.to_string(),
161 PropertyValue::Integer(i) => i.to_string(),
162 PropertyValue::Float(f) => f.to_string(),
163 PropertyValue::String(s) => s.clone(),
164 PropertyValue::Array(_) | PropertyValue::List(_) => format!("{:?}", value),
165 PropertyValue::Map(_) => format!("{:?}", value),
166 }
167 }
168}
169
170impl Default for PropertyIndex {
171 fn default() -> Self {
172 Self::new()
173 }
174}
175
176#[derive(Debug, Clone)]
178pub struct EdgeTypeIndex {
179 index: Arc<DashMap<String, HashSet<EdgeId>>>,
181}
182
183impl EdgeTypeIndex {
184 pub fn new() -> Self {
186 Self {
187 index: Arc::new(DashMap::new()),
188 }
189 }
190
191 pub fn add_edge(&self, edge: &Edge) {
193 self.index
194 .entry(edge.edge_type.clone())
195 .or_insert_with(HashSet::new)
196 .insert(edge.id.clone());
197 }
198
199 pub fn remove_edge(&self, edge: &Edge) {
201 if let Some(mut set) = self.index.get_mut(&edge.edge_type) {
202 set.remove(&edge.id);
203 }
204 }
205
206 pub fn get_edges_by_type(&self, edge_type: &str) -> Vec<EdgeId> {
208 self.index
209 .get(edge_type)
210 .map(|set| set.iter().cloned().collect())
211 .unwrap_or_default()
212 }
213
214 pub fn all_edge_types(&self) -> Vec<String> {
216 self.index.iter().map(|entry| entry.key().clone()).collect()
217 }
218
219 pub fn count_by_type(&self, edge_type: &str) -> usize {
221 self.index.get(edge_type).map(|set| set.len()).unwrap_or(0)
222 }
223
224 pub fn clear(&self) {
226 self.index.clear();
227 }
228}
229
230impl Default for EdgeTypeIndex {
231 fn default() -> Self {
232 Self::new()
233 }
234}
235
236#[derive(Debug, Clone)]
238pub struct AdjacencyIndex {
239 outgoing: Arc<DashMap<NodeId, HashSet<EdgeId>>>,
241 incoming: Arc<DashMap<NodeId, HashSet<EdgeId>>>,
243}
244
245impl AdjacencyIndex {
246 pub fn new() -> Self {
248 Self {
249 outgoing: Arc::new(DashMap::new()),
250 incoming: Arc::new(DashMap::new()),
251 }
252 }
253
254 pub fn add_edge(&self, edge: &Edge) {
256 self.outgoing
257 .entry(edge.from.clone())
258 .or_insert_with(HashSet::new)
259 .insert(edge.id.clone());
260
261 self.incoming
262 .entry(edge.to.clone())
263 .or_insert_with(HashSet::new)
264 .insert(edge.id.clone());
265 }
266
267 pub fn remove_edge(&self, edge: &Edge) {
269 if let Some(mut set) = self.outgoing.get_mut(&edge.from) {
270 set.remove(&edge.id);
271 }
272 if let Some(mut set) = self.incoming.get_mut(&edge.to) {
273 set.remove(&edge.id);
274 }
275 }
276
277 pub fn get_outgoing_edges(&self, node_id: &NodeId) -> Vec<EdgeId> {
279 self.outgoing
280 .get(node_id)
281 .map(|set| set.iter().cloned().collect())
282 .unwrap_or_default()
283 }
284
285 pub fn get_incoming_edges(&self, node_id: &NodeId) -> Vec<EdgeId> {
287 self.incoming
288 .get(node_id)
289 .map(|set| set.iter().cloned().collect())
290 .unwrap_or_default()
291 }
292
293 pub fn get_all_edges(&self, node_id: &NodeId) -> Vec<EdgeId> {
295 let mut edges = self.get_outgoing_edges(node_id);
296 edges.extend(self.get_incoming_edges(node_id));
297 edges
298 }
299
300 pub fn out_degree(&self, node_id: &NodeId) -> usize {
302 self.outgoing.get(node_id).map(|set| set.len()).unwrap_or(0)
303 }
304
305 pub fn in_degree(&self, node_id: &NodeId) -> usize {
307 self.incoming.get(node_id).map(|set| set.len()).unwrap_or(0)
308 }
309
310 pub fn clear(&self) {
312 self.outgoing.clear();
313 self.incoming.clear();
314 }
315}
316
317impl Default for AdjacencyIndex {
318 fn default() -> Self {
319 Self::new()
320 }
321}
322
323#[derive(Debug, Clone)]
325pub struct HyperedgeNodeIndex {
326 index: Arc<DashMap<NodeId, HashSet<HyperedgeId>>>,
328}
329
330impl HyperedgeNodeIndex {
331 pub fn new() -> Self {
333 Self {
334 index: Arc::new(DashMap::new()),
335 }
336 }
337
338 pub fn add_hyperedge(&self, hyperedge: &Hyperedge) {
340 for node_id in &hyperedge.nodes {
341 self.index
342 .entry(node_id.clone())
343 .or_insert_with(HashSet::new)
344 .insert(hyperedge.id.clone());
345 }
346 }
347
348 pub fn remove_hyperedge(&self, hyperedge: &Hyperedge) {
350 for node_id in &hyperedge.nodes {
351 if let Some(mut set) = self.index.get_mut(node_id) {
352 set.remove(&hyperedge.id);
353 }
354 }
355 }
356
357 pub fn get_hyperedges_by_node(&self, node_id: &NodeId) -> Vec<HyperedgeId> {
359 self.index
360 .get(node_id)
361 .map(|set| set.iter().cloned().collect())
362 .unwrap_or_default()
363 }
364
365 pub fn clear(&self) {
367 self.index.clear();
368 }
369}
370
371impl Default for HyperedgeNodeIndex {
372 fn default() -> Self {
373 Self::new()
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::*;
380 use crate::node::NodeBuilder;
381
382 #[test]
383 fn test_label_index() {
384 let index = LabelIndex::new();
385
386 let node1 = NodeBuilder::new().label("Person").label("User").build();
387
388 let node2 = NodeBuilder::new().label("Person").build();
389
390 index.add_node(&node1);
391 index.add_node(&node2);
392
393 let people = index.get_nodes_by_label("Person");
394 assert_eq!(people.len(), 2);
395
396 let users = index.get_nodes_by_label("User");
397 assert_eq!(users.len(), 1);
398
399 assert_eq!(index.count_by_label("Person"), 2);
400 }
401
402 #[test]
403 fn test_property_index() {
404 let index = PropertyIndex::new();
405
406 let node1 = NodeBuilder::new()
407 .property("name", "Alice")
408 .property("age", 30i64)
409 .build();
410
411 let node2 = NodeBuilder::new()
412 .property("name", "Bob")
413 .property("age", 30i64)
414 .build();
415
416 index.add_node(&node1);
417 index.add_node(&node2);
418
419 let alice =
420 index.get_nodes_by_property("name", &PropertyValue::String("Alice".to_string()));
421 assert_eq!(alice.len(), 1);
422
423 let age_30 = index.get_nodes_by_property("age", &PropertyValue::Integer(30));
424 assert_eq!(age_30.len(), 2);
425
426 let with_age = index.get_nodes_with_property("age");
427 assert_eq!(with_age.len(), 2);
428 }
429
430 #[test]
431 fn test_edge_type_index() {
432 let index = EdgeTypeIndex::new();
433
434 let edge1 = Edge::create("n1".to_string(), "n2".to_string(), "KNOWS");
435 let edge2 = Edge::create("n2".to_string(), "n3".to_string(), "KNOWS");
436 let edge3 = Edge::create("n1".to_string(), "n3".to_string(), "WORKS_WITH");
437
438 index.add_edge(&edge1);
439 index.add_edge(&edge2);
440 index.add_edge(&edge3);
441
442 let knows_edges = index.get_edges_by_type("KNOWS");
443 assert_eq!(knows_edges.len(), 2);
444
445 let works_with_edges = index.get_edges_by_type("WORKS_WITH");
446 assert_eq!(works_with_edges.len(), 1);
447
448 assert_eq!(index.all_edge_types().len(), 2);
449 }
450
451 #[test]
452 fn test_adjacency_index() {
453 let index = AdjacencyIndex::new();
454
455 let edge1 = Edge::create("n1".to_string(), "n2".to_string(), "KNOWS");
456 let edge2 = Edge::create("n1".to_string(), "n3".to_string(), "KNOWS");
457 let edge3 = Edge::create("n2".to_string(), "n1".to_string(), "KNOWS");
458
459 index.add_edge(&edge1);
460 index.add_edge(&edge2);
461 index.add_edge(&edge3);
462
463 assert_eq!(index.out_degree(&"n1".to_string()), 2);
464 assert_eq!(index.in_degree(&"n1".to_string()), 1);
465
466 let outgoing = index.get_outgoing_edges(&"n1".to_string());
467 assert_eq!(outgoing.len(), 2);
468
469 let incoming = index.get_incoming_edges(&"n1".to_string());
470 assert_eq!(incoming.len(), 1);
471 }
472}