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