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