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 match label {
478 Some(label) => {
479 let Some(ids) = self.nodes_by_label.get(label) else {
480 return false;
481 };
482 fill_page(ids.iter_from(*cursor), cursor, max, out)
484 }
485 None => {
486 let Ok(from) = usize::try_from(*cursor) else {
488 return false;
489 };
490 let slots = self.nodes.slots_from(from).map(|slot| slot as NodeId);
491 fill_page(slots, cursor, max, out)
492 }
493 }
494 }
495
496 fn contains_relationship(&self, id: RelationshipId) -> bool {
497 self.has_rel_at(id)
498 }
499
500 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
501 self.rel_at(id).map(|r| r.to_record())
502 }
503
504 fn all_rel_ids(&self) -> Vec<RelationshipId> {
505 self.iter_rel_ids().collect()
506 }
507
508 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
509 match self.relationships_by_type.get(rel_type) {
510 Some(ids) => ids.to_vec(),
511 None => Vec::new(),
512 }
513 }
514
515 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)> {
516 self.rel_endpoints_at(id)
517 }
518
519 fn expand_ids(
520 &self,
521 node_id: NodeId,
522 direction: Direction,
523 types: &[String],
524 ) -> Vec<(RelationshipId, NodeId)> {
525 if !self.has_node_at(node_id) {
526 return Vec::new();
527 }
528
529 let mut out: Vec<(RelationshipId, NodeId)> = Vec::new();
530 let _ = self.try_for_each_adjacent_id_unchecked(
531 node_id,
532 direction,
533 types,
534 |rel_id, other_id| {
535 out.push((rel_id, other_id));
536 Ok::<(), ()>(())
537 },
538 );
539 out
540 }
541
542 fn try_for_each_expand_id<F, E>(
543 &self,
544 node_id: NodeId,
545 direction: Direction,
546 types: &[String],
547 visit: F,
548 ) -> Result<(), E>
549 where
550 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
551 Self: Sized,
552 {
553 self.try_for_each_adjacent_id(node_id, direction, types, visit)
554 }
555
556 fn all_labels(&self) -> Vec<String> {
557 self.nodes_by_label.keys().cloned().collect()
558 }
559
560 fn all_relationship_types(&self) -> Vec<String> {
561 self.relationships_by_type.keys().cloned().collect()
562 }
563
564 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
567 where
568 F: FnOnce(NodeRef<'_>) -> R,
569 Self: Sized,
570 {
571 self.node_at(id).map(f)
572 }
573
574 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
575 where
576 F: FnOnce(RelRef<'_>) -> R,
577 Self: Sized,
578 {
579 self.rel_at(id).map(f)
580 }
581
582 fn has_node(&self, id: NodeId) -> bool {
585 self.has_node_at(id)
586 }
587
588 fn has_relationship(&self, id: RelationshipId) -> bool {
589 self.has_rel_at(id)
590 }
591
592 fn node_count(&self) -> usize {
593 self.live_node_count
594 }
595
596 fn relationship_count(&self) -> usize {
597 self.live_rel_count
598 }
599
600 fn node_count_by_label(&self, label: &str) -> usize {
601 self.nodes_by_label.get(label).map_or(0, |ids| ids.len())
602 }
603
604 fn all_nodes(&self) -> Vec<NodeRecord> {
607 self.iter_node_refs().map(|r| r.to_record()).collect()
608 }
609
610 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
611 self.nodes_by_label
612 .get(label)
613 .into_iter()
614 .flat_map(|ids| ids.iter())
615 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
616 .collect()
617 }
618
619 fn all_relationships(&self) -> Vec<RelationshipRecord> {
620 self.iter_rel_refs().map(|r| r.to_record()).collect()
621 }
622
623 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
624 self.relationships_by_type
625 .get(rel_type)
626 .into_iter()
627 .flat_map(|ids| ids.iter())
628 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
629 .collect()
630 }
631
632 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
633 self.relationship_ids_for_direction(node_id, direction)
634 }
635
636 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
637 self.outgoing_at(node_id)
638 .into_iter()
639 .flat_map(|adj| adj.iter())
640 .filter_map(|entry| self.rel_at(entry.rel).map(|r| r.to_record()))
641 .collect()
642 }
643
644 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
645 self.incoming_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 relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
653 let mut out = Vec::new();
654 let _ = self.try_for_each_expand_id(node_id, direction, &[], |rel_id, _| {
655 if let Some(rel) = self.rel_at(rel_id) {
656 out.push(rel.to_record());
657 }
658 Ok::<(), ()>(())
659 });
660 out
661 }
662
663 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
664 let out = || self.outgoing_at(node_id).map_or(0, |adj| adj.count());
666 match direction {
667 Direction::Right => out(),
668 Direction::Left => self.incoming_at(node_id).map_or(0, |adj| adj.count()),
669 Direction::Undirected => {
670 let incoming_non_self = self
671 .incoming_at(node_id)
672 .into_iter()
673 .flat_map(|adj| adj.iter())
674 .filter(|entry| entry.neighbour != node_id)
675 .count();
676 out() + incoming_non_self
677 }
678 }
679 }
680
681 fn expand(
682 &self,
683 node_id: NodeId,
684 direction: Direction,
685 types: &[String],
686 ) -> Vec<(RelationshipRecord, NodeRecord)> {
687 if !self.has_node_at(node_id) {
688 return Vec::new();
689 }
690
691 let mut out = Vec::new();
692 let _ = self.try_for_each_expand_id(node_id, direction, types, |rel_id, other_id| {
693 if let (Some(rel), Some(other)) = (self.rel_at(rel_id), self.node_at(other_id)) {
694 out.push((rel.to_record(), other.to_record()));
695 }
696 Ok::<(), ()>(())
697 });
698 out
699 }
700
701 fn neighbors(
702 &self,
703 node_id: NodeId,
704 direction: Direction,
705 types: &[String],
706 ) -> Vec<NodeRecord> {
707 let mut out = Vec::new();
708 let _ = self.try_for_each_expand_id(node_id, direction, types, |_, other_id| {
709 if let Some(node) = self.node_at(other_id) {
710 out.push(node.to_record());
711 }
712 Ok::<(), ()>(())
713 });
714 out
715 }
716
717 fn all_node_property_keys(&self) -> Vec<String> {
718 let mut keys = BTreeSet::new();
719 for node in self.iter_node_refs() {
720 for key in node.properties().keys() {
721 keys.insert(key.to_string());
722 }
723 }
724 keys.into_iter().collect()
725 }
726
727 fn all_relationship_property_keys(&self) -> Vec<String> {
730 let mut keys = BTreeSet::new();
731 for rel in self.iter_rel_refs() {
732 for key in rel.properties().keys() {
733 keys.insert(key.to_string());
734 }
735 }
736 keys.into_iter().collect()
737 }
738
739 fn label_property_keys(&self, label: &str) -> Vec<String> {
740 let mut keys = BTreeSet::new();
741
742 if let Some(ids) = self.nodes_by_label.get(label) {
743 for id in ids.iter() {
744 if let Some(node) = self.node_at(id) {
745 for key in node.properties().keys() {
746 keys.insert(key.to_string());
747 }
748 }
749 }
750 }
751
752 keys.into_iter().collect()
753 }
754
755 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
756 let mut keys = BTreeSet::new();
757
758 if let Some(ids) = self.relationships_by_type.get(rel_type) {
759 for id in ids.iter() {
760 if let Some(rel) = self.rel_at(id) {
761 for key in rel.properties().keys() {
762 keys.insert(key.to_string());
763 }
764 }
765 }
766 }
767
768 keys.into_iter().collect()
769 }
770
771 fn find_nodes_by_property(
772 &self,
773 label: Option<&str>,
774 key: &str,
775 value: &PropertyValue,
776 ) -> Vec<NodeRecord>
777 where
778 Self: Sized,
779 {
780 if PropertyIndexKey::from_value(value).is_none() {
781 return self.scan_nodes_by_property(label, key, value);
782 }
783
784 self.ensure_node_property_index(key);
785 if label.is_none() {
786 self.ensure_any_scope_node_property_index(key);
787 }
788 let indexes = self.indexes_read();
789
790 match label {
791 Some(label) => {
792 let Some(ids) = indexes.node_properties.scoped_ids_for(label, key, value) else {
793 return Vec::new();
794 };
795 ids.iter()
796 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
797 .collect()
798 }
799 None => indexes
800 .node_properties
801 .ids_for(key, value)
802 .into_iter()
803 .flat_map(|ids| ids.iter())
804 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
805 .collect(),
806 }
807 }
808
809 fn find_node_ids_by_property(
810 &self,
811 label: Option<&str>,
812 key: &str,
813 value: &PropertyValue,
814 ) -> Vec<NodeId>
815 where
816 Self: Sized,
817 {
818 if PropertyIndexKey::from_value(value).is_none() {
819 return self.scan_node_ids_by_property(label, key, value);
820 }
821
822 self.ensure_node_property_index(key);
823 if label.is_none() {
824 self.ensure_any_scope_node_property_index(key);
825 }
826 let indexes = self.indexes_read();
827
828 match label {
829 Some(label) => indexes
830 .node_properties
831 .scoped_ids_for(label, key, value)
832 .map(|ids| ids.to_vec())
833 .unwrap_or_default(),
834 None => indexes
835 .node_properties
836 .ids_for(key, value)
837 .map(|ids| ids.to_vec())
838 .unwrap_or_default(),
839 }
840 }
841 fn find_relationships_by_property(
844 &self,
845 rel_type: Option<&str>,
846 key: &str,
847 value: &PropertyValue,
848 ) -> Vec<RelationshipRecord>
849 where
850 Self: Sized,
851 {
852 if PropertyIndexKey::from_value(value).is_none() {
853 return self.scan_relationships_by_property(rel_type, key, value);
854 }
855
856 self.ensure_relationship_property_index(key);
857 if rel_type.is_none() {
858 self.ensure_any_scope_relationship_property_index(key);
859 }
860 let indexes = self.indexes_read();
861
862 match rel_type {
863 Some(rel_type) => {
864 let Some(ids) = indexes
865 .relationship_properties
866 .scoped_ids_for(rel_type, key, value)
867 else {
868 return Vec::new();
869 };
870 ids.iter()
871 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
872 .collect()
873 }
874 None => indexes
875 .relationship_properties
876 .ids_for(key, value)
877 .into_iter()
878 .flat_map(|ids| ids.iter())
879 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
880 .collect(),
881 }
882 }
883
884 fn find_relationship_ids_by_property(
885 &self,
886 rel_type: Option<&str>,
887 key: &str,
888 value: &PropertyValue,
889 ) -> Vec<RelationshipId>
890 where
891 Self: Sized,
892 {
893 if PropertyIndexKey::from_value(value).is_none() {
894 return self.scan_relationship_ids_by_property(rel_type, key, value);
895 }
896
897 self.ensure_relationship_property_index(key);
898 if rel_type.is_none() {
899 self.ensure_any_scope_relationship_property_index(key);
900 }
901 let indexes = self.indexes_read();
902
903 match rel_type {
904 Some(rel_type) => indexes
905 .relationship_properties
906 .scoped_ids_for(rel_type, key, value)
907 .map(|ids| ids.to_vec())
908 .unwrap_or_default(),
909 None => indexes
910 .relationship_properties
911 .ids_for(key, value)
912 .map(|ids| ids.to_vec())
913 .unwrap_or_default(),
914 }
915 }
916
917 fn node_exists_with_label_and_property(
918 &self,
919 label: &str,
920 key: &str,
921 value: &PropertyValue,
922 ) -> bool
923 where
924 Self: Sized,
925 {
926 if PropertyIndexKey::from_value(value).is_none() {
927 return self.any_node_by_property(label, key, value);
928 }
929
930 self.ensure_node_property_index(key);
931 let indexes = self.indexes_read();
932 indexes
933 .node_properties
934 .scoped_ids_for(label, key, value)
935 .map(|ids| !ids.is_empty())
936 .unwrap_or(false)
937 }
938
939 fn relationship_exists_with_type_and_property(
940 &self,
941 rel_type: &str,
942 key: &str,
943 value: &PropertyValue,
944 ) -> bool
945 where
946 Self: Sized,
947 {
948 if PropertyIndexKey::from_value(value).is_none() {
949 return self.any_relationship_by_property(rel_type, key, value);
950 }
951
952 self.ensure_relationship_property_index(key);
953 let indexes = self.indexes_read();
954 indexes
955 .relationship_properties
956 .scoped_ids_for(rel_type, key, value)
957 .map(|ids| !ids.is_empty())
958 .unwrap_or(false)
959 }
960}
961
962impl GraphStorageMut for InMemoryGraph {
963 fn try_create_node(
964 &mut self,
965 labels: Vec<String>,
966 properties: Properties,
967 ) -> Option<NodeRecord> {
968 let (id, idx) = self.try_reserve_next_node_slot()?;
969 let labels = Self::normalize_labels(labels);
970
971 let node = NodeRecord {
972 id,
973 labels,
974 properties,
975 };
976
977 self.put_node_at_slot(idx, &node);
978
979 self.on_node_created(&node);
980
981 self.emit(|| MutationEvent::CreateNode {
985 id,
986 labels: node.labels.to_strings(),
987 properties: node.properties.clone(),
988 });
989
990 Some(node)
991 }
992
993 fn create_relationship(
994 &mut self,
995 src: NodeId,
996 dst: NodeId,
997 rel_type: &str,
998 properties: Properties,
999 ) -> Option<RelationshipRecord> {
1000 if !self.has_node_at(src) || !self.has_node_at(dst) {
1001 return None;
1002 }
1003
1004 let trimmed = rel_type.trim();
1005 if trimmed.is_empty() {
1006 return None;
1007 }
1008
1009 let (id, idx) = self.try_reserve_next_rel_slot()?;
1010 let rel = RelationshipRecord {
1011 id,
1012 src,
1013 dst,
1014 rel_type: trimmed.into(),
1015 properties,
1016 };
1017
1018 self.put_rel_at_slot(idx, &rel);
1019 self.on_relationship_created(&rel);
1020
1021 self.emit(|| MutationEvent::CreateRelationship {
1022 id,
1023 src,
1024 dst,
1025 rel_type: rel.rel_type.to_string(),
1026 properties: rel.properties.clone(),
1027 });
1028
1029 Some(rel)
1030 }
1031
1032 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
1033 let Some(old) = self.edit_node_property(node_id, &key, PropEdit::Set(&value)) else {
1034 return false;
1035 };
1036 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
1037
1038 self.emit(|| MutationEvent::SetNodeProperty {
1039 node_id,
1040 key: key.clone(),
1041 value: value.clone(),
1042 });
1043
1044 true
1045 }
1046
1047 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
1048 let Some(removed) = self
1049 .edit_node_property(node_id, key, PropEdit::Remove)
1050 .flatten()
1051 else {
1052 return false;
1053 };
1054
1055 self.on_node_property_removed(node_id, key, &removed);
1056
1057 self.emit(|| MutationEvent::RemoveNodeProperty {
1058 node_id,
1059 key: key.to_string(),
1060 });
1061
1062 true
1063 }
1064
1065 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1066 let label = label.trim();
1067 if label.is_empty() {
1068 return false;
1069 }
1070
1071 let applied = match self.node_at(node_id) {
1072 Some(node) if node.has_label(label) => return false,
1073 Some(_) => self
1074 .update_node(node_id, |node| node.labels.push(label))
1075 .is_some(),
1076 None => false,
1077 };
1078 if applied {
1079 self.on_node_label_added(node_id, label);
1080 self.emit(|| MutationEvent::AddNodeLabel {
1081 node_id,
1082 label: label.to_string(),
1083 });
1084 }
1085 applied
1086 }
1087
1088 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1089 let applied = self
1090 .node_at(node_id)
1091 .is_some_and(|node| node.has_label(label))
1092 && self
1093 .update_node(node_id, |node| node.labels.retain(|l| l != label))
1094 .is_some();
1095 if applied {
1096 self.on_node_label_removed(node_id, label);
1097 self.emit(|| MutationEvent::RemoveNodeLabel {
1098 node_id,
1099 label: label.to_string(),
1100 });
1101 }
1102 applied
1103 }
1104
1105 fn set_relationship_property(
1106 &mut self,
1107 rel_id: RelationshipId,
1108 key: String,
1109 value: PropertyValue,
1110 ) -> bool {
1111 let Some(old) = self.edit_rel_property(rel_id, &key, PropEdit::Set(&value)) else {
1112 return false;
1113 };
1114 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
1115
1116 self.emit(|| MutationEvent::SetRelationshipProperty {
1117 rel_id,
1118 key: key.clone(),
1119 value: value.clone(),
1120 });
1121
1122 true
1123 }
1124
1125 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
1126 let Some(removed) = self
1127 .edit_rel_property(rel_id, key, PropEdit::Remove)
1128 .flatten()
1129 else {
1130 return false;
1131 };
1132
1133 self.on_relationship_property_removed(rel_id, key, &removed);
1134
1135 self.emit(|| MutationEvent::RemoveRelationshipProperty {
1136 rel_id,
1137 key: key.to_string(),
1138 });
1139
1140 true
1141 }
1142
1143 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
1144 let applied = match self.take_rel(rel_id) {
1145 Some(rel) => {
1146 if let Some(sink) = &self.deleted_sink {
1147 sink.relationship_deleted(&rel);
1148 }
1149 self.on_relationship_deleted(&rel);
1150 true
1151 }
1152 None => false,
1153 };
1154 if applied {
1155 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
1156 }
1157 applied
1158 }
1159
1160 fn delete_node(&mut self, node_id: NodeId) -> bool {
1161 if !self.has_node_at(node_id) {
1162 return false;
1163 }
1164
1165 if self.has_incident_relationships(node_id) {
1166 return false;
1167 }
1168
1169 let node = match self.take_node(node_id) {
1170 Some(node) => node,
1171 None => return false,
1172 };
1173
1174 if let Some(sink) = &self.deleted_sink {
1175 sink.node_deleted(&node);
1176 }
1177 self.on_node_deleted(&node);
1178
1179 self.emit(|| MutationEvent::DeleteNode { node_id });
1182
1183 true
1184 }
1185
1186 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
1187 if !self.has_node_at(node_id) {
1188 return false;
1189 }
1190
1191 let rel_ids: Vec<_> = self
1192 .incident_relationship_ids(node_id)
1193 .into_iter()
1194 .collect();
1195
1196 for rel_id in rel_ids {
1205 let _ = self.delete_relationship(rel_id);
1206 }
1207
1208 if self.delete_node(node_id) {
1209 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
1210 true
1211 } else {
1212 false
1213 }
1214 }
1215
1216 fn clear(&mut self) {
1217 let recorder = self.recorder.take();
1221 let deleted_sink = self.deleted_sink.take();
1222 *self = Self::default();
1223 self.recorder = recorder;
1224 self.deleted_sink = deleted_sink;
1225 self.emit(|| MutationEvent::Clear);
1226 }
1227
1228 fn create_index(
1229 &mut self,
1230 request: IndexRequest,
1231 if_not_exists: bool,
1232 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1233 self.register_index(request, if_not_exists)
1239 }
1240
1241 fn drop_index(
1242 &mut self,
1243 name: &str,
1244 if_exists: bool,
1245 ) -> Result<DropIndexOutcome, DropIndexError> {
1246 self.drop_named_index(name, if_exists)
1247 }
1248
1249 fn create_constraint(
1250 &mut self,
1251 request: ConstraintRequest,
1252 if_not_exists: bool,
1253 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1254 self.register_constraint(request, if_not_exists)
1255 }
1256
1257 fn drop_constraint(
1258 &mut self,
1259 name: &str,
1260 if_exists: bool,
1261 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1262 self.drop_named_constraint(name, if_exists)
1263 }
1264}
1265
1266#[inline]
1269fn fill_page(
1270 mut ids: impl Iterator<Item = NodeId>,
1271 cursor: &mut u64,
1272 max: usize,
1273 out: &mut Vec<NodeId>,
1274) -> bool {
1275 for id in ids.by_ref().take(max) {
1276 out.push(id);
1277 *cursor = id.saturating_add(1);
1278 }
1279 ids.next().is_some()
1280}