1use std::collections::BTreeSet;
6
7use lora_ast::Direction;
8
9use crate::{
10 BorrowedGraphStorage, ConstraintDefinition, ConstraintRequest, CreateConstraintError,
11 CreateConstraintOutcome, CreateIndexError, CreateIndexOutcome, DropConstraintError,
12 DropConstraintOutcome, DropIndexError, DropIndexOutcome, GraphStats, GraphStorage,
13 GraphStorageMut, IndexDefinition, IndexRequest, LoraVector, MutationEvent, NodeId, NodeRecord,
14 Properties, PropertyValue, RelationshipId, RelationshipRecord, StoredIndexEntity,
15};
16
17use super::property_index::PropertyIndexKey;
18use super::InMemoryGraph;
19
20impl GraphStorage for InMemoryGraph {
21 fn list_indexes(&self) -> Vec<IndexDefinition> {
24 self.index_catalog_read().list()
25 }
26
27 fn get_index(&self, name: &str) -> Option<IndexDefinition> {
28 self.index_catalog_read().get(name).cloned()
29 }
30
31 fn fulltext_search(&self, name: &str, query: &str) -> Vec<(u64, f64)> {
32 let node_hits = self
34 .fulltext_indexes_read(StoredIndexEntity::Node)
35 .get(name)
36 .map(|idx| idx.query(query));
37 if let Some(hits) = node_hits {
38 if !hits.is_empty() {
39 return hits;
40 }
41 }
42 let rel_hits = self
43 .fulltext_indexes_read(StoredIndexEntity::Relationship)
44 .get(name)
45 .map(|idx| idx.query(query));
46 rel_hits.unwrap_or_default()
47 }
48
49 fn vector_search(
50 &self,
51 name: &str,
52 query: &LoraVector,
53 k: usize,
54 restrict_to: Option<&std::collections::BTreeSet<u64>>,
55 ) -> Vec<(u64, f64)> {
56 self.lazy_populate_vector_index(name);
63
64 if let Some(hits) =
68 self.vector_indexes_read(StoredIndexEntity::Node)
69 .query(name, query, k, restrict_to)
70 {
71 if !hits.is_empty() {
72 return hits;
73 }
74 }
75 self.vector_indexes_read(StoredIndexEntity::Relationship)
76 .query(name, query, k, restrict_to)
77 .unwrap_or_default()
78 }
79
80 fn list_constraints(&self) -> Vec<ConstraintDefinition> {
81 self.constraint_catalog_read().list()
82 }
83
84 fn get_constraint(&self, name: &str) -> Option<ConstraintDefinition> {
85 self.constraint_catalog_read().get(name).cloned()
86 }
87
88 fn check_node_create_against_constraints(
89 &self,
90 labels: &[String],
91 properties: &Properties,
92 ) -> Result<(), String> {
93 if !self.has_active_constraints() {
94 return Ok(());
95 }
96 let catalog = self.constraint_catalog_read();
97 crate::memory::constraint_enforce::check_node_create(&catalog, self, labels, properties)
98 .map_err(|e| format!("[{}] {e}", e.gql_status()))
99 }
100
101 fn check_relationship_create_against_constraints(
102 &self,
103 rel_type: &str,
104 properties: &Properties,
105 ) -> Result<(), String> {
106 if !self.has_active_constraints() {
107 return Ok(());
108 }
109 let catalog = self.constraint_catalog_read();
110 crate::memory::constraint_enforce::check_relationship_create(
111 &catalog, self, rel_type, properties,
112 )
113 .map_err(|e| format!("[{}] {e}", e.gql_status()))
114 }
115
116 fn check_node_create_deferring_existence(
117 &self,
118 labels: &[String],
119 properties: &Properties,
120 ) -> Result<(), String> {
121 if !self.has_active_constraints() {
122 return Ok(());
123 }
124 let catalog = self.constraint_catalog_read();
125 crate::memory::constraint_enforce::check_node_create_deferred(
126 &catalog, self, labels, properties,
127 )
128 .map_err(|e| format!("[{}] {e}", e.gql_status()))
129 }
130
131 fn check_relationship_create_deferring_existence(
132 &self,
133 rel_type: &str,
134 properties: &Properties,
135 ) -> Result<(), String> {
136 if !self.has_active_constraints() {
137 return Ok(());
138 }
139 let catalog = self.constraint_catalog_read();
140 crate::memory::constraint_enforce::check_relationship_create_deferred(
141 &catalog, self, rel_type, properties,
142 )
143 .map_err(|e| format!("[{}] {e}", e.gql_status()))
144 }
145
146 fn check_node_existence_constraints(&self, node_id: NodeId) -> Result<(), String> {
147 if !self.has_active_constraints() {
148 return Ok(());
149 }
150 let catalog = self.constraint_catalog_read();
151 crate::memory::constraint_enforce::check_node_existence(&catalog, self, node_id)
152 .map_err(|e| format!("[{}] {e}", e.gql_status()))
153 }
154
155 fn check_relationship_existence_constraints(
156 &self,
157 rel_id: RelationshipId,
158 ) -> Result<(), String> {
159 if !self.has_active_constraints() {
160 return Ok(());
161 }
162 let catalog = self.constraint_catalog_read();
163 crate::memory::constraint_enforce::check_relationship_existence(&catalog, self, rel_id)
164 .map_err(|e| format!("[{}] {e}", e.gql_status()))
165 }
166
167 fn check_node_set_property_against_constraints(
168 &self,
169 node_id: NodeId,
170 key: &str,
171 value: &PropertyValue,
172 ) -> Result<(), String> {
173 if !self.has_active_constraints() {
174 return Ok(());
175 }
176 let catalog = self.constraint_catalog_read();
177 crate::memory::constraint_enforce::check_node_set_property(
178 &catalog, self, node_id, key, value,
179 )
180 .map_err(|e| format!("[{}] {e}", e.gql_status()))
181 }
182
183 fn check_node_remove_property_against_constraints(
184 &self,
185 node_id: NodeId,
186 key: &str,
187 ) -> Result<(), String> {
188 if !self.has_active_constraints() {
189 return Ok(());
190 }
191 let catalog = self.constraint_catalog_read();
192 crate::memory::constraint_enforce::check_node_remove_property(&catalog, self, node_id, key)
193 .map_err(|e| format!("[{}] {e}", e.gql_status()))
194 }
195
196 fn check_node_replace_properties_against_constraints(
197 &self,
198 node_id: NodeId,
199 properties: &Properties,
200 ) -> Result<(), String> {
201 if !self.has_active_constraints() {
202 return Ok(());
203 }
204 let catalog = self.constraint_catalog_read();
205 crate::memory::constraint_enforce::check_node_replace_properties(
206 &catalog, self, node_id, properties,
207 )
208 .map_err(|e| format!("[{}] {e}", e.gql_status()))
209 }
210
211 fn check_relationship_set_property_against_constraints(
212 &self,
213 rel_id: RelationshipId,
214 key: &str,
215 value: &PropertyValue,
216 ) -> Result<(), String> {
217 if !self.has_active_constraints() {
218 return Ok(());
219 }
220 let catalog = self.constraint_catalog_read();
221 crate::memory::constraint_enforce::check_relationship_set_property(
222 &catalog, self, rel_id, key, value,
223 )
224 .map_err(|e| format!("[{}] {e}", e.gql_status()))
225 }
226
227 fn check_relationship_remove_property_against_constraints(
228 &self,
229 rel_id: RelationshipId,
230 key: &str,
231 ) -> Result<(), String> {
232 if !self.has_active_constraints() {
233 return Ok(());
234 }
235 let catalog = self.constraint_catalog_read();
236 crate::memory::constraint_enforce::check_relationship_remove_property(
237 &catalog, self, rel_id, key,
238 )
239 .map_err(|e| format!("[{}] {e}", e.gql_status()))
240 }
241
242 fn check_relationship_replace_properties_against_constraints(
243 &self,
244 rel_id: RelationshipId,
245 properties: &Properties,
246 ) -> Result<(), String> {
247 if !self.has_active_constraints() {
248 return Ok(());
249 }
250 let catalog = self.constraint_catalog_read();
251 crate::memory::constraint_enforce::check_relationship_replace_properties(
252 &catalog, self, rel_id, properties,
253 )
254 .map_err(|e| format!("[{}] {e}", e.gql_status()))
255 }
256
257 fn check_node_add_label_against_constraints(
258 &self,
259 node_id: NodeId,
260 label: &str,
261 ) -> Result<(), String> {
262 if !self.has_active_constraints() {
263 return Ok(());
264 }
265 let catalog = self.constraint_catalog_read();
266 crate::memory::constraint_enforce::check_node_add_label(&catalog, self, node_id, label)
267 .map_err(|e| format!("[{}] {e}", e.gql_status()))
268 }
269
270 fn graph_stats(&self) -> GraphStats {
271 InMemoryGraph::graph_stats(self)
272 }
273
274 fn node_text_candidates(
275 &self,
276 label: &str,
277 property: &str,
278 query: &str,
279 ) -> Option<Vec<NodeId>> {
280 let registry = self.text_indexes_read(crate::StoredIndexEntity::Node);
281 let candidates = registry.candidates(label, property, query)?;
282 Some(candidates.into_iter().collect())
283 }
284
285 fn node_range_candidates(
286 &self,
287 label: &str,
288 property: &str,
289 lo: Option<&PropertyValue>,
290 hi: Option<&PropertyValue>,
291 ) -> Option<Vec<NodeId>> {
292 let registry = self.sorted_indexes_read(crate::StoredIndexEntity::Node);
293 let candidates = registry.range_candidates(label, property, lo, hi)?;
297 Some(candidates.into_iter().collect())
298 }
299
300 fn node_range_ordered_chunk(
301 &self,
302 label: &str,
303 property: &str,
304 lo: Option<&PropertyValue>,
305 hi: Option<&PropertyValue>,
306 descending: bool,
307 after: Option<(&PropertyValue, NodeId)>,
308 max: usize,
309 ) -> Option<Vec<NodeId>> {
310 self.sorted_indexes_read(crate::StoredIndexEntity::Node)
311 .ordered_chunk(label, property, lo, hi, descending, after, max)
312 }
313
314 fn node_point_within_bbox(
315 &self,
316 label: &str,
317 property: &str,
318 ll: (f64, f64),
319 ur: (f64, f64),
320 ) -> Option<Vec<NodeId>> {
321 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
322 let candidates = registry.within_bbox(label, property, ll, ur)?;
323 Some(candidates.into_iter().collect())
324 }
325
326 fn node_point_within_distance(
327 &self,
328 label: &str,
329 property: &str,
330 center: (f64, f64),
331 max_distance: f64,
332 ) -> Option<Vec<NodeId>> {
333 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
334 let candidates = registry.within_distance(label, property, center, max_distance)?;
335 Some(candidates.into_iter().collect())
336 }
337
338 fn relationship_text_candidates(
339 &self,
340 rel_type: &str,
341 property: &str,
342 query: &str,
343 ) -> Option<Vec<RelationshipId>> {
344 let registry = self.text_indexes_read(crate::StoredIndexEntity::Relationship);
345 let candidates = registry.candidates(rel_type, property, query)?;
346 Some(candidates.into_iter().collect())
347 }
348
349 fn relationship_range_candidates(
350 &self,
351 rel_type: &str,
352 property: &str,
353 lo: Option<&PropertyValue>,
354 hi: Option<&PropertyValue>,
355 ) -> Option<Vec<RelationshipId>> {
356 let registry = self.sorted_indexes_read(crate::StoredIndexEntity::Relationship);
357 let candidates = registry.range_candidates(rel_type, property, lo, hi)?;
358 Some(candidates.into_iter().collect())
359 }
360
361 fn relationship_point_within_bbox(
362 &self,
363 rel_type: &str,
364 property: &str,
365 ll: (f64, f64),
366 ur: (f64, f64),
367 ) -> Option<Vec<RelationshipId>> {
368 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
369 let candidates = registry.within_bbox(rel_type, property, ll, ur)?;
370 Some(candidates.into_iter().collect())
371 }
372
373 fn relationship_point_within_distance(
374 &self,
375 rel_type: &str,
376 property: &str,
377 center: (f64, f64),
378 max_distance: f64,
379 ) -> Option<Vec<RelationshipId>> {
380 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
381 let candidates = registry.within_distance(rel_type, property, center, max_distance)?;
382 Some(candidates.into_iter().collect())
383 }
384
385 fn contains_node(&self, id: NodeId) -> bool {
386 self.node_at(id).is_some()
387 }
388
389 fn node(&self, id: NodeId) -> Option<NodeRecord> {
390 self.node_at(id).cloned()
391 }
392
393 fn all_node_ids(&self) -> Vec<NodeId> {
394 self.iter_node_ids().collect()
395 }
396
397 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId> {
398 match self.nodes_by_label.get(label) {
399 Some(ids) => ids.iter().copied().collect(),
400 None => Vec::new(),
401 }
402 }
403
404 fn contains_relationship(&self, id: RelationshipId) -> bool {
405 self.rel_at(id).is_some()
406 }
407
408 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
409 self.rel_at(id).cloned()
410 }
411
412 fn all_rel_ids(&self) -> Vec<RelationshipId> {
413 self.iter_rel_ids().collect()
414 }
415
416 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
417 match self.relationships_by_type.get(rel_type) {
418 Some(ids) => ids.iter().copied().collect(),
419 None => Vec::new(),
420 }
421 }
422
423 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)> {
424 self.rel_at(id).map(|r| (r.src, r.dst))
425 }
426
427 fn expand_ids(
428 &self,
429 node_id: NodeId,
430 direction: Direction,
431 types: &[String],
432 ) -> Vec<(RelationshipId, NodeId)> {
433 if self.node_at(node_id).is_none() {
434 return Vec::new();
435 }
436
437 let mut out: Vec<(RelationshipId, NodeId)> = Vec::new();
443
444 let single_type = match types {
445 [single] => Some(single.as_str()),
446 _ => None,
447 };
448 let has_type_filter = !types.is_empty();
449
450 let push_from = |adj: &[RelationshipId],
451 skip_self_loops: bool,
452 out: &mut Vec<(RelationshipId, NodeId)>| {
453 for &rel_id in adj {
454 let Some(rel) = self.rel_at(rel_id) else {
455 continue;
456 };
457 if skip_self_loops && rel.src == node_id && rel.dst == node_id {
458 continue;
459 }
460 if let Some(single) = single_type {
461 if rel.rel_type != single {
462 continue;
463 }
464 } else if has_type_filter && !types.iter().any(|t| t == &rel.rel_type) {
465 continue;
466 }
467 let Some(other_id) = Self::other_endpoint(rel, node_id) else {
468 continue;
469 };
470 out.push((rel_id, other_id));
471 }
472 };
473
474 match direction {
475 Direction::Right => {
476 if let Some(adj) = self.outgoing_at(node_id) {
477 out.reserve(adj.len());
478 push_from(adj, false, &mut out);
479 }
480 }
481 Direction::Left => {
482 if let Some(adj) = self.incoming_at(node_id) {
483 out.reserve(adj.len());
484 push_from(adj, false, &mut out);
485 }
486 }
487 Direction::Undirected => {
488 let out_len = self.outgoing_at(node_id).map(<[_]>::len).unwrap_or(0);
489 let in_len = self.incoming_at(node_id).map(<[_]>::len).unwrap_or(0);
490 out.reserve(out_len + in_len);
491 if let Some(adj) = self.outgoing_at(node_id) {
492 push_from(adj, false, &mut out);
493 }
494 if let Some(adj) = self.incoming_at(node_id) {
495 push_from(adj, true, &mut out);
496 }
497 }
498 }
499
500 out
501 }
502
503 fn try_for_each_expand_id<F, E>(
504 &self,
505 node_id: NodeId,
506 direction: Direction,
507 types: &[String],
508 visit: F,
509 ) -> Result<(), E>
510 where
511 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
512 Self: Sized,
513 {
514 self.try_for_each_adjacent_id(node_id, direction, types, visit)
515 }
516
517 fn all_labels(&self) -> Vec<String> {
518 self.nodes_by_label.keys().cloned().collect()
519 }
520
521 fn all_relationship_types(&self) -> Vec<String> {
522 self.relationships_by_type.keys().cloned().collect()
523 }
524
525 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
528 where
529 F: FnOnce(&NodeRecord) -> R,
530 Self: Sized,
531 {
532 self.node_at(id).map(f)
533 }
534
535 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
536 where
537 F: FnOnce(&RelationshipRecord) -> R,
538 Self: Sized,
539 {
540 self.rel_at(id).map(f)
541 }
542
543 fn has_node(&self, id: NodeId) -> bool {
546 self.node_at(id).is_some()
547 }
548
549 fn has_relationship(&self, id: RelationshipId) -> bool {
550 self.rel_at(id).is_some()
551 }
552
553 fn node_count(&self) -> usize {
554 self.live_node_count
555 }
556
557 fn relationship_count(&self) -> usize {
558 self.live_rel_count
559 }
560
561 fn node_count_by_label(&self, label: &str) -> usize {
562 self.nodes_by_label.get(label).map_or(0, |ids| ids.len())
563 }
564
565 fn all_nodes(&self) -> Vec<NodeRecord> {
568 self.iter_node_records().cloned().collect()
569 }
570
571 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
572 self.nodes_by_label
573 .get(label)
574 .into_iter()
575 .flat_map(|ids| ids.iter())
576 .filter_map(|&id| self.node_at(id).cloned())
577 .collect()
578 }
579
580 fn all_relationships(&self) -> Vec<RelationshipRecord> {
581 self.iter_rel_records().cloned().collect()
582 }
583
584 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
585 self.relationships_by_type
586 .get(rel_type)
587 .into_iter()
588 .flat_map(|ids| ids.iter())
589 .filter_map(|&id| self.rel_at(id).cloned())
590 .collect()
591 }
592
593 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
594 self.relationship_ids_for_direction(node_id, direction)
595 }
596
597 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
598 self.outgoing_at(node_id)
599 .into_iter()
600 .flat_map(|ids| ids.iter())
601 .filter_map(|&id| self.rel_at(id).cloned())
602 .collect()
603 }
604
605 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
606 self.incoming_at(node_id)
607 .into_iter()
608 .flat_map(|ids| ids.iter())
609 .filter_map(|&id| self.rel_at(id).cloned())
610 .collect()
611 }
612
613 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
614 let mut out = Vec::new();
615 let _ = self.try_for_each_expand_id(node_id, direction, &[], |rel_id, _| {
616 if let Some(rel) = self.rel_at(rel_id) {
617 out.push(rel.clone());
618 }
619 Ok::<(), ()>(())
620 });
621 out
622 }
623
624 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
625 match direction {
626 Direction::Right => self.outgoing_at(node_id).map(|s| s.len()).unwrap_or(0),
627 Direction::Left => self.incoming_at(node_id).map(|s| s.len()).unwrap_or(0),
628 Direction::Undirected => {
629 let out_count = self.outgoing_at(node_id).map(<[_]>::len).unwrap_or(0);
630 let incoming_non_self = self
631 .incoming_at(node_id)
632 .into_iter()
633 .flat_map(|ids| ids.iter())
634 .filter(|&&rel_id| {
635 self.rel_at(rel_id)
636 .map(|rel| rel.src != node_id || rel.dst != node_id)
637 .unwrap_or(false)
638 })
639 .count();
640 out_count + incoming_non_self
641 }
642 }
643 }
644
645 fn expand(
646 &self,
647 node_id: NodeId,
648 direction: Direction,
649 types: &[String],
650 ) -> Vec<(RelationshipRecord, NodeRecord)> {
651 if self.node_at(node_id).is_none() {
652 return Vec::new();
653 }
654
655 let mut out = Vec::new();
656 let _ = self.try_for_each_expand_id(node_id, direction, types, |rel_id, other_id| {
657 if let (Some(rel), Some(other)) = (self.rel_at(rel_id), self.node_at(other_id)) {
658 out.push((rel.clone(), other.clone()));
659 }
660 Ok::<(), ()>(())
661 });
662 out
663 }
664
665 fn neighbors(
666 &self,
667 node_id: NodeId,
668 direction: Direction,
669 types: &[String],
670 ) -> Vec<NodeRecord> {
671 let mut out = Vec::new();
672 let _ = self.try_for_each_expand_id(node_id, direction, types, |_, other_id| {
673 if let Some(node) = self.node_at(other_id) {
674 out.push(node.clone());
675 }
676 Ok::<(), ()>(())
677 });
678 out
679 }
680
681 fn all_node_property_keys(&self) -> Vec<String> {
682 let mut keys = BTreeSet::new();
683 for node in self.iter_node_records() {
684 for key in node.properties.keys() {
685 keys.insert(key.to_string());
686 }
687 }
688 keys.into_iter().collect()
689 }
690
691 fn all_relationship_property_keys(&self) -> Vec<String> {
694 let mut keys = BTreeSet::new();
695 for rel in self.iter_rel_records() {
696 for key in rel.properties.keys() {
697 keys.insert(key.to_string());
698 }
699 }
700 keys.into_iter().collect()
701 }
702
703 fn label_property_keys(&self, label: &str) -> Vec<String> {
704 let mut keys = BTreeSet::new();
705
706 if let Some(ids) = self.nodes_by_label.get(label) {
707 for &id in ids.iter() {
708 if let Some(node) = self.node_at(id) {
709 for key in node.properties.keys() {
710 keys.insert(key.to_string());
711 }
712 }
713 }
714 }
715
716 keys.into_iter().collect()
717 }
718
719 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
720 let mut keys = BTreeSet::new();
721
722 if let Some(ids) = self.relationships_by_type.get(rel_type) {
723 for &id in ids.iter() {
724 if let Some(rel) = self.rel_at(id) {
725 for key in rel.properties.keys() {
726 keys.insert(key.to_string());
727 }
728 }
729 }
730 }
731
732 keys.into_iter().collect()
733 }
734
735 fn find_nodes_by_property(
736 &self,
737 label: Option<&str>,
738 key: &str,
739 value: &PropertyValue,
740 ) -> Vec<NodeRecord>
741 where
742 Self: Sized,
743 {
744 if PropertyIndexKey::from_value(value).is_none() {
745 return self.scan_nodes_by_property(label, key, value);
746 }
747
748 self.ensure_node_property_index(key);
749 let indexes = self.indexes_read();
750
751 match label {
752 Some(label) => {
753 let Some(ids) = indexes.node_properties.scoped_ids_for(label, key, value) else {
754 return Vec::new();
755 };
756 ids.iter()
757 .filter_map(|id| self.node_at(id).cloned())
758 .collect()
759 }
760 None => indexes
761 .node_properties
762 .ids_for(key, value)
763 .into_iter()
764 .flat_map(|ids| ids.iter())
765 .filter_map(|id| self.node_at(id).cloned())
766 .collect(),
767 }
768 }
769
770 fn find_node_ids_by_property(
771 &self,
772 label: Option<&str>,
773 key: &str,
774 value: &PropertyValue,
775 ) -> Vec<NodeId>
776 where
777 Self: Sized,
778 {
779 if PropertyIndexKey::from_value(value).is_none() {
780 return self.scan_node_ids_by_property(label, key, value);
781 }
782
783 self.ensure_node_property_index(key);
784 let indexes = self.indexes_read();
785
786 match label {
787 Some(label) => indexes
788 .node_properties
789 .scoped_ids_for(label, key, value)
790 .map(|ids| ids.to_vec())
791 .unwrap_or_default(),
792 None => indexes
793 .node_properties
794 .ids_for(key, value)
795 .map(|ids| ids.to_vec())
796 .unwrap_or_default(),
797 }
798 }
799 fn find_relationships_by_property(
802 &self,
803 rel_type: Option<&str>,
804 key: &str,
805 value: &PropertyValue,
806 ) -> Vec<RelationshipRecord>
807 where
808 Self: Sized,
809 {
810 if PropertyIndexKey::from_value(value).is_none() {
811 return self.scan_relationships_by_property(rel_type, key, value);
812 }
813
814 self.ensure_relationship_property_index(key);
815 let indexes = self.indexes_read();
816
817 match rel_type {
818 Some(rel_type) => {
819 let Some(ids) = indexes
820 .relationship_properties
821 .scoped_ids_for(rel_type, key, value)
822 else {
823 return Vec::new();
824 };
825 ids.iter()
826 .filter_map(|id| self.rel_at(id).cloned())
827 .collect()
828 }
829 None => indexes
830 .relationship_properties
831 .ids_for(key, value)
832 .into_iter()
833 .flat_map(|ids| ids.iter())
834 .filter_map(|id| self.rel_at(id).cloned())
835 .collect(),
836 }
837 }
838
839 fn find_relationship_ids_by_property(
840 &self,
841 rel_type: Option<&str>,
842 key: &str,
843 value: &PropertyValue,
844 ) -> Vec<RelationshipId>
845 where
846 Self: Sized,
847 {
848 if PropertyIndexKey::from_value(value).is_none() {
849 return self.scan_relationship_ids_by_property(rel_type, key, value);
850 }
851
852 self.ensure_relationship_property_index(key);
853 let indexes = self.indexes_read();
854
855 match rel_type {
856 Some(rel_type) => indexes
857 .relationship_properties
858 .scoped_ids_for(rel_type, key, value)
859 .map(|ids| ids.to_vec())
860 .unwrap_or_default(),
861 None => indexes
862 .relationship_properties
863 .ids_for(key, value)
864 .map(|ids| ids.to_vec())
865 .unwrap_or_default(),
866 }
867 }
868
869 fn node_exists_with_label_and_property(
870 &self,
871 label: &str,
872 key: &str,
873 value: &PropertyValue,
874 ) -> bool
875 where
876 Self: Sized,
877 {
878 if PropertyIndexKey::from_value(value).is_none() {
879 return self.any_node_by_property(label, key, value);
880 }
881
882 self.ensure_node_property_index(key);
883 let indexes = self.indexes_read();
884 indexes
885 .node_properties
886 .scoped_ids_for(label, key, value)
887 .map(|ids| !ids.is_empty())
888 .unwrap_or(false)
889 }
890
891 fn relationship_exists_with_type_and_property(
892 &self,
893 rel_type: &str,
894 key: &str,
895 value: &PropertyValue,
896 ) -> bool
897 where
898 Self: Sized,
899 {
900 if PropertyIndexKey::from_value(value).is_none() {
901 return self.any_relationship_by_property(rel_type, key, value);
902 }
903
904 self.ensure_relationship_property_index(key);
905 let indexes = self.indexes_read();
906 indexes
907 .relationship_properties
908 .scoped_ids_for(rel_type, key, value)
909 .map(|ids| !ids.is_empty())
910 .unwrap_or(false)
911 }
912}
913
914impl BorrowedGraphStorage for InMemoryGraph {
915 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord> {
916 self.node_at(id)
917 }
918
919 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord> {
920 self.rel_at(id)
921 }
922
923 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
924 Box::new(self.iter_node_records())
925 }
926
927 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
928 Box::new(
929 self.nodes_by_label
930 .get(label)
931 .into_iter()
932 .flat_map(|ids| ids.iter())
933 .filter_map(|&id| self.node_at(id)),
934 )
935 }
936
937 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
938 Box::new(self.iter_rel_records())
939 }
940
941 fn relationship_refs_by_type(
942 &self,
943 rel_type: &str,
944 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
945 Box::new(
946 self.relationships_by_type
947 .get(rel_type)
948 .into_iter()
949 .flat_map(|ids| ids.iter())
950 .filter_map(|&id| self.rel_at(id)),
951 )
952 }
953}
954
955impl GraphStorageMut for InMemoryGraph {
956 fn try_create_node(
957 &mut self,
958 labels: Vec<String>,
959 properties: Properties,
960 ) -> Option<NodeRecord> {
961 let (id, idx) = self.try_reserve_next_node_slot()?;
962 let labels = Self::normalize_labels(labels);
963
964 let node = NodeRecord {
965 id,
966 labels: labels.clone(),
967 properties,
968 };
969
970 self.put_node_at_slot(idx, node.clone());
971
972 self.on_node_created(&node);
973
974 self.emit(|| MutationEvent::CreateNode {
978 id,
979 labels: node.labels.clone(),
980 properties: node.properties.clone(),
981 });
982
983 Some(node)
984 }
985
986 fn create_relationship(
987 &mut self,
988 src: NodeId,
989 dst: NodeId,
990 rel_type: &str,
991 properties: Properties,
992 ) -> Option<RelationshipRecord> {
993 if self.node_at(src).is_none() || self.node_at(dst).is_none() {
994 return None;
995 }
996
997 let trimmed = rel_type.trim();
998 if trimmed.is_empty() {
999 return None;
1000 }
1001
1002 let (id, idx) = self.try_reserve_next_rel_slot()?;
1003 let rel = RelationshipRecord {
1004 id,
1005 src,
1006 dst,
1007 rel_type: trimmed.to_string(),
1008 properties,
1009 };
1010
1011 self.put_rel_at_slot(idx, rel.clone());
1012 self.on_relationship_created(&rel);
1013
1014 self.emit(|| MutationEvent::CreateRelationship {
1015 id,
1016 src,
1017 dst,
1018 rel_type: rel.rel_type.clone(),
1019 properties: rel.properties.clone(),
1020 });
1021
1022 Some(rel)
1023 }
1024
1025 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
1026 if self.node_at(node_id).is_none() {
1027 return false;
1028 }
1029
1030 let old = match self.node_at_mut(node_id) {
1031 Some(node) => {
1035 if let Some(slot) = node.properties.get_mut(key.as_str()) {
1036 Some(std::mem::replace(slot, value.clone()))
1037 } else {
1038 let key_arc = crate::intern(&key);
1039 node.properties.insert(key_arc, value.clone())
1040 }
1041 }
1042 None => return false,
1043 };
1044 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
1045
1046 self.emit(|| MutationEvent::SetNodeProperty {
1047 node_id,
1048 key: key.clone(),
1049 value: value.clone(),
1050 });
1051
1052 true
1053 }
1054
1055 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
1056 let removed = match self.node_at_mut(node_id) {
1057 Some(node) => node.properties.remove(key),
1058 None => return false,
1059 };
1060 let Some(removed) = removed else {
1061 return false;
1062 };
1063
1064 self.on_node_property_removed(node_id, key, &removed);
1065
1066 self.emit(|| MutationEvent::RemoveNodeProperty {
1067 node_id,
1068 key: key.to_string(),
1069 });
1070
1071 true
1072 }
1073
1074 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1075 let label = label.trim();
1076 if label.is_empty() {
1077 return false;
1078 }
1079
1080 let applied = match self.node_at_mut(node_id) {
1081 Some(node) => {
1082 if node.labels.iter().any(|l| l == label) {
1083 return false;
1084 }
1085
1086 node.labels.push(label.to_string());
1087 true
1088 }
1089 None => false,
1090 };
1091 if applied {
1092 self.on_node_label_added(node_id, label);
1093 self.emit(|| MutationEvent::AddNodeLabel {
1094 node_id,
1095 label: label.to_string(),
1096 });
1097 }
1098 applied
1099 }
1100
1101 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1102 let applied = match self.node_at_mut(node_id) {
1103 Some(node) => {
1104 let original_len = node.labels.len();
1105 node.labels.retain(|l| l != label);
1106 node.labels.len() != original_len
1107 }
1108 None => false,
1109 };
1110 if applied {
1111 self.on_node_label_removed(node_id, label);
1112 self.emit(|| MutationEvent::RemoveNodeLabel {
1113 node_id,
1114 label: label.to_string(),
1115 });
1116 }
1117 applied
1118 }
1119
1120 fn set_relationship_property(
1121 &mut self,
1122 rel_id: RelationshipId,
1123 key: String,
1124 value: PropertyValue,
1125 ) -> bool {
1126 if self.rel_at(rel_id).is_none() {
1127 return false;
1128 }
1129
1130 let old = match self.rel_at_mut(rel_id) {
1131 Some(rel) => {
1132 if let Some(slot) = rel.properties.get_mut(key.as_str()) {
1133 Some(std::mem::replace(slot, value.clone()))
1134 } else {
1135 let key_arc = crate::intern(&key);
1136 rel.properties.insert(key_arc, value.clone())
1137 }
1138 }
1139 None => return false,
1140 };
1141 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
1142
1143 self.emit(|| MutationEvent::SetRelationshipProperty {
1144 rel_id,
1145 key: key.clone(),
1146 value: value.clone(),
1147 });
1148
1149 true
1150 }
1151
1152 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
1153 let removed = match self.rel_at_mut(rel_id) {
1154 Some(rel) => rel.properties.remove(key),
1155 None => return false,
1156 };
1157 let Some(removed) = removed else {
1158 return false;
1159 };
1160
1161 self.on_relationship_property_removed(rel_id, key, &removed);
1162
1163 self.emit(|| MutationEvent::RemoveRelationshipProperty {
1164 rel_id,
1165 key: key.to_string(),
1166 });
1167
1168 true
1169 }
1170
1171 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
1172 let applied = match self.take_rel(rel_id) {
1173 Some(rel) => {
1174 if let Some(sink) = &self.deleted_sink {
1175 sink.relationship_deleted(&rel);
1176 }
1177 self.on_relationship_deleted(&rel);
1178 true
1179 }
1180 None => false,
1181 };
1182 if applied {
1183 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
1184 }
1185 applied
1186 }
1187
1188 fn delete_node(&mut self, node_id: NodeId) -> bool {
1189 if self.node_at(node_id).is_none() {
1190 return false;
1191 }
1192
1193 if self.has_incident_relationships(node_id) {
1194 return false;
1195 }
1196
1197 let node = match self.take_node(node_id) {
1198 Some(node) => node,
1199 None => return false,
1200 };
1201
1202 if let Some(sink) = &self.deleted_sink {
1203 sink.node_deleted(&node);
1204 }
1205 self.on_node_deleted(&node);
1206
1207 self.emit(|| MutationEvent::DeleteNode { node_id });
1210
1211 true
1212 }
1213
1214 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
1215 if self.node_at(node_id).is_none() {
1216 return false;
1217 }
1218
1219 let rel_ids: Vec<_> = self
1220 .incident_relationship_ids(node_id)
1221 .into_iter()
1222 .collect();
1223
1224 for rel_id in rel_ids {
1233 let _ = self.delete_relationship(rel_id);
1234 }
1235
1236 if self.delete_node(node_id) {
1237 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
1238 true
1239 } else {
1240 false
1241 }
1242 }
1243
1244 fn clear(&mut self) {
1245 let recorder = self.recorder.take();
1249 let deleted_sink = self.deleted_sink.take();
1250 *self = Self::default();
1251 self.recorder = recorder;
1252 self.deleted_sink = deleted_sink;
1253 self.emit(|| MutationEvent::Clear);
1254 }
1255
1256 fn create_index(
1257 &mut self,
1258 request: IndexRequest,
1259 if_not_exists: bool,
1260 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1261 self.register_index(request, if_not_exists)
1267 }
1268
1269 fn drop_index(
1270 &mut self,
1271 name: &str,
1272 if_exists: bool,
1273 ) -> Result<DropIndexOutcome, DropIndexError> {
1274 self.drop_named_index(name, if_exists)
1275 }
1276
1277 fn create_constraint(
1278 &mut self,
1279 request: ConstraintRequest,
1280 if_not_exists: bool,
1281 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1282 self.register_constraint(request, if_not_exists)
1283 }
1284
1285 fn drop_constraint(
1286 &mut self,
1287 name: &str,
1288 if_exists: bool,
1289 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1290 self.drop_named_constraint(name, if_exists)
1291 }
1292}