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