1use std::collections::BTreeSet;
9
10use lora_ast::Direction;
11
12use crate::memory::{
13 ConstraintDefinition, ConstraintRequest, CreateConstraintError, CreateConstraintOutcome,
14 CreateIndexError, CreateIndexOutcome, DropConstraintError, DropConstraintOutcome,
15 DropIndexError, DropIndexOutcome, GraphStats, IndexDefinition, IndexRequest,
16};
17use crate::types::{
18 ExpandedRelationship, LoraVector, NodeId, NodeRecord, Properties, PropertyValue,
19 RelationshipId, RelationshipRecord,
20};
21
22pub trait GraphStorage {
38 fn contains_node(&self, id: NodeId) -> bool;
42
43 fn node(&self, id: NodeId) -> Option<NodeRecord>;
47
48 fn all_node_ids(&self) -> Vec<NodeId>;
50
51 fn node_ids_by_label(&self, label: &str) -> Vec<NodeId>;
54
55 fn contains_relationship(&self, id: RelationshipId) -> bool;
58
59 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord>;
60
61 fn all_rel_ids(&self) -> Vec<RelationshipId>;
62
63 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId>;
64
65 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)>;
69
70 fn expand_ids(
76 &self,
77 node_id: NodeId,
78 direction: Direction,
79 types: &[String],
80 ) -> Vec<(RelationshipId, NodeId)>;
81
82 fn try_for_each_expand_id<F, E>(
86 &self,
87 node_id: NodeId,
88 direction: Direction,
89 types: &[String],
90 mut visit: F,
91 ) -> Result<(), E>
92 where
93 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
94 Self: Sized,
95 {
96 for (rel_id, other_id) in self.expand_ids(node_id, direction, types) {
97 visit(rel_id, other_id)?;
98 }
99 Ok(())
100 }
101
102 fn all_labels(&self) -> Vec<String>;
105 fn all_relationship_types(&self) -> Vec<String>;
106
107 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
114 where
115 F: FnOnce(&NodeRecord) -> R,
116 Self: Sized,
117 {
118 self.node(id).as_ref().map(f)
119 }
120
121 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
122 where
123 F: FnOnce(&RelationshipRecord) -> R,
124 Self: Sized,
125 {
126 self.relationship(id).as_ref().map(f)
127 }
128
129 fn has_node(&self, id: NodeId) -> bool {
132 self.contains_node(id)
133 }
134
135 fn has_relationship(&self, id: RelationshipId) -> bool {
136 self.contains_relationship(id)
137 }
138
139 fn node_count(&self) -> usize {
140 self.all_node_ids().len()
141 }
142
143 fn relationship_count(&self) -> usize {
144 self.all_rel_ids().len()
145 }
146
147 fn node_count_by_label(&self, label: &str) -> usize {
151 self.node_ids_by_label(label).len()
152 }
153
154 fn all_nodes(&self) -> Vec<NodeRecord> {
162 self.all_node_ids()
163 .into_iter()
164 .filter_map(|id| self.node(id))
165 .collect()
166 }
167
168 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
169 self.node_ids_by_label(label)
170 .into_iter()
171 .filter_map(|id| self.node(id))
172 .collect()
173 }
174
175 fn all_relationships(&self) -> Vec<RelationshipRecord> {
176 self.all_rel_ids()
177 .into_iter()
178 .filter_map(|id| self.relationship(id))
179 .collect()
180 }
181
182 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
183 self.rel_ids_by_type(rel_type)
184 .into_iter()
185 .filter_map(|id| self.relationship(id))
186 .collect()
187 }
188
189 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
192 self.expand_ids(node_id, direction, &[])
193 .into_iter()
194 .map(|(rel_id, _)| rel_id)
195 .collect()
196 }
197
198 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
199 self.relationship_ids_of(node_id, Direction::Right)
200 .into_iter()
201 .filter_map(|id| self.relationship(id))
202 .collect()
203 }
204
205 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
206 self.relationship_ids_of(node_id, Direction::Left)
207 .into_iter()
208 .filter_map(|id| self.relationship(id))
209 .collect()
210 }
211
212 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
213 self.relationship_ids_of(node_id, direction)
214 .into_iter()
215 .filter_map(|id| self.relationship(id))
216 .collect()
217 }
218
219 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
220 self.expand_ids(node_id, direction, &[]).len()
221 }
222
223 fn is_isolated(&self, node_id: NodeId) -> bool {
224 self.degree(node_id, Direction::Undirected) == 0
225 }
226
227 fn expand(
228 &self,
229 node_id: NodeId,
230 direction: Direction,
231 types: &[String],
232 ) -> Vec<(RelationshipRecord, NodeRecord)> {
233 self.expand_ids(node_id, direction, types)
234 .into_iter()
235 .filter_map(|(rid, nid)| {
236 let rel = self.relationship(rid)?;
237 let node = self.node(nid)?;
238 Some((rel, node))
239 })
240 .collect()
241 }
242
243 fn expand_detailed(
244 &self,
245 node_id: NodeId,
246 direction: Direction,
247 types: &[String],
248 ) -> Vec<ExpandedRelationship> {
249 self.expand(node_id, direction, types)
250 .into_iter()
251 .map(|(relationship, other_node)| ExpandedRelationship {
252 relationship,
253 other_node,
254 })
255 .collect()
256 }
257
258 fn neighbors(
259 &self,
260 node_id: NodeId,
261 direction: Direction,
262 types: &[String],
263 ) -> Vec<NodeRecord> {
264 self.expand_ids(node_id, direction, types)
265 .into_iter()
266 .filter_map(|(_, nid)| self.node(nid))
267 .collect()
268 }
269
270 fn node_has_label(&self, node_id: NodeId, label: &str) -> bool
273 where
274 Self: Sized,
275 {
276 self.with_node(node_id, |n| n.labels.iter().any(|l| l == label))
277 .unwrap_or(false)
278 }
279
280 fn node_labels(&self, node_id: NodeId) -> Option<Vec<String>>
281 where
282 Self: Sized,
283 {
284 self.with_node(node_id, |n| n.labels.clone())
285 }
286
287 fn node_properties(&self, node_id: NodeId) -> Option<Properties>
288 where
289 Self: Sized,
290 {
291 self.with_node(node_id, |n| n.properties.clone())
292 }
293
294 fn node_property(&self, node_id: NodeId, key: &str) -> Option<PropertyValue>
295 where
296 Self: Sized,
297 {
298 self.with_node(node_id, |n| n.properties.get(key).cloned())
299 .flatten()
300 }
301
302 fn relationship_type(&self, rel_id: RelationshipId) -> Option<String>
305 where
306 Self: Sized,
307 {
308 self.with_relationship(rel_id, |r| r.rel_type.clone())
309 }
310
311 fn relationship_properties(&self, rel_id: RelationshipId) -> Option<Properties>
312 where
313 Self: Sized,
314 {
315 self.with_relationship(rel_id, |r| r.properties.clone())
316 }
317
318 fn relationship_property(&self, rel_id: RelationshipId, key: &str) -> Option<PropertyValue>
319 where
320 Self: Sized,
321 {
322 self.with_relationship(rel_id, |r| r.properties.get(key).cloned())
323 .flatten()
324 }
325
326 fn relationship_source(&self, rel_id: RelationshipId) -> Option<NodeId> {
327 self.relationship_endpoints(rel_id).map(|(s, _)| s)
328 }
329
330 fn relationship_target(&self, rel_id: RelationshipId) -> Option<NodeId> {
331 self.relationship_endpoints(rel_id).map(|(_, d)| d)
332 }
333
334 fn other_node(&self, rel_id: RelationshipId, node_id: NodeId) -> Option<NodeId> {
335 let (src, dst) = self.relationship_endpoints(rel_id)?;
336 if src == node_id {
337 Some(dst)
338 } else if dst == node_id {
339 Some(src)
340 } else {
341 None
342 }
343 }
344
345 fn has_label_name(&self, label: &str) -> bool {
348 self.all_labels().iter().any(|l| l == label)
349 }
350
351 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
352 self.all_relationship_types().iter().any(|t| t == rel_type)
353 }
354
355 fn all_node_property_keys(&self) -> Vec<String>
356 where
357 Self: Sized,
358 {
359 let mut keys = BTreeSet::new();
360 for id in self.all_node_ids() {
361 self.with_node(id, |n| {
362 for key in n.properties.keys() {
363 keys.insert(key.to_string());
364 }
365 });
366 }
367 keys.into_iter().collect()
368 }
369
370 fn all_relationship_property_keys(&self) -> Vec<String>
371 where
372 Self: Sized,
373 {
374 let mut keys = BTreeSet::new();
375 for id in self.all_rel_ids() {
376 self.with_relationship(id, |r| {
377 for key in r.properties.keys() {
378 keys.insert(key.to_string());
379 }
380 });
381 }
382 keys.into_iter().collect()
383 }
384
385 fn all_property_keys(&self) -> Vec<String>
386 where
387 Self: Sized,
388 {
389 let mut keys = BTreeSet::new();
390 for key in self.all_node_property_keys() {
391 keys.insert(key);
392 }
393 for key in self.all_relationship_property_keys() {
394 keys.insert(key);
395 }
396 keys.into_iter().collect()
397 }
398
399 fn has_property_key(&self, key: &str) -> bool
400 where
401 Self: Sized,
402 {
403 self.all_node_property_keys().iter().any(|k| k == key)
404 || self
405 .all_relationship_property_keys()
406 .iter()
407 .any(|k| k == key)
408 }
409
410 fn label_property_keys(&self, label: &str) -> Vec<String>
411 where
412 Self: Sized,
413 {
414 let mut keys = BTreeSet::new();
415 for id in self.node_ids_by_label(label) {
416 self.with_node(id, |n| {
417 for key in n.properties.keys() {
418 keys.insert(key.to_string());
419 }
420 });
421 }
422 keys.into_iter().collect()
423 }
424
425 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String>
426 where
427 Self: Sized,
428 {
429 let mut keys = BTreeSet::new();
430 for id in self.rel_ids_by_type(rel_type) {
431 self.with_relationship(id, |r| {
432 for key in r.properties.keys() {
433 keys.insert(key.to_string());
434 }
435 });
436 }
437 keys.into_iter().collect()
438 }
439
440 fn label_has_property_key(&self, label: &str, key: &str) -> bool
441 where
442 Self: Sized,
443 {
444 self.node_ids_by_label(label).into_iter().any(|id| {
445 self.with_node(id, |n| n.properties.contains_key(key))
446 .unwrap_or(false)
447 })
448 }
449
450 fn rel_type_has_property_key(&self, rel_type: &str, key: &str) -> bool
451 where
452 Self: Sized,
453 {
454 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
455 self.with_relationship(id, |r| r.properties.contains_key(key))
456 .unwrap_or(false)
457 })
458 }
459
460 fn find_nodes_by_property(
463 &self,
464 label: Option<&str>,
465 key: &str,
466 value: &PropertyValue,
467 ) -> Vec<NodeRecord>
468 where
469 Self: Sized,
470 {
471 let ids = match label {
472 Some(label) => self.node_ids_by_label(label),
473 None => self.all_node_ids(),
474 };
475
476 ids.into_iter()
477 .filter_map(|id| {
478 let matches = self
479 .with_node(id, |n| n.properties.get(key) == Some(value))
480 .unwrap_or(false);
481 if matches {
482 self.node(id)
483 } else {
484 None
485 }
486 })
487 .collect()
488 }
489
490 fn find_node_ids_by_property(
491 &self,
492 label: Option<&str>,
493 key: &str,
494 value: &PropertyValue,
495 ) -> Vec<NodeId>
496 where
497 Self: Sized,
498 {
499 self.find_nodes_by_property(label, key, value)
500 .into_iter()
501 .map(|n| n.id)
502 .collect()
503 }
504
505 fn find_relationships_by_property(
506 &self,
507 rel_type: Option<&str>,
508 key: &str,
509 value: &PropertyValue,
510 ) -> Vec<RelationshipRecord>
511 where
512 Self: Sized,
513 {
514 let ids = match rel_type {
515 Some(rel_type) => self.rel_ids_by_type(rel_type),
516 None => self.all_rel_ids(),
517 };
518
519 ids.into_iter()
520 .filter_map(|id| {
521 let matches = self
522 .with_relationship(id, |r| r.properties.get(key) == Some(value))
523 .unwrap_or(false);
524 if matches {
525 self.relationship(id)
526 } else {
527 None
528 }
529 })
530 .collect()
531 }
532
533 fn find_relationship_ids_by_property(
534 &self,
535 rel_type: Option<&str>,
536 key: &str,
537 value: &PropertyValue,
538 ) -> Vec<RelationshipId>
539 where
540 Self: Sized,
541 {
542 self.find_relationships_by_property(rel_type, key, value)
543 .into_iter()
544 .map(|r| r.id)
545 .collect()
546 }
547
548 fn node_exists_with_label_and_property(
549 &self,
550 label: &str,
551 key: &str,
552 value: &PropertyValue,
553 ) -> bool
554 where
555 Self: Sized,
556 {
557 self.node_ids_by_label(label).into_iter().any(|id| {
558 self.with_node(id, |n| n.properties.get(key) == Some(value))
559 .unwrap_or(false)
560 })
561 }
562
563 fn relationship_exists_with_type_and_property(
564 &self,
565 rel_type: &str,
566 key: &str,
567 value: &PropertyValue,
568 ) -> bool
569 where
570 Self: Sized,
571 {
572 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
573 self.with_relationship(id, |r| r.properties.get(key) == Some(value))
574 .unwrap_or(false)
575 })
576 }
577
578 fn list_indexes(&self) -> Vec<IndexDefinition> {
585 Vec::new()
586 }
587
588 fn get_index(&self, _name: &str) -> Option<IndexDefinition> {
589 None
590 }
591
592 fn fulltext_search(&self, _name: &str, _query: &str) -> Vec<(u64, f64)> {
598 Vec::new()
599 }
600
601 fn vector_search(
617 &self,
618 _name: &str,
619 _query: &LoraVector,
620 _k: usize,
621 _restrict_to: Option<&std::collections::BTreeSet<u64>>,
622 ) -> Vec<(u64, f64)> {
623 Vec::new()
624 }
625
626 fn list_constraints(&self) -> Vec<ConstraintDefinition> {
629 Vec::new()
630 }
631
632 fn get_constraint(&self, _name: &str) -> Option<ConstraintDefinition> {
633 None
634 }
635
636 fn check_node_create_against_constraints(
642 &self,
643 _labels: &[String],
644 _properties: &Properties,
645 ) -> Result<(), String> {
646 Ok(())
647 }
648
649 fn check_relationship_create_against_constraints(
651 &self,
652 _rel_type: &str,
653 _properties: &Properties,
654 ) -> Result<(), String> {
655 Ok(())
656 }
657
658 fn check_node_create_deferring_existence(
663 &self,
664 labels: &[String],
665 properties: &Properties,
666 ) -> Result<(), String> {
667 self.check_node_create_against_constraints(labels, properties)
668 }
669
670 fn check_relationship_create_deferring_existence(
673 &self,
674 rel_type: &str,
675 properties: &Properties,
676 ) -> Result<(), String> {
677 self.check_relationship_create_against_constraints(rel_type, properties)
678 }
679
680 fn check_node_existence_constraints(&self, _node_id: NodeId) -> Result<(), String> {
683 Ok(())
684 }
685
686 fn check_relationship_existence_constraints(
688 &self,
689 _rel_id: RelationshipId,
690 ) -> Result<(), String> {
691 Ok(())
692 }
693
694 fn check_node_set_property_against_constraints(
697 &self,
698 _node_id: NodeId,
699 _key: &str,
700 _value: &PropertyValue,
701 ) -> Result<(), String> {
702 Ok(())
703 }
704
705 fn check_node_remove_property_against_constraints(
708 &self,
709 _node_id: NodeId,
710 _key: &str,
711 ) -> Result<(), String> {
712 Ok(())
713 }
714
715 fn check_node_replace_properties_against_constraints(
719 &self,
720 _node_id: NodeId,
721 _properties: &Properties,
722 ) -> Result<(), String> {
723 Ok(())
724 }
725
726 fn check_relationship_set_property_against_constraints(
729 &self,
730 _rel_id: RelationshipId,
731 _key: &str,
732 _value: &PropertyValue,
733 ) -> Result<(), String> {
734 Ok(())
735 }
736
737 fn check_relationship_remove_property_against_constraints(
738 &self,
739 _rel_id: RelationshipId,
740 _key: &str,
741 ) -> Result<(), String> {
742 Ok(())
743 }
744
745 fn check_relationship_replace_properties_against_constraints(
749 &self,
750 _rel_id: RelationshipId,
751 _properties: &Properties,
752 ) -> Result<(), String> {
753 Ok(())
754 }
755
756 fn check_node_add_label_against_constraints(
759 &self,
760 _node_id: NodeId,
761 _label: &str,
762 ) -> Result<(), String> {
763 Ok(())
764 }
765
766 fn check_node_replace_properties_deferring_existence(
771 &self,
772 node_id: NodeId,
773 properties: &Properties,
774 ) -> Result<(), String> {
775 self.check_node_replace_properties_against_constraints(node_id, properties)
776 }
777
778 fn check_relationship_replace_properties_deferring_existence(
781 &self,
782 rel_id: RelationshipId,
783 properties: &Properties,
784 ) -> Result<(), String> {
785 self.check_relationship_replace_properties_against_constraints(rel_id, properties)
786 }
787
788 fn check_node_add_label_deferring_existence(
794 &self,
795 node_id: NodeId,
796 label: &str,
797 ) -> Result<(), String> {
798 self.check_node_add_label_against_constraints(node_id, label)
799 }
800
801 fn graph_stats(&self) -> GraphStats {
805 GraphStats::default()
806 }
807
808 fn node_text_candidates(
817 &self,
818 _label: &str,
819 _property: &str,
820 _query: &str,
821 ) -> Option<Vec<NodeId>> {
822 None
823 }
824
825 fn node_range_candidates(
831 &self,
832 _label: &str,
833 _property: &str,
834 _lo: Option<&PropertyValue>,
835 _hi: Option<&PropertyValue>,
836 ) -> Option<Vec<NodeId>> {
837 None
838 }
839
840 fn node_range_other_temporal_kind_ids(
847 &self,
848 _label: &str,
849 _property: &str,
850 _like: &PropertyValue,
851 ) -> Option<Vec<NodeId>> {
852 None
853 }
854
855 #[allow(clippy::too_many_arguments)]
861 fn node_range_ordered_chunk(
862 &self,
863 _label: &str,
864 _property: &str,
865 _lo: Option<&PropertyValue>,
866 _hi: Option<&PropertyValue>,
867 _descending: bool,
868 _after: Option<(&PropertyValue, NodeId)>,
869 _max: usize,
870 ) -> Option<Vec<NodeId>> {
871 None
872 }
873
874 fn node_point_within_bbox(
879 &self,
880 _label: &str,
881 _property: &str,
882 _ll: (f64, f64),
883 _ur: (f64, f64),
884 ) -> Option<Vec<NodeId>> {
885 None
886 }
887
888 fn node_point_within_distance(
892 &self,
893 _label: &str,
894 _property: &str,
895 _center: (f64, f64),
896 _max_distance: f64,
897 ) -> Option<Vec<NodeId>> {
898 None
899 }
900
901 fn relationship_text_candidates(
905 &self,
906 _rel_type: &str,
907 _property: &str,
908 _query: &str,
909 ) -> Option<Vec<RelationshipId>> {
910 None
911 }
912
913 fn relationship_range_candidates(
916 &self,
917 _rel_type: &str,
918 _property: &str,
919 _lo: Option<&PropertyValue>,
920 _hi: Option<&PropertyValue>,
921 ) -> Option<Vec<RelationshipId>> {
922 None
923 }
924
925 fn relationship_range_other_temporal_kind_ids(
928 &self,
929 _rel_type: &str,
930 _property: &str,
931 _like: &PropertyValue,
932 ) -> Option<Vec<RelationshipId>> {
933 None
934 }
935
936 fn relationship_point_within_bbox(
940 &self,
941 _rel_type: &str,
942 _property: &str,
943 _ll: (f64, f64),
944 _ur: (f64, f64),
945 ) -> Option<Vec<RelationshipId>> {
946 None
947 }
948
949 fn relationship_point_within_distance(
953 &self,
954 _rel_type: &str,
955 _property: &str,
956 _center: (f64, f64),
957 _max_distance: f64,
958 ) -> Option<Vec<RelationshipId>> {
959 None
960 }
961}
962
963pub trait GraphCatalog {
971 fn node_count(&self) -> usize;
972 fn relationship_count(&self) -> usize;
973 fn has_label_name(&self, label: &str) -> bool;
974 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
975 fn has_property_key(&self, key: &str) -> bool;
976}
977
978impl<T: GraphStorage> GraphCatalog for T {
979 fn node_count(&self) -> usize {
980 GraphStorage::node_count(self)
981 }
982 fn relationship_count(&self) -> usize {
983 GraphStorage::relationship_count(self)
984 }
985 fn has_label_name(&self, label: &str) -> bool {
986 GraphStorage::has_label_name(self, label)
987 }
988 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
989 GraphStorage::has_relationship_type_name(self, rel_type)
990 }
991 fn has_property_key(&self, key: &str) -> bool {
992 GraphStorage::has_property_key(self, key)
993 }
994}
995
996pub trait BorrowedGraphStorage: GraphStorage {
1007 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
1008 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
1009
1010 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
1011 Box::new(
1012 self.all_node_ids()
1013 .into_iter()
1014 .filter_map(|id| self.node_ref(id)),
1015 )
1016 }
1017
1018 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
1019 Box::new(
1020 self.node_ids_by_label(label)
1021 .into_iter()
1022 .filter_map(|id| self.node_ref(id)),
1023 )
1024 }
1025
1026 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
1027 Box::new(
1028 self.all_rel_ids()
1029 .into_iter()
1030 .filter_map(|id| self.relationship_ref(id)),
1031 )
1032 }
1033
1034 fn relationship_refs_by_type(
1035 &self,
1036 rel_type: &str,
1037 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
1038 Box::new(
1039 self.rel_ids_by_type(rel_type)
1040 .into_iter()
1041 .filter_map(|id| self.relationship_ref(id)),
1042 )
1043 }
1044}
1045
1046pub trait GraphStorageMut: GraphStorage {
1056 fn try_create_node(
1059 &mut self,
1060 labels: Vec<String>,
1061 properties: Properties,
1062 ) -> Option<NodeRecord>;
1063
1064 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord
1069 where
1070 Self: Sized,
1071 {
1072 self.try_create_node(labels, properties)
1073 .unwrap_or_else(|| NodeRecord {
1074 id: NodeId::MAX,
1075 labels: Vec::new(),
1076 properties: Properties::new(),
1077 })
1078 }
1079
1080 fn create_relationship(
1081 &mut self,
1082 src: NodeId,
1083 dst: NodeId,
1084 rel_type: &str,
1085 properties: Properties,
1086 ) -> Option<RelationshipRecord>;
1087
1088 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
1091
1092 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
1093
1094 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1095 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1096
1097 fn set_relationship_property(
1100 &mut self,
1101 rel_id: RelationshipId,
1102 key: String,
1103 value: PropertyValue,
1104 ) -> bool;
1105
1106 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
1107
1108 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
1111
1112 fn delete_node(&mut self, node_id: NodeId) -> bool;
1114
1115 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
1117
1118 fn clear(&mut self);
1127
1128 #[allow(clippy::result_large_err)]
1135 fn create_index(
1136 &mut self,
1137 _request: IndexRequest,
1138 _if_not_exists: bool,
1139 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1140 Err(CreateIndexError::Unsupported(
1141 "this backend does not maintain an index catalog",
1142 ))
1143 }
1144
1145 fn drop_index(
1150 &mut self,
1151 _name: &str,
1152 _if_exists: bool,
1153 ) -> Result<DropIndexOutcome, DropIndexError> {
1154 Err(DropIndexError::Unsupported(
1155 "this backend does not maintain an index catalog",
1156 ))
1157 }
1158
1159 fn create_constraint(
1164 &mut self,
1165 _request: ConstraintRequest,
1166 _if_not_exists: bool,
1167 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1168 Err(CreateConstraintError::Unsupported(
1169 "this backend does not maintain a constraint catalog",
1170 ))
1171 }
1172
1173 fn drop_constraint(
1176 &mut self,
1177 _name: &str,
1178 _if_exists: bool,
1179 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1180 Err(DropConstraintError::Unsupported(
1181 "this backend does not maintain a constraint catalog",
1182 ))
1183 }
1184
1185 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1188 where
1189 Self: Sized,
1190 {
1191 if !self.contains_node(node_id) {
1192 return false;
1193 }
1194
1195 let existing_keys = match self.node_properties(node_id) {
1196 Some(props) => props.into_keys().collect::<Vec<_>>(),
1197 None => return false,
1198 };
1199
1200 for key in existing_keys {
1201 self.remove_node_property(node_id, &key);
1202 }
1203
1204 for (k, v) in properties {
1205 self.set_node_property(node_id, k.to_string(), v);
1206 }
1207
1208 true
1209 }
1210
1211 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1212 if !self.contains_node(node_id) {
1213 return false;
1214 }
1215
1216 for (k, v) in properties {
1217 self.set_node_property(node_id, k.to_string(), v);
1218 }
1219
1220 true
1221 }
1222
1223 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1224 where
1225 Self: Sized,
1226 {
1227 if !self.contains_node(node_id) {
1228 return false;
1229 }
1230
1231 let current = match self.node_labels(node_id) {
1232 Some(labels) => labels,
1233 None => return false,
1234 };
1235
1236 for label in ¤t {
1237 self.remove_node_label(node_id, label);
1238 }
1239
1240 for label in &labels {
1241 self.add_node_label(node_id, label);
1242 }
1243
1244 true
1245 }
1246
1247 fn replace_relationship_properties(
1248 &mut self,
1249 rel_id: RelationshipId,
1250 properties: Properties,
1251 ) -> bool
1252 where
1253 Self: Sized,
1254 {
1255 if !self.contains_relationship(rel_id) {
1256 return false;
1257 }
1258
1259 let existing_keys = match self.relationship_properties(rel_id) {
1260 Some(props) => props.into_keys().collect::<Vec<_>>(),
1261 None => return false,
1262 };
1263
1264 for key in existing_keys {
1265 self.remove_relationship_property(rel_id, &key);
1266 }
1267
1268 for (k, v) in properties {
1269 self.set_relationship_property(rel_id, k.to_string(), v);
1270 }
1271
1272 true
1273 }
1274
1275 fn merge_relationship_properties(
1276 &mut self,
1277 rel_id: RelationshipId,
1278 properties: Properties,
1279 ) -> bool {
1280 if !self.contains_relationship(rel_id) {
1281 return false;
1282 }
1283
1284 for (k, v) in properties {
1285 self.set_relationship_property(rel_id, k.to_string(), v);
1286 }
1287
1288 true
1289 }
1290
1291 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1292 let rel_ids = self.relationship_ids_of(node_id, direction);
1293
1294 let mut deleted = 0;
1295 for rel_id in rel_ids {
1296 if self.delete_relationship(rel_id) {
1297 deleted += 1;
1298 }
1299 }
1300 deleted
1301 }
1302
1303 fn get_or_create_node(
1304 &mut self,
1305 labels: Vec<String>,
1306 match_key: &str,
1307 match_value: &PropertyValue,
1308 init_properties: Properties,
1309 ) -> NodeRecord
1310 where
1311 Self: Sized,
1312 {
1313 for label in &labels {
1314 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1315 if let Some(node) = matches.into_iter().next() {
1316 return node;
1317 }
1318 }
1319
1320 self.create_node(labels, init_properties)
1321 }
1322}