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 if !self.try_ensure_node_property_index(key) {
813 return self.scan_nodes_by_property(label, key, value);
814 }
815 if label.is_none() {
816 self.ensure_any_scope_node_property_index(key);
817 }
818 let indexes = self.indexes_read();
819
820 match label {
821 Some(label) => {
822 let Some(ids) =
823 indexes
824 .node_properties
825 .scoped_ids_for(label, key, value, &self.node_values())
826 else {
827 return Vec::new();
828 };
829 ids.iter()
830 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
831 .collect()
832 }
833 None => indexes
834 .node_properties
835 .ids_for(key, value, &self.node_values())
836 .into_iter()
837 .flat_map(|ids| ids.iter())
838 .filter_map(|id| self.node_at(id).map(|r| r.to_record()))
839 .collect(),
840 }
841 }
842
843 fn find_node_ids_by_property(
844 &self,
845 label: Option<&str>,
846 key: &str,
847 value: &PropertyValue,
848 ) -> Vec<NodeId>
849 where
850 Self: Sized,
851 {
852 if PropertyIndexKey::from_value(value).is_none() {
853 return self.scan_node_ids_by_property(label, key, value);
854 }
855
856 if !self.try_ensure_node_property_index(key) {
857 return self.scan_node_ids_by_property(label, key, value);
858 }
859 if label.is_none() {
860 self.ensure_any_scope_node_property_index(key);
861 }
862 let indexes = self.indexes_read();
863
864 match label {
865 Some(label) => indexes
866 .node_properties
867 .scoped_ids_for(label, key, value, &self.node_values())
868 .map(|ids| ids.to_vec())
869 .unwrap_or_default(),
870 None => indexes
871 .node_properties
872 .ids_for(key, value, &self.node_values())
873 .map(|ids| ids.to_vec())
874 .unwrap_or_default(),
875 }
876 }
877 fn find_relationships_by_property(
880 &self,
881 rel_type: Option<&str>,
882 key: &str,
883 value: &PropertyValue,
884 ) -> Vec<RelationshipRecord>
885 where
886 Self: Sized,
887 {
888 if PropertyIndexKey::from_value(value).is_none() {
889 return self.scan_relationships_by_property(rel_type, key, value);
890 }
891
892 if !self.try_ensure_relationship_property_index(key) {
893 return self.scan_relationships_by_property(rel_type, key, value);
894 }
895 if rel_type.is_none() {
896 self.ensure_any_scope_relationship_property_index(key);
897 }
898 let indexes = self.indexes_read();
899
900 match rel_type {
901 Some(rel_type) => {
902 let Some(ids) = indexes.relationship_properties.scoped_ids_for(
903 rel_type,
904 key,
905 value,
906 &self.relationship_values(),
907 ) else {
908 return Vec::new();
909 };
910 ids.iter()
911 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
912 .collect()
913 }
914 None => indexes
915 .relationship_properties
916 .ids_for(key, value, &self.relationship_values())
917 .into_iter()
918 .flat_map(|ids| ids.iter())
919 .filter_map(|id| self.rel_at(id).map(|r| r.to_record()))
920 .collect(),
921 }
922 }
923
924 fn find_relationship_ids_by_property(
925 &self,
926 rel_type: Option<&str>,
927 key: &str,
928 value: &PropertyValue,
929 ) -> Vec<RelationshipId>
930 where
931 Self: Sized,
932 {
933 if PropertyIndexKey::from_value(value).is_none() {
934 return self.scan_relationship_ids_by_property(rel_type, key, value);
935 }
936
937 if !self.try_ensure_relationship_property_index(key) {
938 return self.scan_relationship_ids_by_property(rel_type, key, value);
939 }
940 if rel_type.is_none() {
941 self.ensure_any_scope_relationship_property_index(key);
942 }
943 let indexes = self.indexes_read();
944
945 match rel_type {
946 Some(rel_type) => indexes
947 .relationship_properties
948 .scoped_ids_for(rel_type, key, value, &self.relationship_values())
949 .map(|ids| ids.to_vec())
950 .unwrap_or_default(),
951 None => indexes
952 .relationship_properties
953 .ids_for(key, value, &self.relationship_values())
954 .map(|ids| ids.to_vec())
955 .unwrap_or_default(),
956 }
957 }
958
959 fn node_exists_with_label_and_property(
960 &self,
961 label: &str,
962 key: &str,
963 value: &PropertyValue,
964 ) -> bool
965 where
966 Self: Sized,
967 {
968 if PropertyIndexKey::from_value(value).is_none() {
969 return self.any_node_by_property(label, key, value);
970 }
971
972 if !self.try_ensure_node_property_index(key) {
973 return self.any_node_by_property(label, key, value);
974 }
975 let indexes = self.indexes_read();
976 indexes
977 .node_properties
978 .scoped_ids_for(label, key, value, &self.node_values())
979 .map(|ids| !ids.is_empty())
980 .unwrap_or(false)
981 }
982
983 fn relationship_exists_with_type_and_property(
984 &self,
985 rel_type: &str,
986 key: &str,
987 value: &PropertyValue,
988 ) -> bool
989 where
990 Self: Sized,
991 {
992 if PropertyIndexKey::from_value(value).is_none() {
993 return self.any_relationship_by_property(rel_type, key, value);
994 }
995
996 if !self.try_ensure_relationship_property_index(key) {
997 return self.any_relationship_by_property(rel_type, key, value);
998 }
999 let indexes = self.indexes_read();
1000 indexes
1001 .relationship_properties
1002 .scoped_ids_for(rel_type, key, value, &self.relationship_values())
1003 .map(|ids| !ids.is_empty())
1004 .unwrap_or(false)
1005 }
1006}
1007
1008impl InMemoryGraph {
1009 fn delete_relationship_deferring(
1013 &mut self,
1014 rel_id: RelationshipId,
1015 pending: Option<&mut PendingAdjRemovals>,
1016 ) -> bool {
1017 let applied = match self.take_rel(rel_id) {
1018 Some(rel) => {
1019 if let Some(sink) = &self.deleted_sink {
1020 sink.relationship_deleted(&rel);
1021 }
1022 self.on_relationship_deleted(&rel, pending);
1023 true
1024 }
1025 None => false,
1026 };
1027 if applied {
1028 self.emit(|| MutationEvent::DeleteRelationship { rel_id });
1029 }
1030 applied
1031 }
1032
1033 fn detach_delete_deferring(
1039 &mut self,
1040 node_id: NodeId,
1041 pending: &mut PendingAdjRemovals,
1042 ) -> bool {
1043 if !self.has_node_at(node_id) {
1044 return false;
1045 }
1046
1047 let rel_ids = self.incident_relationship_ids(node_id);
1048
1049 self.clear_adjacency(node_id);
1060 for rel_id in rel_ids {
1061 let _ = self.delete_relationship_deferring(rel_id, Some(pending));
1062 }
1063
1064 if self.delete_node(node_id) {
1065 self.emit(|| MutationEvent::DetachDeleteNode { node_id });
1066 true
1067 } else {
1068 false
1069 }
1070 }
1071}
1072
1073impl GraphStorageMut for InMemoryGraph {
1074 fn try_create_node(
1075 &mut self,
1076 labels: Vec<String>,
1077 properties: Properties,
1078 ) -> Option<NodeRecord> {
1079 let (id, idx) = self.try_reserve_next_node_slot()?;
1080 let labels = Self::normalize_labels(labels);
1081
1082 let node = NodeRecord {
1083 id,
1084 labels,
1085 properties,
1086 };
1087
1088 self.put_node_at_slot(idx, &node);
1089
1090 self.on_node_created(&node);
1091
1092 self.emit(|| MutationEvent::CreateNode {
1096 id,
1097 labels: node.labels.to_strings(),
1098 properties: node.properties.clone(),
1099 });
1100
1101 Some(node)
1102 }
1103
1104 fn create_relationship(
1105 &mut self,
1106 src: NodeId,
1107 dst: NodeId,
1108 rel_type: &str,
1109 properties: Properties,
1110 ) -> Option<RelationshipRecord> {
1111 if !self.has_node_at(src) || !self.has_node_at(dst) {
1112 return None;
1113 }
1114
1115 let trimmed = rel_type.trim();
1116 if trimmed.is_empty() {
1117 return None;
1118 }
1119
1120 let (id, idx) = self.try_reserve_next_rel_slot()?;
1121 let rel = RelationshipRecord {
1122 id,
1123 src,
1124 dst,
1125 rel_type: trimmed.into(),
1126 properties,
1127 };
1128
1129 self.put_rel_at_slot(idx, &rel);
1130 self.on_relationship_created(&rel);
1131
1132 self.emit(|| MutationEvent::CreateRelationship {
1133 id,
1134 src,
1135 dst,
1136 rel_type: rel.rel_type.to_string(),
1137 properties: rel.properties.clone(),
1138 });
1139
1140 Some(rel)
1141 }
1142
1143 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool {
1144 let Some(old) = self.edit_node_property(node_id, &key, PropEdit::Set(&value)) else {
1145 return false;
1146 };
1147 self.on_node_property_set(node_id, &key, old.as_ref(), &value);
1148
1149 self.emit(|| MutationEvent::SetNodeProperty {
1150 node_id,
1151 key: key.clone(),
1152 value: value.clone(),
1153 });
1154
1155 true
1156 }
1157
1158 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool {
1159 let Some(removed) = self
1160 .edit_node_property(node_id, key, PropEdit::Remove)
1161 .flatten()
1162 else {
1163 return false;
1164 };
1165
1166 self.on_node_property_removed(node_id, key, &removed);
1167
1168 self.emit(|| MutationEvent::RemoveNodeProperty {
1169 node_id,
1170 key: key.to_string(),
1171 });
1172
1173 true
1174 }
1175
1176 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1177 let label = label.trim();
1178 if label.is_empty() {
1179 return false;
1180 }
1181
1182 let applied = match self.node_at(node_id) {
1183 Some(node) if node.has_label(label) => return false,
1184 Some(_) => self
1185 .update_node(node_id, |node| node.labels.push(label))
1186 .is_some(),
1187 None => false,
1188 };
1189 if applied {
1190 self.on_node_label_added(node_id, label);
1191 self.emit(|| MutationEvent::AddNodeLabel {
1192 node_id,
1193 label: label.to_string(),
1194 });
1195 }
1196 applied
1197 }
1198
1199 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool {
1200 let applied = self
1201 .node_at(node_id)
1202 .is_some_and(|node| node.has_label(label))
1203 && self
1204 .update_node(node_id, |node| node.labels.retain(|l| l != label))
1205 .is_some();
1206 if applied {
1207 self.on_node_label_removed(node_id, label);
1208 self.emit(|| MutationEvent::RemoveNodeLabel {
1209 node_id,
1210 label: label.to_string(),
1211 });
1212 }
1213 applied
1214 }
1215
1216 fn set_relationship_property(
1217 &mut self,
1218 rel_id: RelationshipId,
1219 key: String,
1220 value: PropertyValue,
1221 ) -> bool {
1222 let Some(old) = self.edit_rel_property(rel_id, &key, PropEdit::Set(&value)) else {
1223 return false;
1224 };
1225 self.on_relationship_property_set(rel_id, &key, old.as_ref(), &value);
1226
1227 self.emit(|| MutationEvent::SetRelationshipProperty {
1228 rel_id,
1229 key: key.clone(),
1230 value: value.clone(),
1231 });
1232
1233 true
1234 }
1235
1236 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool {
1237 let Some(removed) = self
1238 .edit_rel_property(rel_id, key, PropEdit::Remove)
1239 .flatten()
1240 else {
1241 return false;
1242 };
1243
1244 self.on_relationship_property_removed(rel_id, key, &removed);
1245
1246 self.emit(|| MutationEvent::RemoveRelationshipProperty {
1247 rel_id,
1248 key: key.to_string(),
1249 });
1250
1251 true
1252 }
1253
1254 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool {
1255 self.delete_relationship_deferring(rel_id, None)
1256 }
1257
1258 fn delete_relationships(&mut self, rel_ids: &[RelationshipId]) -> usize {
1259 let mut pending = PendingAdjRemovals::new();
1260 let deleted = rel_ids
1261 .iter()
1262 .filter(|&&rel_id| self.delete_relationship_deferring(rel_id, Some(&mut pending)))
1263 .count();
1264 self.flush_adjacency_removals(&mut pending);
1265 deleted
1266 }
1267
1268 fn delete_node(&mut self, node_id: NodeId) -> bool {
1269 if !self.has_node_at(node_id) {
1270 return false;
1271 }
1272
1273 if self.has_incident_relationships(node_id) {
1274 return false;
1275 }
1276
1277 let node = match self.take_node(node_id) {
1278 Some(node) => node,
1279 None => return false,
1280 };
1281
1282 if let Some(sink) = &self.deleted_sink {
1283 sink.node_deleted(&node);
1284 }
1285 self.on_node_deleted(&node);
1286
1287 self.emit(|| MutationEvent::DeleteNode { node_id });
1290
1291 true
1292 }
1293
1294 fn detach_delete_node(&mut self, node_id: NodeId) -> bool {
1295 self.detach_delete_nodes(&[node_id]) == 1
1296 }
1297
1298 fn detach_delete_nodes(&mut self, node_ids: &[NodeId]) -> usize {
1299 let mut pending = PendingAdjRemovals::new();
1300 let deleted = node_ids
1301 .iter()
1302 .filter(|&&node_id| self.detach_delete_deferring(node_id, &mut pending))
1303 .count();
1304 self.flush_adjacency_removals(&mut pending);
1305 deleted
1306 }
1307
1308 fn clear(&mut self) {
1309 let recorder = self.recorder.take();
1313 let deleted_sink = self.deleted_sink.take();
1314 *self = Self::default();
1315 self.recorder = recorder;
1316 self.deleted_sink = deleted_sink;
1317 self.emit(|| MutationEvent::Clear);
1318 }
1319
1320 fn create_index(
1321 &mut self,
1322 request: IndexRequest,
1323 if_not_exists: bool,
1324 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1325 self.register_index(request, if_not_exists)
1331 }
1332
1333 fn drop_index(
1334 &mut self,
1335 name: &str,
1336 if_exists: bool,
1337 ) -> Result<DropIndexOutcome, DropIndexError> {
1338 self.drop_named_index(name, if_exists)
1339 }
1340
1341 fn create_constraint(
1342 &mut self,
1343 request: ConstraintRequest,
1344 if_not_exists: bool,
1345 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1346 self.register_constraint(request, if_not_exists)
1347 }
1348
1349 fn drop_constraint(
1350 &mut self,
1351 name: &str,
1352 if_exists: bool,
1353 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1354 self.drop_named_constraint(name, if_exists)
1355 }
1356}
1357
1358#[inline]
1361fn fill_page(
1362 mut ids: impl Iterator<Item = NodeId>,
1363 cursor: &mut u64,
1364 max: usize,
1365 out: &mut Vec<NodeId>,
1366) -> bool {
1367 for id in ids.by_ref().take(max) {
1368 out.push(id);
1369 *cursor = id.saturating_add(1);
1370 }
1371 ids.next().is_some()
1372}