1use std::collections::BTreeSet;
6
7use lora_ast::Direction;
8
9use crate::{
10 BorrowedGraphStorage, GraphStorage, GraphStorageMut, MutationEvent, NodeId, NodeRecord,
11 Properties, PropertyValue, RelationshipId, RelationshipRecord,
12};
13
14use super::property_index::PropertyIndexKey;
15use super::InMemoryGraph;
16
17impl GraphStorage for InMemoryGraph {
18 fn contains_node(&self, id: NodeId) -> bool {
21 self.node_at(id).is_some()
22 }
23
24 fn node(&self, id: NodeId) -> Option<NodeRecord> {
25 self.node_at(id).cloned()
26 }
27
28 fn all_node_ids(&self) -> Vec<NodeId> {
29 self.iter_node_ids().collect()
30 }
31
32 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId> {
33 match self.nodes_by_label.get(label) {
34 Some(ids) => ids.clone(),
35 None => Vec::new(),
36 }
37 }
38
39 fn contains_relationship(&self, id: RelationshipId) -> bool {
40 self.rel_at(id).is_some()
41 }
42
43 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
44 self.rel_at(id).cloned()
45 }
46
47 fn all_rel_ids(&self) -> Vec<RelationshipId> {
48 self.iter_rel_ids().collect()
49 }
50
51 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
52 match self.relationships_by_type.get(rel_type) {
53 Some(ids) => ids.clone(),
54 None => Vec::new(),
55 }
56 }
57
58 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)> {
59 self.rel_at(id).map(|r| (r.src, r.dst))
60 }
61
62 fn expand_ids(
63 &self,
64 node_id: NodeId,
65 direction: Direction,
66 types: &[String],
67 ) -> Vec<(RelationshipId, NodeId)> {
68 if self.node_at(node_id).is_none() {
69 return Vec::new();
70 }
71
72 let mut out: Vec<(RelationshipId, NodeId)> = Vec::new();
78
79 let push_from = |adj: &Vec<RelationshipId>, out: &mut Vec<(RelationshipId, NodeId)>| {
80 for &rel_id in adj {
81 let Some(rel) = self.rel_at(rel_id) else {
82 continue;
83 };
84 if !types.is_empty() && !types.iter().any(|t| t == &rel.rel_type) {
85 continue;
86 }
87 let Some(other_id) = Self::other_endpoint(rel, node_id) else {
88 continue;
89 };
90 out.push((rel_id, other_id));
91 }
92 };
93
94 match direction {
95 Direction::Right => {
96 if let Some(adj) = self.outgoing_at(node_id) {
97 out.reserve(adj.len());
98 push_from(adj, &mut out);
99 }
100 }
101 Direction::Left => {
102 if let Some(adj) = self.incoming_at(node_id) {
103 out.reserve(adj.len());
104 push_from(adj, &mut out);
105 }
106 }
107 Direction::Undirected => {
108 let out_len = self.outgoing_at(node_id).map(Vec::len).unwrap_or(0);
109 let in_len = self.incoming_at(node_id).map(Vec::len).unwrap_or(0);
110 out.reserve(out_len + in_len);
111 if let Some(adj) = self.outgoing_at(node_id) {
112 push_from(adj, &mut out);
113 }
114 if let Some(adj) = self.incoming_at(node_id) {
115 for &rel_id in adj {
117 if out.iter().any(|(r, _)| *r == rel_id) {
118 continue;
119 }
120 let Some(rel) = self.rel_at(rel_id) else {
121 continue;
122 };
123 if !types.is_empty() && !types.iter().any(|t| t == &rel.rel_type) {
124 continue;
125 }
126 let Some(other_id) = Self::other_endpoint(rel, node_id) else {
127 continue;
128 };
129 out.push((rel_id, other_id));
130 }
131 }
132 }
133 }
134 out
135 }
136
137 fn all_labels(&self) -> Vec<String> {
138 self.nodes_by_label.keys().cloned().collect()
139 }
140
141 fn all_relationship_types(&self) -> Vec<String> {
142 self.relationships_by_type.keys().cloned().collect()
143 }
144
145 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
148 where
149 F: FnOnce(&NodeRecord) -> R,
150 Self: Sized,
151 {
152 self.node_at(id).map(f)
153 }
154
155 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
156 where
157 F: FnOnce(&RelationshipRecord) -> R,
158 Self: Sized,
159 {
160 self.rel_at(id).map(f)
161 }
162
163 fn has_node(&self, id: NodeId) -> bool {
166 self.node_at(id).is_some()
167 }
168
169 fn has_relationship(&self, id: RelationshipId) -> bool {
170 self.rel_at(id).is_some()
171 }
172
173 fn node_count(&self) -> usize {
174 self.live_node_count
175 }
176
177 fn relationship_count(&self) -> usize {
178 self.live_rel_count
179 }
180
181 fn all_nodes(&self) -> Vec<NodeRecord> {
184 self.iter_node_records().cloned().collect()
185 }
186
187 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
188 self.nodes_by_label
189 .get(label)
190 .into_iter()
191 .flat_map(|ids| ids.iter())
192 .filter_map(|&id| self.node_at(id).cloned())
193 .collect()
194 }
195
196 fn all_relationships(&self) -> Vec<RelationshipRecord> {
197 self.iter_rel_records().cloned().collect()
198 }
199
200 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
201 self.relationships_by_type
202 .get(rel_type)
203 .into_iter()
204 .flat_map(|ids| ids.iter())
205 .filter_map(|&id| self.rel_at(id).cloned())
206 .collect()
207 }
208
209 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
210 self.relationship_ids_for_direction(node_id, direction)
211 }
212
213 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
214 self.outgoing_at(node_id)
215 .into_iter()
216 .flat_map(|ids| ids.iter())
217 .filter_map(|&id| self.rel_at(id).cloned())
218 .collect()
219 }
220
221 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
222 self.incoming_at(node_id)
223 .into_iter()
224 .flat_map(|ids| ids.iter())
225 .filter_map(|&id| self.rel_at(id).cloned())
226 .collect()
227 }
228
229 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
230 match direction {
231 Direction::Right => self.outgoing_at(node_id).map(|s| s.len()).unwrap_or(0),
232 Direction::Left => self.incoming_at(node_id).map(|s| s.len()).unwrap_or(0),
233 Direction::Undirected => {
234 self.outgoing_at(node_id).map(|s| s.len()).unwrap_or(0)
235 + self.incoming_at(node_id).map(|s| s.len()).unwrap_or(0)
236 }
237 }
238 }
239
240 fn expand(
241 &self,
242 node_id: NodeId,
243 direction: Direction,
244 types: &[String],
245 ) -> Vec<(RelationshipRecord, NodeRecord)> {
246 if self.node_at(node_id).is_none() {
247 return Vec::new();
248 }
249
250 let type_filter: Option<BTreeSet<&str>> = if types.is_empty() {
251 None
252 } else {
253 Some(types.iter().map(String::as_str).collect())
254 };
255
256 self.relationship_ids_for_direction(node_id, direction)
257 .into_iter()
258 .filter_map(|rel_id| self.rel_at(rel_id))
259 .filter(|rel| {
260 type_filter
261 .as_ref()
262 .map(|allowed| allowed.contains(rel.rel_type.as_str()))
263 .unwrap_or(true)
264 })
265 .filter_map(|rel| {
266 let other_id = Self::other_endpoint(rel, node_id)?;
267 let other = self.node_at(other_id)?;
268 Some((rel.clone(), other.clone()))
269 })
270 .collect()
271 }
272
273 fn all_node_property_keys(&self) -> Vec<String> {
274 let mut keys = BTreeSet::new();
275 for node in self.iter_node_records() {
276 for key in node.properties.keys() {
277 keys.insert(key.clone());
278 }
279 }
280 keys.into_iter().collect()
281 }
282
283 fn all_relationship_property_keys(&self) -> Vec<String> {
286 let mut keys = BTreeSet::new();
287 for rel in self.iter_rel_records() {
288 for key in rel.properties.keys() {
289 keys.insert(key.clone());
290 }
291 }
292 keys.into_iter().collect()
293 }
294
295 fn label_property_keys(&self, label: &str) -> Vec<String> {
296 let mut keys = BTreeSet::new();
297
298 if let Some(ids) = self.nodes_by_label.get(label) {
299 for &id in ids {
300 if let Some(node) = self.node_at(id) {
301 for key in node.properties.keys() {
302 keys.insert(key.clone());
303 }
304 }
305 }
306 }
307
308 keys.into_iter().collect()
309 }
310
311 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
312 let mut keys = BTreeSet::new();
313
314 if let Some(ids) = self.relationships_by_type.get(rel_type) {
315 for &id in ids {
316 if let Some(rel) = self.rel_at(id) {
317 for key in rel.properties.keys() {
318 keys.insert(key.clone());
319 }
320 }
321 }
322 }
323
324 keys.into_iter().collect()
325 }
326
327 fn find_nodes_by_property(
328 &self,
329 label: Option<&str>,
330 key: &str,
331 value: &PropertyValue,
332 ) -> Vec<NodeRecord>
333 where
334 Self: Sized,
335 {
336 if PropertyIndexKey::from_value(value).is_none() {
337 return self.scan_nodes_by_property(label, key, value);
338 }
339
340 self.ensure_node_property_index(key);
341 let indexes = self.indexes_read();
342
343 match label {
344 Some(label) => {
345 let Some(ids) = indexes.node_properties.scoped_ids_for(label, key, value) else {
346 return Vec::new();
347 };
348 ids.iter()
349 .filter_map(|&id| self.node_at(id).cloned())
350 .collect()
351 }
352 None => indexes
353 .node_properties
354 .ids_for(key, value)
355 .into_iter()
356 .flat_map(|ids| ids.iter())
357 .filter_map(|&id| self.node_at(id).cloned())
358 .collect(),
359 }
360 }
361
362 fn find_node_ids_by_property(
363 &self,
364 label: Option<&str>,
365 key: &str,
366 value: &PropertyValue,
367 ) -> Vec<NodeId>
368 where
369 Self: Sized,
370 {
371 if PropertyIndexKey::from_value(value).is_none() {
372 return self
373 .scan_nodes_by_property(label, key, value)
374 .into_iter()
375 .map(|n| n.id)
376 .collect();
377 }
378
379 self.ensure_node_property_index(key);
380 let indexes = self.indexes_read();
381
382 match label {
383 Some(label) => indexes
384 .node_properties
385 .scoped_ids_for(label, key, value)
386 .map(|ids| ids.iter().copied().collect())
387 .unwrap_or_default(),
388 None => indexes
389 .node_properties
390 .ids_for(key, value)
391 .map(|ids| ids.iter().copied().collect())
392 .unwrap_or_default(),
393 }
394 }
395 fn find_relationships_by_property(
398 &self,
399 rel_type: Option<&str>,
400 key: &str,
401 value: &PropertyValue,
402 ) -> Vec<RelationshipRecord>
403 where
404 Self: Sized,
405 {
406 if PropertyIndexKey::from_value(value).is_none() {
407 return self.scan_relationships_by_property(rel_type, key, value);
408 }
409
410 self.ensure_relationship_property_index(key);
411 let indexes = self.indexes_read();
412
413 match rel_type {
414 Some(rel_type) => {
415 let Some(ids) = indexes
416 .relationship_properties
417 .scoped_ids_for(rel_type, key, value)
418 else {
419 return Vec::new();
420 };
421 ids.iter()
422 .filter_map(|&id| self.rel_at(id).cloned())
423 .collect()
424 }
425 None => indexes
426 .relationship_properties
427 .ids_for(key, value)
428 .into_iter()
429 .flat_map(|ids| ids.iter())
430 .filter_map(|&id| self.rel_at(id).cloned())
431 .collect(),
432 }
433 }
434
435 fn find_relationship_ids_by_property(
436 &self,
437 rel_type: Option<&str>,
438 key: &str,
439 value: &PropertyValue,
440 ) -> Vec<RelationshipId>
441 where
442 Self: Sized,
443 {
444 if PropertyIndexKey::from_value(value).is_none() {
445 return self
446 .scan_relationships_by_property(rel_type, key, value)
447 .into_iter()
448 .map(|r| r.id)
449 .collect();
450 }
451
452 self.ensure_relationship_property_index(key);
453 let indexes = self.indexes_read();
454
455 match rel_type {
456 Some(rel_type) => indexes
457 .relationship_properties
458 .scoped_ids_for(rel_type, key, value)
459 .map(|ids| ids.iter().copied().collect())
460 .unwrap_or_default(),
461 None => indexes
462 .relationship_properties
463 .ids_for(key, value)
464 .map(|ids| ids.iter().copied().collect())
465 .unwrap_or_default(),
466 }
467 }
468
469 fn node_exists_with_label_and_property(
470 &self,
471 label: &str,
472 key: &str,
473 value: &PropertyValue,
474 ) -> bool
475 where
476 Self: Sized,
477 {
478 if PropertyIndexKey::from_value(value).is_none() {
479 return !self
480 .scan_nodes_by_property(Some(label), key, value)
481 .is_empty();
482 }
483
484 self.ensure_node_property_index(key);
485 let indexes = self.indexes_read();
486 indexes
487 .node_properties
488 .scoped_ids_for(label, key, value)
489 .map(|ids| !ids.is_empty())
490 .unwrap_or(false)
491 }
492
493 fn relationship_exists_with_type_and_property(
494 &self,
495 rel_type: &str,
496 key: &str,
497 value: &PropertyValue,
498 ) -> bool
499 where
500 Self: Sized,
501 {
502 if PropertyIndexKey::from_value(value).is_none() {
503 return !self
504 .scan_relationships_by_property(Some(rel_type), key, value)
505 .is_empty();
506 }
507
508 self.ensure_relationship_property_index(key);
509 let indexes = self.indexes_read();
510 indexes
511 .relationship_properties
512 .scoped_ids_for(rel_type, key, value)
513 .map(|ids| !ids.is_empty())
514 .unwrap_or(false)
515 }
516}
517
518impl BorrowedGraphStorage for InMemoryGraph {
519 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord> {
520 self.node_at(id)
521 }
522
523 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord> {
524 self.rel_at(id)
525 }
526
527 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
528 Box::new(self.iter_node_records())
529 }
530
531 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
532 Box::new(
533 self.nodes_by_label
534 .get(label)
535 .into_iter()
536 .flat_map(|ids| ids.iter())
537 .filter_map(|&id| self.node_at(id)),
538 )
539 }
540
541 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
542 Box::new(self.iter_rel_records())
543 }
544
545 fn relationship_refs_by_type(
546 &self,
547 rel_type: &str,
548 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
549 Box::new(
550 self.relationships_by_type
551 .get(rel_type)
552 .into_iter()
553 .flat_map(|ids| ids.iter())
554 .filter_map(|&id| self.rel_at(id)),
555 )
556 }
557}
558
559impl GraphStorageMut for InMemoryGraph {
560 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord {
561 let id = self.alloc_node_id();
562 let labels = Self::normalize_labels(labels);
563
564 let node = NodeRecord {
565 id,
566 labels: labels.clone(),
567 properties,
568 };
569
570 self.on_node_created(&node);
571
572 self.put_node(id, node.clone());
573
574 self.emit(|| MutationEvent::CreateNode {
578 id,
579 labels: node.labels.clone(),
580 properties: node.properties.clone(),
581 });
582
583 node
584 }
585
586 fn create_relationship(
587 &mut self,
588 src: NodeId,
589 dst: NodeId,
590 rel_type: &str,
591 properties: Properties,
592 ) -> Option<RelationshipRecord> {
593 if self.node_at(src).is_none() || self.node_at(dst).is_none() {
594 return None;
595 }
596
597 let trimmed = rel_type.trim();
598 if trimmed.is_empty() {
599 return None;
600 }
601
602 let id = self.alloc_rel_id();
603 let rel = RelationshipRecord {
604 id,
605 src,
606 dst,
607 rel_type: trimmed.to_string(),
608 properties,
609 };
610
611 self.on_relationship_created(&rel);
612 self.put_rel(id, rel.clone());
613
614 self.emit(|| MutationEvent::CreateRelationship {
615 id,
616 src,
617 dst,
618 rel_type: rel.rel_type.clone(),
619 properties: rel.properties.clone(),
620 });
621
622 Some(rel)
623 }
624
625 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
626 if self.node_at(node_id).is_none() {
627 return false;
628 }
629
630 let recorder_active = self.recorder.is_some();
631 let (stored_key, stored_value) = if recorder_active {
632 (Some(key.clone()), Some(value.clone()))
633 } else {
634 (None, None)
635 };
636
637 let old = match self.node_at_mut(node_id) {
638 Some(node) => node.properties.insert(key.clone(), value.clone()),
639 None => return false,
640 };
641 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
642
643 self.emit(|| MutationEvent::SetNodeProperty {
644 node_id,
645 key: stored_key.unwrap(),
646 value: stored_value.unwrap(),
647 });
648
649 true
650 }
651
652 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
653 let removed = match self.node_at_mut(node_id) {
654 Some(node) => node.properties.remove(key),
655 None => return false,
656 };
657 let Some(removed) = removed else {
658 return false;
659 };
660
661 self.on_node_property_removed(node_id, key, &removed);
662
663 self.emit(|| MutationEvent::RemoveNodeProperty {
664 node_id,
665 key: key.to_string(),
666 });
667
668 true
669 }
670
671 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
672 let label = label.trim();
673 if label.is_empty() {
674 return false;
675 }
676
677 let applied = match self.node_at_mut(node_id) {
678 Some(node) => {
679 if node.labels.iter().any(|l| l == label) {
680 return false;
681 }
682
683 node.labels.push(label.to_string());
684 true
685 }
686 None => false,
687 };
688 if applied {
689 self.on_node_label_added(node_id, label);
690 self.emit(|| MutationEvent::AddNodeLabel {
691 node_id,
692 label: label.to_string(),
693 });
694 }
695 applied
696 }
697
698 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
699 let applied = match self.node_at_mut(node_id) {
700 Some(node) => {
701 let original_len = node.labels.len();
702 node.labels.retain(|l| l != label);
703 node.labels.len() != original_len
704 }
705 None => false,
706 };
707 if applied {
708 self.on_node_label_removed(node_id, label);
709 self.emit(|| MutationEvent::RemoveNodeLabel {
710 node_id,
711 label: label.to_string(),
712 });
713 }
714 applied
715 }
716
717 fn set_relationship_property(
718 &mut self,
719 rel_id: RelationshipId,
720 key: String,
721 value: PropertyValue,
722 ) -> bool {
723 if self.rel_at(rel_id).is_none() {
724 return false;
725 }
726
727 let recorder_active = self.recorder.is_some();
728 let (stored_key, stored_value) = if recorder_active {
729 (Some(key.clone()), Some(value.clone()))
730 } else {
731 (None, None)
732 };
733
734 let old = match self.rel_at_mut(rel_id) {
735 Some(rel) => rel.properties.insert(key.clone(), value.clone()),
736 None => return false,
737 };
738 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
739
740 self.emit(|| MutationEvent::SetRelationshipProperty {
741 rel_id,
742 key: stored_key.unwrap(),
743 value: stored_value.unwrap(),
744 });
745
746 true
747 }
748
749 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
750 let removed = match self.rel_at_mut(rel_id) {
751 Some(rel) => rel.properties.remove(key),
752 None => return false,
753 };
754 let Some(removed) = removed else {
755 return false;
756 };
757
758 self.on_relationship_property_removed(rel_id, key, &removed);
759
760 self.emit(|| MutationEvent::RemoveRelationshipProperty {
761 rel_id,
762 key: key.to_string(),
763 });
764
765 true
766 }
767
768 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
769 let applied = match self.take_rel(rel_id) {
770 Some(rel) => {
771 self.on_relationship_deleted(&rel);
772 true
773 }
774 None => false,
775 };
776 if applied {
777 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
778 }
779 applied
780 }
781
782 fn delete_node(&mut self, node_id: NodeId) -> bool {
783 if self.node_at(node_id).is_none() {
784 return false;
785 }
786
787 if self.has_incident_relationships(node_id) {
788 return false;
789 }
790
791 let node = match self.take_node(node_id) {
792 Some(node) => node,
793 None => return false,
794 };
795
796 self.on_node_deleted(&node);
797
798 self.emit(|| MutationEvent::DeleteNode { node_id });
801
802 true
803 }
804
805 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
806 if self.node_at(node_id).is_none() {
807 return false;
808 }
809
810 let rel_ids: Vec<_> = self
811 .incident_relationship_ids(node_id)
812 .into_iter()
813 .collect();
814
815 for rel_id in rel_ids {
824 let _ = self.delete_relationship(rel_id);
825 }
826
827 if self.delete_node(node_id) {
828 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
829 true
830 } else {
831 false
832 }
833 }
834
835 fn clear(&mut self) {
836 let recorder = self.recorder.take();
840 *self = Self::default();
841 self.recorder = recorder;
842 self.emit(|| MutationEvent::Clear);
843 }
844}