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_holds_other_temporal_kind(
301 &self,
302 label: &str,
303 property: &str,
304 like: &PropertyValue,
305 ) -> Option<bool> {
306 self.sorted_indexes_read(crate::StoredIndexEntity::Node)
307 .holds_other_temporal_kind(label, property, like)
308 }
309
310 fn node_range_ordered_chunk(
311 &self,
312 label: &str,
313 property: &str,
314 lo: Option<&PropertyValue>,
315 hi: Option<&PropertyValue>,
316 descending: bool,
317 after: Option<(&PropertyValue, NodeId)>,
318 max: usize,
319 ) -> Option<Vec<NodeId>> {
320 self.sorted_indexes_read(crate::StoredIndexEntity::Node)
321 .ordered_chunk(label, property, lo, hi, descending, after, max)
322 }
323
324 fn node_point_within_bbox(
325 &self,
326 label: &str,
327 property: &str,
328 ll: (f64, f64),
329 ur: (f64, f64),
330 ) -> Option<Vec<NodeId>> {
331 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
332 let candidates = registry.within_bbox(label, property, ll, ur)?;
333 Some(candidates.into_iter().collect())
334 }
335
336 fn node_point_within_distance(
337 &self,
338 label: &str,
339 property: &str,
340 center: (f64, f64),
341 max_distance: f64,
342 ) -> Option<Vec<NodeId>> {
343 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
344 let candidates = registry.within_distance(label, property, center, max_distance)?;
345 Some(candidates.into_iter().collect())
346 }
347
348 fn relationship_text_candidates(
349 &self,
350 rel_type: &str,
351 property: &str,
352 query: &str,
353 ) -> Option<Vec<RelationshipId>> {
354 let registry = self.text_indexes_read(crate::StoredIndexEntity::Relationship);
355 let candidates = registry.candidates(rel_type, property, query)?;
356 Some(candidates.into_iter().collect())
357 }
358
359 fn relationship_range_candidates(
360 &self,
361 rel_type: &str,
362 property: &str,
363 lo: Option<&PropertyValue>,
364 hi: Option<&PropertyValue>,
365 ) -> Option<Vec<RelationshipId>> {
366 let registry = self.sorted_indexes_read(crate::StoredIndexEntity::Relationship);
367 let candidates = registry.range_candidates(rel_type, property, lo, hi)?;
368 Some(candidates.into_iter().collect())
369 }
370
371 fn relationship_range_holds_other_temporal_kind(
372 &self,
373 rel_type: &str,
374 property: &str,
375 like: &PropertyValue,
376 ) -> Option<bool> {
377 self.sorted_indexes_read(crate::StoredIndexEntity::Relationship)
378 .holds_other_temporal_kind(rel_type, property, like)
379 }
380
381 fn relationship_point_within_bbox(
382 &self,
383 rel_type: &str,
384 property: &str,
385 ll: (f64, f64),
386 ur: (f64, f64),
387 ) -> Option<Vec<RelationshipId>> {
388 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
389 let candidates = registry.within_bbox(rel_type, property, ll, ur)?;
390 Some(candidates.into_iter().collect())
391 }
392
393 fn relationship_point_within_distance(
394 &self,
395 rel_type: &str,
396 property: &str,
397 center: (f64, f64),
398 max_distance: f64,
399 ) -> Option<Vec<RelationshipId>> {
400 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
401 let candidates = registry.within_distance(rel_type, property, center, max_distance)?;
402 Some(candidates.into_iter().collect())
403 }
404
405 fn contains_node(&self, id: NodeId) -> bool {
406 self.node_at(id).is_some()
407 }
408
409 fn node(&self, id: NodeId) -> Option<NodeRecord> {
410 self.node_at(id).cloned()
411 }
412
413 fn all_node_ids(&self) -> Vec<NodeId> {
414 self.iter_node_ids().collect()
415 }
416
417 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId> {
418 match self.nodes_by_label.get(label) {
419 Some(ids) => ids.to_vec(),
420 None => Vec::new(),
421 }
422 }
423
424 fn contains_relationship(&self, id: RelationshipId) -> bool {
425 self.rel_at(id).is_some()
426 }
427
428 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
429 self.rel_at(id).cloned()
430 }
431
432 fn all_rel_ids(&self) -> Vec<RelationshipId> {
433 self.iter_rel_ids().collect()
434 }
435
436 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
437 match self.relationships_by_type.get(rel_type) {
438 Some(ids) => ids.to_vec(),
439 None => Vec::new(),
440 }
441 }
442
443 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)> {
444 self.rel_at(id).map(|r| (r.src, r.dst))
445 }
446
447 fn expand_ids(
448 &self,
449 node_id: NodeId,
450 direction: Direction,
451 types: &[String],
452 ) -> Vec<(RelationshipId, NodeId)> {
453 if self.node_at(node_id).is_none() {
454 return Vec::new();
455 }
456
457 let mut out: Vec<(RelationshipId, NodeId)> = Vec::new();
463
464 let single_type = match types {
465 [single] => Some(single.as_str()),
466 _ => None,
467 };
468 let has_type_filter = !types.is_empty();
469
470 let push_from = |adj: &[RelationshipId],
471 skip_self_loops: bool,
472 out: &mut Vec<(RelationshipId, NodeId)>| {
473 for &rel_id in adj {
474 let Some(rel) = self.rel_at(rel_id) else {
475 continue;
476 };
477 if skip_self_loops && rel.src == node_id && rel.dst == node_id {
478 continue;
479 }
480 if let Some(single) = single_type {
481 if rel.rel_type != single {
482 continue;
483 }
484 } else if has_type_filter && !types.iter().any(|t| t == &rel.rel_type) {
485 continue;
486 }
487 let Some(other_id) = Self::other_endpoint(rel, node_id) else {
488 continue;
489 };
490 out.push((rel_id, other_id));
491 }
492 };
493
494 match direction {
495 Direction::Right => {
496 if let Some(adj) = self.outgoing_at(node_id) {
497 out.reserve(adj.len());
498 push_from(adj, false, &mut out);
499 }
500 }
501 Direction::Left => {
502 if let Some(adj) = self.incoming_at(node_id) {
503 out.reserve(adj.len());
504 push_from(adj, false, &mut out);
505 }
506 }
507 Direction::Undirected => {
508 let out_len = self.outgoing_at(node_id).map(<[_]>::len).unwrap_or(0);
509 let in_len = self.incoming_at(node_id).map(<[_]>::len).unwrap_or(0);
510 out.reserve(out_len + in_len);
511 if let Some(adj) = self.outgoing_at(node_id) {
512 push_from(adj, false, &mut out);
513 }
514 if let Some(adj) = self.incoming_at(node_id) {
515 push_from(adj, true, &mut out);
516 }
517 }
518 }
519
520 out
521 }
522
523 fn try_for_each_expand_id<F, E>(
524 &self,
525 node_id: NodeId,
526 direction: Direction,
527 types: &[String],
528 visit: F,
529 ) -> Result<(), E>
530 where
531 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
532 Self: Sized,
533 {
534 self.try_for_each_adjacent_id(node_id, direction, types, visit)
535 }
536
537 fn all_labels(&self) -> Vec<String> {
538 self.nodes_by_label.keys().cloned().collect()
539 }
540
541 fn all_relationship_types(&self) -> Vec<String> {
542 self.relationships_by_type.keys().cloned().collect()
543 }
544
545 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
548 where
549 F: FnOnce(&NodeRecord) -> R,
550 Self: Sized,
551 {
552 self.node_at(id).map(f)
553 }
554
555 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
556 where
557 F: FnOnce(&RelationshipRecord) -> R,
558 Self: Sized,
559 {
560 self.rel_at(id).map(f)
561 }
562
563 fn has_node(&self, id: NodeId) -> bool {
566 self.node_at(id).is_some()
567 }
568
569 fn has_relationship(&self, id: RelationshipId) -> bool {
570 self.rel_at(id).is_some()
571 }
572
573 fn node_count(&self) -> usize {
574 self.live_node_count
575 }
576
577 fn relationship_count(&self) -> usize {
578 self.live_rel_count
579 }
580
581 fn node_count_by_label(&self, label: &str) -> usize {
582 self.nodes_by_label.get(label).map_or(0, |ids| ids.len())
583 }
584
585 fn all_nodes(&self) -> Vec<NodeRecord> {
588 self.iter_node_records().cloned().collect()
589 }
590
591 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
592 self.nodes_by_label
593 .get(label)
594 .into_iter()
595 .flat_map(|ids| ids.iter())
596 .filter_map(|&id| self.node_at(id).cloned())
597 .collect()
598 }
599
600 fn all_relationships(&self) -> Vec<RelationshipRecord> {
601 self.iter_rel_records().cloned().collect()
602 }
603
604 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
605 self.relationships_by_type
606 .get(rel_type)
607 .into_iter()
608 .flat_map(|ids| ids.iter())
609 .filter_map(|&id| self.rel_at(id).cloned())
610 .collect()
611 }
612
613 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
614 self.relationship_ids_for_direction(node_id, direction)
615 }
616
617 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
618 self.outgoing_at(node_id)
619 .into_iter()
620 .flat_map(|ids| ids.iter())
621 .filter_map(|&id| self.rel_at(id).cloned())
622 .collect()
623 }
624
625 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
626 self.incoming_at(node_id)
627 .into_iter()
628 .flat_map(|ids| ids.iter())
629 .filter_map(|&id| self.rel_at(id).cloned())
630 .collect()
631 }
632
633 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
634 let mut out = Vec::new();
635 let _ = self.try_for_each_expand_id(node_id, direction, &[], |rel_id, _| {
636 if let Some(rel) = self.rel_at(rel_id) {
637 out.push(rel.clone());
638 }
639 Ok::<(), ()>(())
640 });
641 out
642 }
643
644 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
645 match direction {
646 Direction::Right => self.outgoing_at(node_id).map(|s| s.len()).unwrap_or(0),
647 Direction::Left => self.incoming_at(node_id).map(|s| s.len()).unwrap_or(0),
648 Direction::Undirected => {
649 let out_count = self.outgoing_at(node_id).map(<[_]>::len).unwrap_or(0);
650 let incoming_non_self = self
651 .incoming_at(node_id)
652 .into_iter()
653 .flat_map(|ids| ids.iter())
654 .filter(|&&rel_id| {
655 self.rel_at(rel_id)
656 .map(|rel| rel.src != node_id || rel.dst != node_id)
657 .unwrap_or(false)
658 })
659 .count();
660 out_count + incoming_non_self
661 }
662 }
663 }
664
665 fn expand(
666 &self,
667 node_id: NodeId,
668 direction: Direction,
669 types: &[String],
670 ) -> Vec<(RelationshipRecord, NodeRecord)> {
671 if self.node_at(node_id).is_none() {
672 return Vec::new();
673 }
674
675 let mut out = Vec::new();
676 let _ = self.try_for_each_expand_id(node_id, direction, types, |rel_id, other_id| {
677 if let (Some(rel), Some(other)) = (self.rel_at(rel_id), self.node_at(other_id)) {
678 out.push((rel.clone(), other.clone()));
679 }
680 Ok::<(), ()>(())
681 });
682 out
683 }
684
685 fn neighbors(
686 &self,
687 node_id: NodeId,
688 direction: Direction,
689 types: &[String],
690 ) -> Vec<NodeRecord> {
691 let mut out = Vec::new();
692 let _ = self.try_for_each_expand_id(node_id, direction, types, |_, other_id| {
693 if let Some(node) = self.node_at(other_id) {
694 out.push(node.clone());
695 }
696 Ok::<(), ()>(())
697 });
698 out
699 }
700
701 fn all_node_property_keys(&self) -> Vec<String> {
702 let mut keys = BTreeSet::new();
703 for node in self.iter_node_records() {
704 for key in node.properties.keys() {
705 keys.insert(key.to_string());
706 }
707 }
708 keys.into_iter().collect()
709 }
710
711 fn all_relationship_property_keys(&self) -> Vec<String> {
714 let mut keys = BTreeSet::new();
715 for rel in self.iter_rel_records() {
716 for key in rel.properties.keys() {
717 keys.insert(key.to_string());
718 }
719 }
720 keys.into_iter().collect()
721 }
722
723 fn label_property_keys(&self, label: &str) -> Vec<String> {
724 let mut keys = BTreeSet::new();
725
726 if let Some(ids) = self.nodes_by_label.get(label) {
727 for &id in ids.iter() {
728 if let Some(node) = self.node_at(id) {
729 for key in node.properties.keys() {
730 keys.insert(key.to_string());
731 }
732 }
733 }
734 }
735
736 keys.into_iter().collect()
737 }
738
739 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
740 let mut keys = BTreeSet::new();
741
742 if let Some(ids) = self.relationships_by_type.get(rel_type) {
743 for &id in ids.iter() {
744 if let Some(rel) = self.rel_at(id) {
745 for key in rel.properties.keys() {
746 keys.insert(key.to_string());
747 }
748 }
749 }
750 }
751
752 keys.into_iter().collect()
753 }
754
755 fn find_nodes_by_property(
756 &self,
757 label: Option<&str>,
758 key: &str,
759 value: &PropertyValue,
760 ) -> Vec<NodeRecord>
761 where
762 Self: Sized,
763 {
764 if PropertyIndexKey::from_value(value).is_none() {
765 return self.scan_nodes_by_property(label, key, value);
766 }
767
768 self.ensure_node_property_index(key);
769 let indexes = self.indexes_read();
770
771 match label {
772 Some(label) => {
773 let Some(ids) = indexes.node_properties.scoped_ids_for(label, key, value) else {
774 return Vec::new();
775 };
776 ids.iter()
777 .filter_map(|id| self.node_at(id).cloned())
778 .collect()
779 }
780 None => indexes
781 .node_properties
782 .ids_for(key, value)
783 .into_iter()
784 .flat_map(|ids| ids.iter())
785 .filter_map(|id| self.node_at(id).cloned())
786 .collect(),
787 }
788 }
789
790 fn find_node_ids_by_property(
791 &self,
792 label: Option<&str>,
793 key: &str,
794 value: &PropertyValue,
795 ) -> Vec<NodeId>
796 where
797 Self: Sized,
798 {
799 if PropertyIndexKey::from_value(value).is_none() {
800 return self.scan_node_ids_by_property(label, key, value);
801 }
802
803 self.ensure_node_property_index(key);
804 let indexes = self.indexes_read();
805
806 match label {
807 Some(label) => indexes
808 .node_properties
809 .scoped_ids_for(label, key, value)
810 .map(|ids| ids.to_vec())
811 .unwrap_or_default(),
812 None => indexes
813 .node_properties
814 .ids_for(key, value)
815 .map(|ids| ids.to_vec())
816 .unwrap_or_default(),
817 }
818 }
819 fn find_relationships_by_property(
822 &self,
823 rel_type: Option<&str>,
824 key: &str,
825 value: &PropertyValue,
826 ) -> Vec<RelationshipRecord>
827 where
828 Self: Sized,
829 {
830 if PropertyIndexKey::from_value(value).is_none() {
831 return self.scan_relationships_by_property(rel_type, key, value);
832 }
833
834 self.ensure_relationship_property_index(key);
835 let indexes = self.indexes_read();
836
837 match rel_type {
838 Some(rel_type) => {
839 let Some(ids) = indexes
840 .relationship_properties
841 .scoped_ids_for(rel_type, key, value)
842 else {
843 return Vec::new();
844 };
845 ids.iter()
846 .filter_map(|id| self.rel_at(id).cloned())
847 .collect()
848 }
849 None => indexes
850 .relationship_properties
851 .ids_for(key, value)
852 .into_iter()
853 .flat_map(|ids| ids.iter())
854 .filter_map(|id| self.rel_at(id).cloned())
855 .collect(),
856 }
857 }
858
859 fn find_relationship_ids_by_property(
860 &self,
861 rel_type: Option<&str>,
862 key: &str,
863 value: &PropertyValue,
864 ) -> Vec<RelationshipId>
865 where
866 Self: Sized,
867 {
868 if PropertyIndexKey::from_value(value).is_none() {
869 return self.scan_relationship_ids_by_property(rel_type, key, value);
870 }
871
872 self.ensure_relationship_property_index(key);
873 let indexes = self.indexes_read();
874
875 match rel_type {
876 Some(rel_type) => indexes
877 .relationship_properties
878 .scoped_ids_for(rel_type, key, value)
879 .map(|ids| ids.to_vec())
880 .unwrap_or_default(),
881 None => indexes
882 .relationship_properties
883 .ids_for(key, value)
884 .map(|ids| ids.to_vec())
885 .unwrap_or_default(),
886 }
887 }
888
889 fn node_exists_with_label_and_property(
890 &self,
891 label: &str,
892 key: &str,
893 value: &PropertyValue,
894 ) -> bool
895 where
896 Self: Sized,
897 {
898 if PropertyIndexKey::from_value(value).is_none() {
899 return self.any_node_by_property(label, key, value);
900 }
901
902 self.ensure_node_property_index(key);
903 let indexes = self.indexes_read();
904 indexes
905 .node_properties
906 .scoped_ids_for(label, key, value)
907 .map(|ids| !ids.is_empty())
908 .unwrap_or(false)
909 }
910
911 fn relationship_exists_with_type_and_property(
912 &self,
913 rel_type: &str,
914 key: &str,
915 value: &PropertyValue,
916 ) -> bool
917 where
918 Self: Sized,
919 {
920 if PropertyIndexKey::from_value(value).is_none() {
921 return self.any_relationship_by_property(rel_type, key, value);
922 }
923
924 self.ensure_relationship_property_index(key);
925 let indexes = self.indexes_read();
926 indexes
927 .relationship_properties
928 .scoped_ids_for(rel_type, key, value)
929 .map(|ids| !ids.is_empty())
930 .unwrap_or(false)
931 }
932}
933
934impl BorrowedGraphStorage for InMemoryGraph {
935 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord> {
936 self.node_at(id)
937 }
938
939 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord> {
940 self.rel_at(id)
941 }
942
943 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
944 Box::new(self.iter_node_records())
945 }
946
947 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
948 Box::new(
949 self.nodes_by_label
950 .get(label)
951 .into_iter()
952 .flat_map(|ids| ids.iter())
953 .filter_map(|&id| self.node_at(id)),
954 )
955 }
956
957 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
958 Box::new(self.iter_rel_records())
959 }
960
961 fn relationship_refs_by_type(
962 &self,
963 rel_type: &str,
964 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
965 Box::new(
966 self.relationships_by_type
967 .get(rel_type)
968 .into_iter()
969 .flat_map(|ids| ids.iter())
970 .filter_map(|&id| self.rel_at(id)),
971 )
972 }
973}
974
975impl GraphStorageMut for InMemoryGraph {
976 fn try_create_node(
977 &mut self,
978 labels: Vec<String>,
979 properties: Properties,
980 ) -> Option<NodeRecord> {
981 let (id, idx) = self.try_reserve_next_node_slot()?;
982 let labels = Self::normalize_labels(labels);
983
984 let node = NodeRecord {
985 id,
986 labels: labels.clone(),
987 properties,
988 };
989
990 self.put_node_at_slot(idx, node.clone());
991
992 self.on_node_created(&node);
993
994 self.emit(|| MutationEvent::CreateNode {
998 id,
999 labels: node.labels.clone(),
1000 properties: node.properties.clone(),
1001 });
1002
1003 Some(node)
1004 }
1005
1006 fn create_relationship(
1007 &mut self,
1008 src: NodeId,
1009 dst: NodeId,
1010 rel_type: &str,
1011 properties: Properties,
1012 ) -> Option<RelationshipRecord> {
1013 if self.node_at(src).is_none() || self.node_at(dst).is_none() {
1014 return None;
1015 }
1016
1017 let trimmed = rel_type.trim();
1018 if trimmed.is_empty() {
1019 return None;
1020 }
1021
1022 let (id, idx) = self.try_reserve_next_rel_slot()?;
1023 let rel = RelationshipRecord {
1024 id,
1025 src,
1026 dst,
1027 rel_type: trimmed.to_string(),
1028 properties,
1029 };
1030
1031 self.put_rel_at_slot(idx, rel.clone());
1032 self.on_relationship_created(&rel);
1033
1034 self.emit(|| MutationEvent::CreateRelationship {
1035 id,
1036 src,
1037 dst,
1038 rel_type: rel.rel_type.clone(),
1039 properties: rel.properties.clone(),
1040 });
1041
1042 Some(rel)
1043 }
1044
1045 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
1046 if self.node_at(node_id).is_none() {
1047 return false;
1048 }
1049
1050 let old = match self.node_at_mut(node_id) {
1051 Some(node) => {
1055 if let Some(slot) = node.properties.get_mut(key.as_str()) {
1056 Some(std::mem::replace(slot, value.clone()))
1057 } else {
1058 let key_arc = crate::intern(&key);
1059 node.properties.insert(key_arc, value.clone())
1060 }
1061 }
1062 None => return false,
1063 };
1064 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
1065
1066 self.emit(|| MutationEvent::SetNodeProperty {
1067 node_id,
1068 key: key.clone(),
1069 value: value.clone(),
1070 });
1071
1072 true
1073 }
1074
1075 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
1076 let removed = match self.node_at_mut(node_id) {
1077 Some(node) => node.properties.remove(key),
1078 None => return false,
1079 };
1080 let Some(removed) = removed else {
1081 return false;
1082 };
1083
1084 self.on_node_property_removed(node_id, key, &removed);
1085
1086 self.emit(|| MutationEvent::RemoveNodeProperty {
1087 node_id,
1088 key: key.to_string(),
1089 });
1090
1091 true
1092 }
1093
1094 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1095 let label = label.trim();
1096 if label.is_empty() {
1097 return false;
1098 }
1099
1100 let applied = match self.node_at_mut(node_id) {
1101 Some(node) => {
1102 if node.labels.iter().any(|l| l == label) {
1103 return false;
1104 }
1105
1106 node.labels.push(label.to_string());
1107 true
1108 }
1109 None => false,
1110 };
1111 if applied {
1112 self.on_node_label_added(node_id, label);
1113 self.emit(|| MutationEvent::AddNodeLabel {
1114 node_id,
1115 label: label.to_string(),
1116 });
1117 }
1118 applied
1119 }
1120
1121 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1122 let applied = match self.node_at_mut(node_id) {
1123 Some(node) => {
1124 let original_len = node.labels.len();
1125 node.labels.retain(|l| l != label);
1126 node.labels.len() != original_len
1127 }
1128 None => false,
1129 };
1130 if applied {
1131 self.on_node_label_removed(node_id, label);
1132 self.emit(|| MutationEvent::RemoveNodeLabel {
1133 node_id,
1134 label: label.to_string(),
1135 });
1136 }
1137 applied
1138 }
1139
1140 fn set_relationship_property(
1141 &mut self,
1142 rel_id: RelationshipId,
1143 key: String,
1144 value: PropertyValue,
1145 ) -> bool {
1146 if self.rel_at(rel_id).is_none() {
1147 return false;
1148 }
1149
1150 let old = match self.rel_at_mut(rel_id) {
1151 Some(rel) => {
1152 if let Some(slot) = rel.properties.get_mut(key.as_str()) {
1153 Some(std::mem::replace(slot, value.clone()))
1154 } else {
1155 let key_arc = crate::intern(&key);
1156 rel.properties.insert(key_arc, value.clone())
1157 }
1158 }
1159 None => return false,
1160 };
1161 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
1162
1163 self.emit(|| MutationEvent::SetRelationshipProperty {
1164 rel_id,
1165 key: key.clone(),
1166 value: value.clone(),
1167 });
1168
1169 true
1170 }
1171
1172 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
1173 let removed = match self.rel_at_mut(rel_id) {
1174 Some(rel) => rel.properties.remove(key),
1175 None => return false,
1176 };
1177 let Some(removed) = removed else {
1178 return false;
1179 };
1180
1181 self.on_relationship_property_removed(rel_id, key, &removed);
1182
1183 self.emit(|| MutationEvent::RemoveRelationshipProperty {
1184 rel_id,
1185 key: key.to_string(),
1186 });
1187
1188 true
1189 }
1190
1191 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
1192 let applied = match self.take_rel(rel_id) {
1193 Some(rel) => {
1194 if let Some(sink) = &self.deleted_sink {
1195 sink.relationship_deleted(&rel);
1196 }
1197 self.on_relationship_deleted(&rel);
1198 true
1199 }
1200 None => false,
1201 };
1202 if applied {
1203 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
1204 }
1205 applied
1206 }
1207
1208 fn delete_node(&mut self, node_id: NodeId) -> bool {
1209 if self.node_at(node_id).is_none() {
1210 return false;
1211 }
1212
1213 if self.has_incident_relationships(node_id) {
1214 return false;
1215 }
1216
1217 let node = match self.take_node(node_id) {
1218 Some(node) => node,
1219 None => return false,
1220 };
1221
1222 if let Some(sink) = &self.deleted_sink {
1223 sink.node_deleted(&node);
1224 }
1225 self.on_node_deleted(&node);
1226
1227 self.emit(|| MutationEvent::DeleteNode { node_id });
1230
1231 true
1232 }
1233
1234 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
1235 if self.node_at(node_id).is_none() {
1236 return false;
1237 }
1238
1239 let rel_ids: Vec<_> = self
1240 .incident_relationship_ids(node_id)
1241 .into_iter()
1242 .collect();
1243
1244 for rel_id in rel_ids {
1253 let _ = self.delete_relationship(rel_id);
1254 }
1255
1256 if self.delete_node(node_id) {
1257 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
1258 true
1259 } else {
1260 false
1261 }
1262 }
1263
1264 fn clear(&mut self) {
1265 let recorder = self.recorder.take();
1269 let deleted_sink = self.deleted_sink.take();
1270 *self = Self::default();
1271 self.recorder = recorder;
1272 self.deleted_sink = deleted_sink;
1273 self.emit(|| MutationEvent::Clear);
1274 }
1275
1276 fn create_index(
1277 &mut self,
1278 request: IndexRequest,
1279 if_not_exists: bool,
1280 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1281 self.register_index(request, if_not_exists)
1287 }
1288
1289 fn drop_index(
1290 &mut self,
1291 name: &str,
1292 if_exists: bool,
1293 ) -> Result<DropIndexOutcome, DropIndexError> {
1294 self.drop_named_index(name, if_exists)
1295 }
1296
1297 fn create_constraint(
1298 &mut self,
1299 request: ConstraintRequest,
1300 if_not_exists: bool,
1301 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1302 self.register_constraint(request, if_not_exists)
1303 }
1304
1305 fn drop_constraint(
1306 &mut self,
1307 name: &str,
1308 if_exists: bool,
1309 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1310 self.drop_named_constraint(name, if_exists)
1311 }
1312}