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_list_element_candidates(
375 &self,
376 label: &str,
377 property: &str,
378 element: &PropertyValue,
379 ) -> Option<Vec<NodeId>> {
380 self.sorted_indexes_read(crate::StoredIndexEntity::Node)
381 .element_candidates(label, property, element)
382 }
383
384 fn relationship_list_element_candidates(
385 &self,
386 rel_type: &str,
387 property: &str,
388 element: &PropertyValue,
389 ) -> Option<Vec<RelationshipId>> {
390 self.sorted_indexes_read(crate::StoredIndexEntity::Relationship)
391 .element_candidates(rel_type, property, element)
392 }
393
394 fn node_point_within_bbox(
395 &self,
396 label: &str,
397 property: &str,
398 ll: (f64, f64),
399 ur: (f64, f64),
400 ) -> Option<Vec<NodeId>> {
401 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
402 let candidates = registry.within_bbox(label, property, ll, ur)?;
403 Some(candidates.into_iter().collect())
404 }
405
406 fn node_point_within_distance(
407 &self,
408 label: &str,
409 property: &str,
410 center: (f64, f64),
411 max_distance: f64,
412 ) -> Option<Vec<NodeId>> {
413 let registry = self.point_indexes_read(crate::StoredIndexEntity::Node);
414 let candidates = registry.within_distance(label, property, center, max_distance)?;
415 Some(candidates.into_iter().collect())
416 }
417
418 fn relationship_text_candidates(
419 &self,
420 rel_type: &str,
421 property: &str,
422 query: &str,
423 ) -> Option<Vec<RelationshipId>> {
424 let registry = self.text_indexes_read(crate::StoredIndexEntity::Relationship);
425 let candidates = registry.candidates(rel_type, property, query)?;
426 Some(candidates.into_iter().collect())
427 }
428
429 fn relationship_range_candidates(
430 &self,
431 rel_type: &str,
432 property: &str,
433 lo: Option<&PropertyValue>,
434 hi: Option<&PropertyValue>,
435 ) -> Option<Vec<RelationshipId>> {
436 let registry = self.sorted_indexes_read(crate::StoredIndexEntity::Relationship);
437 let candidates = registry.range_candidates(rel_type, property, lo, hi)?;
438 Some(candidates.into_iter().collect())
439 }
440
441 fn relationship_range_other_temporal_kind_ids(
442 &self,
443 rel_type: &str,
444 property: &str,
445 like: &PropertyValue,
446 ) -> Option<Vec<RelationshipId>> {
447 self.sorted_indexes_read(crate::StoredIndexEntity::Relationship)
448 .other_temporal_kind_ids(rel_type, property, like)
449 }
450
451 fn relationship_point_within_bbox(
452 &self,
453 rel_type: &str,
454 property: &str,
455 ll: (f64, f64),
456 ur: (f64, f64),
457 ) -> Option<Vec<RelationshipId>> {
458 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
459 let candidates = registry.within_bbox(rel_type, property, ll, ur)?;
460 Some(candidates.into_iter().collect())
461 }
462
463 fn relationship_point_within_distance(
464 &self,
465 rel_type: &str,
466 property: &str,
467 center: (f64, f64),
468 max_distance: f64,
469 ) -> Option<Vec<RelationshipId>> {
470 let registry = self.point_indexes_read(crate::StoredIndexEntity::Relationship);
471 let candidates = registry.within_distance(rel_type, property, center, max_distance)?;
472 Some(candidates.into_iter().collect())
473 }
474
475 fn contains_node(&self, id: NodeId) -> bool {
476 self.has_node_at(id)
477 }
478
479 fn node(&self, id: NodeId) -> Option<NodeRecord> {
480 self.node_at(id).map(|r| r.to_record())
481 }
482
483 fn all_node_ids(&self) -> Vec<NodeId> {
484 self.iter_node_ids().collect()
485 }
486
487 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId> {
488 match self.nodes_by_label.get(label) {
489 Some(ids) => ids.to_vec(),
490 None => Vec::new(),
491 }
492 }
493
494 fn scan_node_ids(
495 &self,
496 label: Option<&str>,
497 cursor: &mut u64,
498 max: usize,
499 out: &mut Vec<NodeId>,
500 ) -> bool {
501 let max = max.max(1);
502 match label {
503 Some(label) => {
504 let Some(ids) = self.nodes_by_label.get(label) else {
505 return false;
506 };
507 fill_page(ids.iter_from(*cursor), cursor, max, out)
509 }
510 None => {
511 let Ok(from) = usize::try_from(*cursor) else {
513 return false;
514 };
515 let slots = self.nodes.slots_from(from).map(|slot| slot as NodeId);
516 fill_page(slots, cursor, max, out)
517 }
518 }
519 }
520
521 fn contains_relationship(&self, id: RelationshipId) -> bool {
522 self.has_rel_at(id)
523 }
524
525 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord> {
526 self.rel_at(id).map(|r| r.to_record())
527 }
528
529 fn all_rel_ids(&self) -> Vec<RelationshipId> {
530 self.iter_rel_ids().collect()
531 }
532
533 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId> {
534 match self.relationships_by_type.get(rel_type) {
535 Some(ids) => ids.to_vec(),
536 None => Vec::new(),
537 }
538 }
539
540 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)> {
541 self.rel_endpoints_at(id)
542 }
543
544 fn expand_ids(
545 &self,
546 node_id: NodeId,
547 direction: Direction,
548 types: &[String],
549 ) -> Vec<(RelationshipId, NodeId)> {
550 if !self.has_node_at(node_id) {
551 return Vec::new();
552 }
553
554 let mut out: Vec<(RelationshipId, NodeId)> = Vec::new();
555 let _ = self.try_for_each_adjacent_id_unchecked(
556 node_id,
557 direction,
558 types,
559 |rel_id, other_id| {
560 out.push((rel_id, other_id));
561 Ok::<(), ()>(())
562 },
563 );
564 out
565 }
566
567 fn try_for_each_expand_id<F, E>(
568 &self,
569 node_id: NodeId,
570 direction: Direction,
571 types: &[String],
572 visit: F,
573 ) -> Result<(), E>
574 where
575 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
576 Self: Sized,
577 {
578 self.try_for_each_adjacent_id(node_id, direction, types, visit)
579 }
580
581 fn all_labels(&self) -> Vec<String> {
582 self.nodes_by_label.keys().map(|k| k.to_string()).collect()
583 }
584
585 fn all_relationship_types(&self) -> Vec<String> {
586 self.relationships_by_type
587 .keys()
588 .map(|k| k.to_string())
589 .collect()
590 }
591
592 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
595 where
596 F: FnOnce(NodeRef<'_>) -> R,
597 Self: Sized,
598 {
599 self.node_at(id).map(f)
600 }
601
602 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
603 where
604 F: FnOnce(RelRef<'_>) -> R,
605 Self: Sized,
606 {
607 self.rel_at(id).map(f)
608 }
609
610 fn has_node(&self, id: NodeId) -> bool {
613 self.has_node_at(id)
614 }
615
616 fn has_relationship(&self, id: RelationshipId) -> bool {
617 self.has_rel_at(id)
618 }
619
620 fn node_count(&self) -> usize {
621 self.live_node_count
622 }
623
624 fn relationship_count(&self) -> usize {
625 self.live_rel_count
626 }
627
628 fn node_count_by_label(&self, label: &str) -> usize {
629 self.nodes_by_label.get(label).map_or(0, |ids| ids.len())
630 }
631
632 fn all_nodes(&self) -> Vec<NodeRecord> {
635 self.iter_node_refs().map(|r| r.to_record()).collect()
636 }
637
638 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
639 self.nodes_by_label
640 .get(label)
641 .into_iter()
642 .flat_map(|ids| ids.iter())
643 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
644 .collect()
645 }
646
647 fn all_relationships(&self) -> Vec<RelationshipRecord> {
648 self.iter_rel_refs().map(|r| r.to_record()).collect()
649 }
650
651 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
652 self.relationships_by_type
653 .get(rel_type)
654 .into_iter()
655 .flat_map(|ids| ids.iter())
656 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
657 .collect()
658 }
659
660 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
661 self.relationship_ids_for_direction(node_id, direction)
662 }
663
664 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
665 self.outgoing_at(node_id)
666 .into_iter()
667 .flat_map(|adj| adj.iter())
668 .filter_map(|entry| self.rel_at(entry.rel).map(|r| r.to_record()))
669 .collect()
670 }
671
672 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
673 self.incoming_at(node_id)
674 .into_iter()
675 .flat_map(|adj| adj.iter())
676 .filter_map(|entry| self.rel_at(entry.rel).map(|r| r.to_record()))
677 .collect()
678 }
679
680 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
681 let mut out = Vec::new();
682 let _ = self.try_for_each_expand_id(node_id, direction, &[], |rel_id, _| {
683 if let Some(rel) = self.rel_at(rel_id) {
684 out.push(rel.to_record());
685 }
686 Ok::<(), ()>(())
687 });
688 out
689 }
690
691 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
692 let out = || self.outgoing_at(node_id).map_or(0, |adj| adj.count());
694 match direction {
695 Direction::Right => out(),
696 Direction::Left => self.incoming_at(node_id).map_or(0, |adj| adj.count()),
697 Direction::Undirected => {
698 let incoming_non_self = self
699 .incoming_at(node_id)
700 .into_iter()
701 .flat_map(|adj| adj.iter())
702 .filter(|entry| entry.neighbour != node_id)
703 .count();
704 out() + incoming_non_self
705 }
706 }
707 }
708
709 fn expand(
710 &self,
711 node_id: NodeId,
712 direction: Direction,
713 types: &[String],
714 ) -> Vec<(RelationshipRecord, NodeRecord)> {
715 if !self.has_node_at(node_id) {
716 return Vec::new();
717 }
718
719 let mut out = Vec::new();
720 let _ = self.try_for_each_expand_id(node_id, direction, types, |rel_id, other_id| {
721 if let (Some(rel), Some(other)) = (self.rel_at(rel_id), self.node_at(other_id)) {
722 out.push((rel.to_record(), other.to_record()));
723 }
724 Ok::<(), ()>(())
725 });
726 out
727 }
728
729 fn neighbors(
730 &self,
731 node_id: NodeId,
732 direction: Direction,
733 types: &[String],
734 ) -> Vec<NodeRecord> {
735 let mut out = Vec::new();
736 let _ = self.try_for_each_expand_id(node_id, direction, types, |_, other_id| {
737 if let Some(node) = self.node_at(other_id) {
738 out.push(node.to_record());
739 }
740 Ok::<(), ()>(())
741 });
742 out
743 }
744
745 fn all_node_property_keys(&self) -> Vec<String> {
746 let mut keys = BTreeSet::new();
747 for node in self.iter_node_refs() {
748 for key in node.properties().keys() {
749 keys.insert(key.to_string());
750 }
751 }
752 keys.into_iter().collect()
753 }
754
755 fn all_relationship_property_keys(&self) -> Vec<String> {
758 let mut keys = BTreeSet::new();
759 for rel in self.iter_rel_refs() {
760 for key in rel.properties().keys() {
761 keys.insert(key.to_string());
762 }
763 }
764 keys.into_iter().collect()
765 }
766
767 fn label_property_keys(&self, label: &str) -> Vec<String> {
768 let mut keys = BTreeSet::new();
769
770 if let Some(ids) = self.nodes_by_label.get(label) {
771 for id in ids.iter() {
772 if let Some(node) = self.node_at(id) {
773 for key in node.properties().keys() {
774 keys.insert(key.to_string());
775 }
776 }
777 }
778 }
779
780 keys.into_iter().collect()
781 }
782
783 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String> {
784 let mut keys = BTreeSet::new();
785
786 if let Some(ids) = self.relationships_by_type.get(rel_type) {
787 for id in ids.iter() {
788 if let Some(rel) = self.rel_at(id) {
789 for key in rel.properties().keys() {
790 keys.insert(key.to_string());
791 }
792 }
793 }
794 }
795
796 keys.into_iter().collect()
797 }
798
799 fn find_nodes_by_property(
800 &self,
801 label: Option<&str>,
802 key: &str,
803 value: &PropertyValue,
804 ) -> Vec<NodeRecord>
805 where
806 Self: Sized,
807 {
808 if PropertyIndexKey::from_value(value).is_none() {
809 return self.scan_nodes_by_property(label, key, value);
810 }
811
812 self.ensure_node_property_index(key);
813 if label.is_none() {
814 self.ensure_any_scope_node_property_index(key);
815 }
816 let indexes = self.indexes_read();
817
818 match label {
819 Some(label) => {
820 let Some(ids) =
821 indexes
822 .node_properties
823 .scoped_ids_for(label, key, value, &self.node_values())
824 else {
825 return Vec::new();
826 };
827 ids.iter()
828 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
829 .collect()
830 }
831 None => indexes
832 .node_properties
833 .ids_for(key, value, &self.node_values())
834 .into_iter()
835 .flat_map(|ids| ids.iter())
836 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
837 .collect(),
838 }
839 }
840
841 fn find_node_ids_by_property(
842 &self,
843 label: Option<&str>,
844 key: &str,
845 value: &PropertyValue,
846 ) -> Vec<NodeId>
847 where
848 Self: Sized,
849 {
850 if PropertyIndexKey::from_value(value).is_none() {
851 return self.scan_node_ids_by_property(label, key, value);
852 }
853
854 self.ensure_node_property_index(key);
855 if label.is_none() {
856 self.ensure_any_scope_node_property_index(key);
857 }
858 let indexes = self.indexes_read();
859
860 match label {
861 Some(label) => indexes
862 .node_properties
863 .scoped_ids_for(label, key, value, &self.node_values())
864 .map(|ids| ids.to_vec())
865 .unwrap_or_default(),
866 None => indexes
867 .node_properties
868 .ids_for(key, value, &self.node_values())
869 .map(|ids| ids.to_vec())
870 .unwrap_or_default(),
871 }
872 }
873 fn find_relationships_by_property(
876 &self,
877 rel_type: Option<&str>,
878 key: &str,
879 value: &PropertyValue,
880 ) -> Vec<RelationshipRecord>
881 where
882 Self: Sized,
883 {
884 if PropertyIndexKey::from_value(value).is_none() {
885 return self.scan_relationships_by_property(rel_type, key, value);
886 }
887
888 self.ensure_relationship_property_index(key);
889 if rel_type.is_none() {
890 self.ensure_any_scope_relationship_property_index(key);
891 }
892 let indexes = self.indexes_read();
893
894 match rel_type {
895 Some(rel_type) => {
896 let Some(ids) = indexes.relationship_properties.scoped_ids_for(
897 rel_type,
898 key,
899 value,
900 &self.relationship_values(),
901 ) else {
902 return Vec::new();
903 };
904 ids.iter()
905 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
906 .collect()
907 }
908 None => indexes
909 .relationship_properties
910 .ids_for(key, value, &self.relationship_values())
911 .into_iter()
912 .flat_map(|ids| ids.iter())
913 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
914 .collect(),
915 }
916 }
917
918 fn find_relationship_ids_by_property(
919 &self,
920 rel_type: Option<&str>,
921 key: &str,
922 value: &PropertyValue,
923 ) -> Vec<RelationshipId>
924 where
925 Self: Sized,
926 {
927 if PropertyIndexKey::from_value(value).is_none() {
928 return self.scan_relationship_ids_by_property(rel_type, key, value);
929 }
930
931 self.ensure_relationship_property_index(key);
932 if rel_type.is_none() {
933 self.ensure_any_scope_relationship_property_index(key);
934 }
935 let indexes = self.indexes_read();
936
937 match rel_type {
938 Some(rel_type) => indexes
939 .relationship_properties
940 .scoped_ids_for(rel_type, key, value, &self.relationship_values())
941 .map(|ids| ids.to_vec())
942 .unwrap_or_default(),
943 None => indexes
944 .relationship_properties
945 .ids_for(key, value, &self.relationship_values())
946 .map(|ids| ids.to_vec())
947 .unwrap_or_default(),
948 }
949 }
950
951 fn node_exists_with_label_and_property(
952 &self,
953 label: &str,
954 key: &str,
955 value: &PropertyValue,
956 ) -> bool
957 where
958 Self: Sized,
959 {
960 if PropertyIndexKey::from_value(value).is_none() {
961 return self.any_node_by_property(label, key, value);
962 }
963
964 self.ensure_node_property_index(key);
965 let indexes = self.indexes_read();
966 indexes
967 .node_properties
968 .scoped_ids_for(label, key, value, &self.node_values())
969 .map(|ids| !ids.is_empty())
970 .unwrap_or(false)
971 }
972
973 fn relationship_exists_with_type_and_property(
974 &self,
975 rel_type: &str,
976 key: &str,
977 value: &PropertyValue,
978 ) -> bool
979 where
980 Self: Sized,
981 {
982 if PropertyIndexKey::from_value(value).is_none() {
983 return self.any_relationship_by_property(rel_type, key, value);
984 }
985
986 self.ensure_relationship_property_index(key);
987 let indexes = self.indexes_read();
988 indexes
989 .relationship_properties
990 .scoped_ids_for(rel_type, key, value, &self.relationship_values())
991 .map(|ids| !ids.is_empty())
992 .unwrap_or(false)
993 }
994}
995
996impl InMemoryGraph {
997 fn delete_relationship_deferring(
1001 &mut self,
1002 rel_id: RelationshipId,
1003 pending: Option<&mut PendingAdjRemovals>,
1004 ) -> bool {
1005 let applied = match self.take_rel(rel_id) {
1006 Some(rel) => {
1007 if let Some(sink) = &self.deleted_sink {
1008 sink.relationship_deleted(&rel);
1009 }
1010 self.on_relationship_deleted(&rel, pending);
1011 true
1012 }
1013 None => false,
1014 };
1015 if applied {
1016 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
1017 }
1018 applied
1019 }
1020
1021 fn detach_delete_deferring(
1027 &mut self,
1028 node_id: NodeId,
1029 pending: &mut PendingAdjRemovals,
1030 ) -> bool {
1031 if !self.has_node_at(node_id) {
1032 return false;
1033 }
1034
1035 let rel_ids = self.incident_relationship_ids(node_id);
1036
1037 self.clear_adjacency(node_id);
1048 for rel_id in rel_ids {
1049 let _ = self.delete_relationship_deferring(rel_id, Some(pending));
1050 }
1051
1052 if self.delete_node(node_id) {
1053 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
1054 true
1055 } else {
1056 false
1057 }
1058 }
1059}
1060
1061impl GraphStorageMut for InMemoryGraph {
1062 fn try_create_node(
1063 &mut self,
1064 labels: Vec<String>,
1065 properties: Properties,
1066 ) -> Option<NodeRecord> {
1067 let (id, idx) = self.try_reserve_next_node_slot()?;
1068 let labels = Self::normalize_labels(labels);
1069
1070 let node = NodeRecord {
1071 id,
1072 labels,
1073 properties,
1074 };
1075
1076 self.put_node_at_slot(idx, &node);
1077
1078 self.on_node_created(&node);
1079
1080 self.emit(|| MutationEvent::CreateNode {
1084 id,
1085 labels: node.labels.to_strings(),
1086 properties: node.properties.clone(),
1087 });
1088
1089 Some(node)
1090 }
1091
1092 fn create_relationship(
1093 &mut self,
1094 src: NodeId,
1095 dst: NodeId,
1096 rel_type: &str,
1097 properties: Properties,
1098 ) -> Option<RelationshipRecord> {
1099 if !self.has_node_at(src) || !self.has_node_at(dst) {
1100 return None;
1101 }
1102
1103 let trimmed = rel_type.trim();
1104 if trimmed.is_empty() {
1105 return None;
1106 }
1107
1108 let (id, idx) = self.try_reserve_next_rel_slot()?;
1109 let rel = RelationshipRecord {
1110 id,
1111 src,
1112 dst,
1113 rel_type: trimmed.into(),
1114 properties,
1115 };
1116
1117 self.put_rel_at_slot(idx, &rel);
1118 self.on_relationship_created(&rel);
1119
1120 self.emit(|| MutationEvent::CreateRelationship {
1121 id,
1122 src,
1123 dst,
1124 rel_type: rel.rel_type.to_string(),
1125 properties: rel.properties.clone(),
1126 });
1127
1128 Some(rel)
1129 }
1130
1131 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
1132 let Some(old) = self.edit_node_property(node_id, &key, PropEdit::Set(&value)) else {
1133 return false;
1134 };
1135 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
1136
1137 self.emit(|| MutationEvent::SetNodeProperty {
1138 node_id,
1139 key: key.clone(),
1140 value: value.clone(),
1141 });
1142
1143 true
1144 }
1145
1146 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
1147 let Some(removed) = self
1148 .edit_node_property(node_id, key, PropEdit::Remove)
1149 .flatten()
1150 else {
1151 return false;
1152 };
1153
1154 self.on_node_property_removed(node_id, key, &removed);
1155
1156 self.emit(|| MutationEvent::RemoveNodeProperty {
1157 node_id,
1158 key: key.to_string(),
1159 });
1160
1161 true
1162 }
1163
1164 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1165 let label = label.trim();
1166 if label.is_empty() {
1167 return false;
1168 }
1169
1170 let applied = match self.node_at(node_id) {
1171 Some(node) if node.has_label(label) => return false,
1172 Some(_) => self
1173 .update_node(node_id, |node| node.labels.push(label))
1174 .is_some(),
1175 None => false,
1176 };
1177 if applied {
1178 self.on_node_label_added(node_id, label);
1179 self.emit(|| MutationEvent::AddNodeLabel {
1180 node_id,
1181 label: label.to_string(),
1182 });
1183 }
1184 applied
1185 }
1186
1187 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1188 let applied = self
1189 .node_at(node_id)
1190 .is_some_and(|node| node.has_label(label))
1191 && self
1192 .update_node(node_id, |node| node.labels.retain(|l| l != label))
1193 .is_some();
1194 if applied {
1195 self.on_node_label_removed(node_id, label);
1196 self.emit(|| MutationEvent::RemoveNodeLabel {
1197 node_id,
1198 label: label.to_string(),
1199 });
1200 }
1201 applied
1202 }
1203
1204 fn set_relationship_property(
1205 &mut self,
1206 rel_id: RelationshipId,
1207 key: String,
1208 value: PropertyValue,
1209 ) -> bool {
1210 let Some(old) = self.edit_rel_property(rel_id, &key, PropEdit::Set(&value)) else {
1211 return false;
1212 };
1213 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
1214
1215 self.emit(|| MutationEvent::SetRelationshipProperty {
1216 rel_id,
1217 key: key.clone(),
1218 value: value.clone(),
1219 });
1220
1221 true
1222 }
1223
1224 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
1225 let Some(removed) = self
1226 .edit_rel_property(rel_id, key, PropEdit::Remove)
1227 .flatten()
1228 else {
1229 return false;
1230 };
1231
1232 self.on_relationship_property_removed(rel_id, key, &removed);
1233
1234 self.emit(|| MutationEvent::RemoveRelationshipProperty {
1235 rel_id,
1236 key: key.to_string(),
1237 });
1238
1239 true
1240 }
1241
1242 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
1243 self.delete_relationship_deferring(rel_id, None)
1244 }
1245
1246 fn delete_relationships(&mut self, rel_ids: &[RelationshipId]) -> usize {
1247 let mut pending = PendingAdjRemovals::new();
1248 let deleted = rel_ids
1249 .iter()
1250 .filter(|&&rel_id| self.delete_relationship_deferring(rel_id, Some(&mut pending)))
1251 .count();
1252 self.flush_adjacency_removals(&mut pending);
1253 deleted
1254 }
1255
1256 fn delete_node(&mut self, node_id: NodeId) -> bool {
1257 if !self.has_node_at(node_id) {
1258 return false;
1259 }
1260
1261 if self.has_incident_relationships(node_id) {
1262 return false;
1263 }
1264
1265 let node = match self.take_node(node_id) {
1266 Some(node) => node,
1267 None => return false,
1268 };
1269
1270 if let Some(sink) = &self.deleted_sink {
1271 sink.node_deleted(&node);
1272 }
1273 self.on_node_deleted(&node);
1274
1275 self.emit(|| MutationEvent::DeleteNode { node_id });
1278
1279 true
1280 }
1281
1282 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
1283 self.detach_delete_nodes(&[node_id]) == 1
1284 }
1285
1286 fn detach_delete_nodes(&mut self, node_ids: &[NodeId]) -> usize {
1287 let mut pending = PendingAdjRemovals::new();
1288 let deleted = node_ids
1289 .iter()
1290 .filter(|&&node_id| self.detach_delete_deferring(node_id, &mut pending))
1291 .count();
1292 self.flush_adjacency_removals(&mut pending);
1293 deleted
1294 }
1295
1296 fn clear(&mut self) {
1297 let recorder = self.recorder.take();
1301 let deleted_sink = self.deleted_sink.take();
1302 *self = Self::default();
1303 self.recorder = recorder;
1304 self.deleted_sink = deleted_sink;
1305 self.emit(|| MutationEvent::Clear);
1306 }
1307
1308 fn create_index(
1309 &mut self,
1310 request: IndexRequest,
1311 if_not_exists: bool,
1312 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1313 self.register_index(request, if_not_exists)
1319 }
1320
1321 fn drop_index(
1322 &mut self,
1323 name: &str,
1324 if_exists: bool,
1325 ) -> Result<DropIndexOutcome, DropIndexError> {
1326 self.drop_named_index(name, if_exists)
1327 }
1328
1329 fn create_constraint(
1330 &mut self,
1331 request: ConstraintRequest,
1332 if_not_exists: bool,
1333 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1334 self.register_constraint(request, if_not_exists)
1335 }
1336
1337 fn drop_constraint(
1338 &mut self,
1339 name: &str,
1340 if_exists: bool,
1341 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1342 self.drop_named_constraint(name, if_exists)
1343 }
1344}
1345
1346#[inline]
1349fn fill_page(
1350 mut ids: impl Iterator<Item = NodeId>,
1351 cursor: &mut u64,
1352 max: usize,
1353 out: &mut Vec<NodeId>,
1354) -> bool {
1355 for id in ids.by_ref().take(max) {
1356 out.push(id);
1357 *cursor = id.saturating_add(1);
1358 }
1359 ids.next().is_some()
1360}