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, NodeRef, Properties, PropertyValue,
19 RelRef, 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 scan_node_ids(
67 &self,
68 label: Option<&str>,
69 cursor: &mut u64,
70 max: usize,
71 out: &mut Vec<NodeId>,
72 ) -> bool {
73 let _ = max;
74 if *cursor == 0 {
75 *cursor = u64::MAX;
76 out.extend(match label {
77 Some(label) => self.node_ids_by_label(label),
78 None => self.all_node_ids(),
79 });
80 }
81 false
82 }
83
84 fn contains_relationship(&self, id: RelationshipId) -> bool;
87
88 fn relationship(&self, id: RelationshipId) -> Option<RelationshipRecord>;
89
90 fn all_rel_ids(&self) -> Vec<RelationshipId>;
91
92 fn rel_ids_by_type(&self, rel_type: &str) -> Vec<RelationshipId>;
93
94 fn relationship_endpoints(&self, id: RelationshipId) -> Option<(NodeId, NodeId)>;
98
99 fn expand_ids(
105 &self,
106 node_id: NodeId,
107 direction: Direction,
108 types: &[String],
109 ) -> Vec<(RelationshipId, NodeId)>;
110
111 fn try_for_each_expand_id<F, E>(
115 &self,
116 node_id: NodeId,
117 direction: Direction,
118 types: &[String],
119 mut visit: F,
120 ) -> Result<(), E>
121 where
122 F: FnMut(RelationshipId, NodeId) -> Result<(), E>,
123 Self: Sized,
124 {
125 for (rel_id, other_id) in self.expand_ids(node_id, direction, types) {
126 visit(rel_id, other_id)?;
127 }
128 Ok(())
129 }
130
131 fn all_labels(&self) -> Vec<String>;
134 fn all_relationship_types(&self) -> Vec<String>;
135
136 fn with_node<F, R>(&self, id: NodeId, f: F) -> Option<R>
144 where
145 F: FnOnce(NodeRef<'_>) -> R,
146 Self: Sized,
147 {
148 self.node(id).as_ref().map(|node| f(NodeRef::from(node)))
149 }
150
151 fn with_relationship<F, R>(&self, id: RelationshipId, f: F) -> Option<R>
152 where
153 F: FnOnce(RelRef<'_>) -> R,
154 Self: Sized,
155 {
156 self.relationship(id)
157 .as_ref()
158 .map(|rel| f(RelRef::from(rel)))
159 }
160
161 fn has_node(&self, id: NodeId) -> bool {
164 self.contains_node(id)
165 }
166
167 fn has_relationship(&self, id: RelationshipId) -> bool {
168 self.contains_relationship(id)
169 }
170
171 fn node_count(&self) -> usize {
172 self.all_node_ids().len()
173 }
174
175 fn relationship_count(&self) -> usize {
176 self.all_rel_ids().len()
177 }
178
179 fn node_count_by_label(&self, label: &str) -> usize {
183 self.node_ids_by_label(label).len()
184 }
185
186 fn all_nodes(&self) -> Vec<NodeRecord> {
194 self.all_node_ids()
195 .into_iter()
196 .filter_map(|id| self.node(id))
197 .collect()
198 }
199
200 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
201 self.node_ids_by_label(label)
202 .into_iter()
203 .filter_map(|id| self.node(id))
204 .collect()
205 }
206
207 fn all_relationships(&self) -> Vec<RelationshipRecord> {
208 self.all_rel_ids()
209 .into_iter()
210 .filter_map(|id| self.relationship(id))
211 .collect()
212 }
213
214 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
215 self.rel_ids_by_type(rel_type)
216 .into_iter()
217 .filter_map(|id| self.relationship(id))
218 .collect()
219 }
220
221 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
224 self.expand_ids(node_id, direction, &[])
225 .into_iter()
226 .map(|(rel_id, _)| rel_id)
227 .collect()
228 }
229
230 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
231 self.relationship_ids_of(node_id, Direction::Right)
232 .into_iter()
233 .filter_map(|id| self.relationship(id))
234 .collect()
235 }
236
237 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
238 self.relationship_ids_of(node_id, Direction::Left)
239 .into_iter()
240 .filter_map(|id| self.relationship(id))
241 .collect()
242 }
243
244 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
245 self.relationship_ids_of(node_id, direction)
246 .into_iter()
247 .filter_map(|id| self.relationship(id))
248 .collect()
249 }
250
251 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
252 self.expand_ids(node_id, direction, &[]).len()
253 }
254
255 fn is_isolated(&self, node_id: NodeId) -> bool {
256 self.degree(node_id, Direction::Undirected) == 0
257 }
258
259 fn expand(
260 &self,
261 node_id: NodeId,
262 direction: Direction,
263 types: &[String],
264 ) -> Vec<(RelationshipRecord, NodeRecord)> {
265 self.expand_ids(node_id, direction, types)
266 .into_iter()
267 .filter_map(|(rid, nid)| {
268 let rel = self.relationship(rid)?;
269 let node = self.node(nid)?;
270 Some((rel, node))
271 })
272 .collect()
273 }
274
275 fn expand_detailed(
276 &self,
277 node_id: NodeId,
278 direction: Direction,
279 types: &[String],
280 ) -> Vec<ExpandedRelationship> {
281 self.expand(node_id, direction, types)
282 .into_iter()
283 .map(|(relationship, other_node)| ExpandedRelationship {
284 relationship,
285 other_node,
286 })
287 .collect()
288 }
289
290 fn neighbors(
291 &self,
292 node_id: NodeId,
293 direction: Direction,
294 types: &[String],
295 ) -> Vec<NodeRecord> {
296 self.expand_ids(node_id, direction, types)
297 .into_iter()
298 .filter_map(|(_, nid)| self.node(nid))
299 .collect()
300 }
301
302 fn node_has_label(&self, node_id: NodeId, label: &str) -> bool
305 where
306 Self: Sized,
307 {
308 self.with_node(node_id, |n| n.has_label(label))
309 .unwrap_or(false)
310 }
311
312 fn node_labels(&self, node_id: NodeId) -> Option<Vec<String>>
313 where
314 Self: Sized,
315 {
316 self.with_node(node_id, |n| n.labels().to_strings())
317 }
318
319 fn node_properties(&self, node_id: NodeId) -> Option<Properties>
320 where
321 Self: Sized,
322 {
323 self.with_node(node_id, |n| n.properties().to_owned())
324 }
325
326 fn node_property(&self, node_id: NodeId, key: &str) -> Option<PropertyValue>
327 where
328 Self: Sized,
329 {
330 self.with_node(node_id, |n| n.properties().get(key).map(|v| v.to_owned()))
331 .flatten()
332 }
333
334 fn relationship_type(&self, rel_id: RelationshipId) -> Option<String>
337 where
338 Self: Sized,
339 {
340 self.with_relationship(rel_id, |r| r.rel_type().to_string())
341 }
342
343 fn relationship_properties(&self, rel_id: RelationshipId) -> Option<Properties>
344 where
345 Self: Sized,
346 {
347 self.with_relationship(rel_id, |r| r.properties().to_owned())
348 }
349
350 fn relationship_property(&self, rel_id: RelationshipId, key: &str) -> Option<PropertyValue>
351 where
352 Self: Sized,
353 {
354 self.with_relationship(rel_id, |r| r.properties().get(key).map(|v| v.to_owned()))
355 .flatten()
356 }
357
358 fn relationship_source(&self, rel_id: RelationshipId) -> Option<NodeId> {
359 self.relationship_endpoints(rel_id).map(|(s, _)| s)
360 }
361
362 fn relationship_target(&self, rel_id: RelationshipId) -> Option<NodeId> {
363 self.relationship_endpoints(rel_id).map(|(_, d)| d)
364 }
365
366 fn other_node(&self, rel_id: RelationshipId, node_id: NodeId) -> Option<NodeId> {
367 let (src, dst) = self.relationship_endpoints(rel_id)?;
368 if src == node_id {
369 Some(dst)
370 } else if dst == node_id {
371 Some(src)
372 } else {
373 None
374 }
375 }
376
377 fn has_label_name(&self, label: &str) -> bool {
380 self.all_labels().iter().any(|l| l == label)
381 }
382
383 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
384 self.all_relationship_types().iter().any(|t| t == rel_type)
385 }
386
387 fn all_node_property_keys(&self) -> Vec<String>
388 where
389 Self: Sized,
390 {
391 let mut keys = BTreeSet::new();
392 for id in self.all_node_ids() {
393 self.with_node(id, |n| {
394 for key in n.properties().keys() {
395 keys.insert(key.to_string());
396 }
397 });
398 }
399 keys.into_iter().collect()
400 }
401
402 fn all_relationship_property_keys(&self) -> Vec<String>
403 where
404 Self: Sized,
405 {
406 let mut keys = BTreeSet::new();
407 for id in self.all_rel_ids() {
408 self.with_relationship(id, |r| {
409 for key in r.properties().keys() {
410 keys.insert(key.to_string());
411 }
412 });
413 }
414 keys.into_iter().collect()
415 }
416
417 fn all_property_keys(&self) -> Vec<String>
418 where
419 Self: Sized,
420 {
421 let mut keys = BTreeSet::new();
422 for key in self.all_node_property_keys() {
423 keys.insert(key);
424 }
425 for key in self.all_relationship_property_keys() {
426 keys.insert(key);
427 }
428 keys.into_iter().collect()
429 }
430
431 fn has_property_key(&self, key: &str) -> bool
432 where
433 Self: Sized,
434 {
435 self.all_node_property_keys().iter().any(|k| k == key)
436 || self
437 .all_relationship_property_keys()
438 .iter()
439 .any(|k| k == key)
440 }
441
442 fn label_property_keys(&self, label: &str) -> Vec<String>
443 where
444 Self: Sized,
445 {
446 let mut keys = BTreeSet::new();
447 for id in self.node_ids_by_label(label) {
448 self.with_node(id, |n| {
449 for key in n.properties().keys() {
450 keys.insert(key.to_string());
451 }
452 });
453 }
454 keys.into_iter().collect()
455 }
456
457 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String>
458 where
459 Self: Sized,
460 {
461 let mut keys = BTreeSet::new();
462 for id in self.rel_ids_by_type(rel_type) {
463 self.with_relationship(id, |r| {
464 for key in r.properties().keys() {
465 keys.insert(key.to_string());
466 }
467 });
468 }
469 keys.into_iter().collect()
470 }
471
472 fn label_has_property_key(&self, label: &str, key: &str) -> bool
473 where
474 Self: Sized,
475 {
476 self.node_ids_by_label(label).into_iter().any(|id| {
477 self.with_node(id, |n| n.properties().contains_key(key))
478 .unwrap_or(false)
479 })
480 }
481
482 fn rel_type_has_property_key(&self, rel_type: &str, key: &str) -> bool
483 where
484 Self: Sized,
485 {
486 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
487 self.with_relationship(id, |r| r.properties().contains_key(key))
488 .unwrap_or(false)
489 })
490 }
491
492 fn find_nodes_by_property(
495 &self,
496 label: Option<&str>,
497 key: &str,
498 value: &PropertyValue,
499 ) -> Vec<NodeRecord>
500 where
501 Self: Sized,
502 {
503 let ids = match label {
504 Some(label) => self.node_ids_by_label(label),
505 None => self.all_node_ids(),
506 };
507
508 ids.into_iter()
509 .filter_map(|id| {
510 let matches = self
511 .with_node(id, |n| n.properties().get(key).is_some_and(|v| v == *value))
512 .unwrap_or(false);
513 if matches {
514 self.node(id)
515 } else {
516 None
517 }
518 })
519 .collect()
520 }
521
522 fn find_node_ids_by_property(
523 &self,
524 label: Option<&str>,
525 key: &str,
526 value: &PropertyValue,
527 ) -> Vec<NodeId>
528 where
529 Self: Sized,
530 {
531 self.find_nodes_by_property(label, key, value)
532 .into_iter()
533 .map(|n| n.id)
534 .collect()
535 }
536
537 fn find_relationships_by_property(
538 &self,
539 rel_type: Option<&str>,
540 key: &str,
541 value: &PropertyValue,
542 ) -> Vec<RelationshipRecord>
543 where
544 Self: Sized,
545 {
546 let ids = match rel_type {
547 Some(rel_type) => self.rel_ids_by_type(rel_type),
548 None => self.all_rel_ids(),
549 };
550
551 ids.into_iter()
552 .filter_map(|id| {
553 let matches = self
554 .with_relationship(id, |r| r.properties().get(key).is_some_and(|v| v == *value))
555 .unwrap_or(false);
556 if matches {
557 self.relationship(id)
558 } else {
559 None
560 }
561 })
562 .collect()
563 }
564
565 fn find_relationship_ids_by_property(
566 &self,
567 rel_type: Option<&str>,
568 key: &str,
569 value: &PropertyValue,
570 ) -> Vec<RelationshipId>
571 where
572 Self: Sized,
573 {
574 self.find_relationships_by_property(rel_type, key, value)
575 .into_iter()
576 .map(|r| r.id)
577 .collect()
578 }
579
580 fn node_exists_with_label_and_property(
581 &self,
582 label: &str,
583 key: &str,
584 value: &PropertyValue,
585 ) -> bool
586 where
587 Self: Sized,
588 {
589 self.node_ids_by_label(label).into_iter().any(|id| {
590 self.with_node(id, |n| n.properties().get(key).is_some_and(|v| v == *value))
591 .unwrap_or(false)
592 })
593 }
594
595 fn relationship_exists_with_type_and_property(
596 &self,
597 rel_type: &str,
598 key: &str,
599 value: &PropertyValue,
600 ) -> bool
601 where
602 Self: Sized,
603 {
604 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
605 self.with_relationship(id, |r| r.properties().get(key).is_some_and(|v| v == *value))
606 .unwrap_or(false)
607 })
608 }
609
610 fn list_indexes(&self) -> Vec<IndexDefinition> {
617 Vec::new()
618 }
619
620 fn get_index(&self, _name: &str) -> Option<IndexDefinition> {
621 None
622 }
623
624 fn fulltext_search(&self, _name: &str, _query: &str, _limit: Option<usize>) -> Vec<(u64, f64)> {
631 Vec::new()
632 }
633
634 fn vector_search(
650 &self,
651 _name: &str,
652 _query: &LoraVector,
653 _k: usize,
654 _restrict_to: Option<&std::collections::BTreeSet<u64>>,
655 ) -> Vec<(u64, f64)> {
656 Vec::new()
657 }
658
659 fn combines_property_writes(&self) -> bool {
666 false
667 }
668
669 fn list_constraints(&self) -> Vec<ConstraintDefinition> {
670 Vec::new()
671 }
672
673 fn get_constraint(&self, _name: &str) -> Option<ConstraintDefinition> {
674 None
675 }
676
677 fn check_node_create_against_constraints(
683 &self,
684 _labels: &[String],
685 _properties: &Properties,
686 ) -> Result<(), String> {
687 Ok(())
688 }
689
690 fn check_relationship_create_against_constraints(
692 &self,
693 _rel_type: &str,
694 _properties: &Properties,
695 ) -> Result<(), String> {
696 Ok(())
697 }
698
699 fn check_node_create_deferring_existence(
704 &self,
705 labels: &[String],
706 properties: &Properties,
707 ) -> Result<(), String> {
708 self.check_node_create_against_constraints(labels, properties)
709 }
710
711 fn check_relationship_create_deferring_existence(
714 &self,
715 rel_type: &str,
716 properties: &Properties,
717 ) -> Result<(), String> {
718 self.check_relationship_create_against_constraints(rel_type, properties)
719 }
720
721 fn check_node_existence_constraints(&self, _node_id: NodeId) -> Result<(), String> {
724 Ok(())
725 }
726
727 fn check_relationship_existence_constraints(
729 &self,
730 _rel_id: RelationshipId,
731 ) -> Result<(), String> {
732 Ok(())
733 }
734
735 fn check_node_set_property_against_constraints(
738 &self,
739 _node_id: NodeId,
740 _key: &str,
741 _value: &PropertyValue,
742 ) -> Result<(), String> {
743 Ok(())
744 }
745
746 fn check_node_remove_property_against_constraints(
749 &self,
750 _node_id: NodeId,
751 _key: &str,
752 ) -> Result<(), String> {
753 Ok(())
754 }
755
756 fn check_node_replace_properties_against_constraints(
760 &self,
761 _node_id: NodeId,
762 _properties: &Properties,
763 ) -> Result<(), String> {
764 Ok(())
765 }
766
767 fn check_relationship_set_property_against_constraints(
770 &self,
771 _rel_id: RelationshipId,
772 _key: &str,
773 _value: &PropertyValue,
774 ) -> Result<(), String> {
775 Ok(())
776 }
777
778 fn check_relationship_remove_property_against_constraints(
779 &self,
780 _rel_id: RelationshipId,
781 _key: &str,
782 ) -> Result<(), String> {
783 Ok(())
784 }
785
786 fn check_relationship_replace_properties_against_constraints(
790 &self,
791 _rel_id: RelationshipId,
792 _properties: &Properties,
793 ) -> Result<(), String> {
794 Ok(())
795 }
796
797 fn check_node_add_label_against_constraints(
800 &self,
801 _node_id: NodeId,
802 _label: &str,
803 ) -> Result<(), String> {
804 Ok(())
805 }
806
807 fn check_node_replace_properties_deferring_existence(
812 &self,
813 node_id: NodeId,
814 properties: &Properties,
815 ) -> Result<(), String> {
816 self.check_node_replace_properties_against_constraints(node_id, properties)
817 }
818
819 fn check_relationship_replace_properties_deferring_existence(
822 &self,
823 rel_id: RelationshipId,
824 properties: &Properties,
825 ) -> Result<(), String> {
826 self.check_relationship_replace_properties_against_constraints(rel_id, properties)
827 }
828
829 fn check_node_add_label_deferring_existence(
835 &self,
836 node_id: NodeId,
837 label: &str,
838 ) -> Result<(), String> {
839 self.check_node_add_label_against_constraints(node_id, label)
840 }
841
842 fn graph_stats(&self) -> GraphStats {
846 GraphStats::default()
847 }
848
849 fn plan_signature(&self) -> u64 {
856 self.graph_stats().plan_signature()
857 }
858
859 fn node_text_candidates(
868 &self,
869 _label: &str,
870 _property: &str,
871 _query: &str,
872 ) -> Option<Vec<NodeId>> {
873 None
874 }
875
876 fn node_range_candidates(
882 &self,
883 _label: &str,
884 _property: &str,
885 _lo: Option<&PropertyValue>,
886 _hi: Option<&PropertyValue>,
887 ) -> Option<Vec<NodeId>> {
888 None
889 }
890
891 fn node_range_other_temporal_kind_ids(
898 &self,
899 _label: &str,
900 _property: &str,
901 _like: &PropertyValue,
902 ) -> Option<Vec<NodeId>> {
903 None
904 }
905
906 #[allow(clippy::too_many_arguments)]
912 fn node_range_ordered_chunk(
913 &self,
914 _label: &str,
915 _property: &str,
916 _lo: Option<&PropertyValue>,
917 _hi: Option<&PropertyValue>,
918 _descending: bool,
919 _after: Option<(&PropertyValue, NodeId)>,
920 _max: usize,
921 ) -> Option<Vec<NodeId>> {
922 None
923 }
924
925 fn node_list_element_candidates(
934 &self,
935 _label: &str,
936 _property: &str,
937 _element: &PropertyValue,
938 ) -> Option<Vec<NodeId>> {
939 None
940 }
941
942 fn relationship_list_element_candidates(
945 &self,
946 _rel_type: &str,
947 _property: &str,
948 _element: &PropertyValue,
949 ) -> Option<Vec<RelationshipId>> {
950 None
951 }
952
953 fn node_point_within_bbox(
958 &self,
959 _label: &str,
960 _property: &str,
961 _ll: (f64, f64),
962 _ur: (f64, f64),
963 ) -> Option<Vec<NodeId>> {
964 None
965 }
966
967 fn node_point_within_distance(
971 &self,
972 _label: &str,
973 _property: &str,
974 _center: (f64, f64),
975 _max_distance: f64,
976 ) -> Option<Vec<NodeId>> {
977 None
978 }
979
980 fn relationship_text_candidates(
984 &self,
985 _rel_type: &str,
986 _property: &str,
987 _query: &str,
988 ) -> Option<Vec<RelationshipId>> {
989 None
990 }
991
992 fn relationship_range_candidates(
995 &self,
996 _rel_type: &str,
997 _property: &str,
998 _lo: Option<&PropertyValue>,
999 _hi: Option<&PropertyValue>,
1000 ) -> Option<Vec<RelationshipId>> {
1001 None
1002 }
1003
1004 fn relationship_range_other_temporal_kind_ids(
1007 &self,
1008 _rel_type: &str,
1009 _property: &str,
1010 _like: &PropertyValue,
1011 ) -> Option<Vec<RelationshipId>> {
1012 None
1013 }
1014
1015 fn relationship_point_within_bbox(
1019 &self,
1020 _rel_type: &str,
1021 _property: &str,
1022 _ll: (f64, f64),
1023 _ur: (f64, f64),
1024 ) -> Option<Vec<RelationshipId>> {
1025 None
1026 }
1027
1028 fn relationship_point_within_distance(
1032 &self,
1033 _rel_type: &str,
1034 _property: &str,
1035 _center: (f64, f64),
1036 _max_distance: f64,
1037 ) -> Option<Vec<RelationshipId>> {
1038 None
1039 }
1040}
1041
1042pub trait GraphCatalog {
1050 fn node_count(&self) -> usize;
1051 fn relationship_count(&self) -> usize;
1052 fn has_label_name(&self, label: &str) -> bool;
1053 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
1054 fn has_property_key(&self, key: &str) -> bool;
1055}
1056
1057impl<T: GraphStorage> GraphCatalog for T {
1058 fn node_count(&self) -> usize {
1059 GraphStorage::node_count(self)
1060 }
1061 fn relationship_count(&self) -> usize {
1062 GraphStorage::relationship_count(self)
1063 }
1064 fn has_label_name(&self, label: &str) -> bool {
1065 GraphStorage::has_label_name(self, label)
1066 }
1067 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
1068 GraphStorage::has_relationship_type_name(self, rel_type)
1069 }
1070 fn has_property_key(&self, key: &str) -> bool {
1071 GraphStorage::has_property_key(self, key)
1072 }
1073}
1074
1075pub trait GraphStorageMut: GraphStorage {
1085 fn try_create_node(
1088 &mut self,
1089 labels: Vec<String>,
1090 properties: Properties,
1091 ) -> Option<NodeRecord>;
1092
1093 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord
1098 where
1099 Self: Sized,
1100 {
1101 self.try_create_node(labels, properties)
1102 .unwrap_or_else(|| NodeRecord {
1103 id: NodeId::MAX,
1104 labels: Default::default(),
1105 properties: Properties::new(),
1106 })
1107 }
1108
1109 fn create_relationship(
1110 &mut self,
1111 src: NodeId,
1112 dst: NodeId,
1113 rel_type: &str,
1114 properties: Properties,
1115 ) -> Option<RelationshipRecord>;
1116
1117 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
1120
1121 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
1122
1123 fn update_node_properties(
1128 &mut self,
1129 node_id: NodeId,
1130 edits: Vec<(String, Option<PropertyValue>)>,
1131 ) -> bool {
1132 if !self.contains_node(node_id) {
1133 return false;
1134 }
1135 for (key, value) in edits {
1136 match value {
1137 Some(value) => {
1138 self.set_node_property(node_id, key, value);
1139 }
1140 None => {
1141 self.remove_node_property(node_id, &key);
1142 }
1143 }
1144 }
1145 true
1146 }
1147
1148 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1149 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1150
1151 fn set_relationship_property(
1154 &mut self,
1155 rel_id: RelationshipId,
1156 key: String,
1157 value: PropertyValue,
1158 ) -> bool;
1159
1160 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
1161
1162 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
1165
1166 fn delete_node(&mut self, node_id: NodeId) -> bool;
1168
1169 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
1171
1172 fn clear(&mut self);
1181
1182 #[allow(clippy::result_large_err)]
1189 fn create_index(
1190 &mut self,
1191 _request: IndexRequest,
1192 _if_not_exists: bool,
1193 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1194 Err(CreateIndexError::Unsupported(
1195 "this backend does not maintain an index catalog",
1196 ))
1197 }
1198
1199 fn drop_index(
1204 &mut self,
1205 _name: &str,
1206 _if_exists: bool,
1207 ) -> Result<DropIndexOutcome, DropIndexError> {
1208 Err(DropIndexError::Unsupported(
1209 "this backend does not maintain an index catalog",
1210 ))
1211 }
1212
1213 fn create_constraint(
1218 &mut self,
1219 _request: ConstraintRequest,
1220 _if_not_exists: bool,
1221 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1222 Err(CreateConstraintError::Unsupported(
1223 "this backend does not maintain a constraint catalog",
1224 ))
1225 }
1226
1227 fn drop_constraint(
1230 &mut self,
1231 _name: &str,
1232 _if_exists: bool,
1233 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1234 Err(DropConstraintError::Unsupported(
1235 "this backend does not maintain a constraint catalog",
1236 ))
1237 }
1238
1239 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1242 where
1243 Self: Sized,
1244 {
1245 if !self.contains_node(node_id) {
1246 return false;
1247 }
1248
1249 let existing_keys = match self.node_properties(node_id) {
1250 Some(props) => props.into_keys().collect::<Vec<_>>(),
1251 None => return false,
1252 };
1253
1254 for key in existing_keys {
1255 self.remove_node_property(node_id, &key);
1256 }
1257
1258 for (k, v) in properties {
1259 self.set_node_property(node_id, k.to_string(), v);
1260 }
1261
1262 true
1263 }
1264
1265 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1266 if !self.contains_node(node_id) {
1267 return false;
1268 }
1269
1270 for (k, v) in properties {
1271 self.set_node_property(node_id, k.to_string(), v);
1272 }
1273
1274 true
1275 }
1276
1277 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1278 where
1279 Self: Sized,
1280 {
1281 if !self.contains_node(node_id) {
1282 return false;
1283 }
1284
1285 let current = match self.node_labels(node_id) {
1286 Some(labels) => labels,
1287 None => return false,
1288 };
1289
1290 for label in ¤t {
1291 self.remove_node_label(node_id, label);
1292 }
1293
1294 for label in &labels {
1295 self.add_node_label(node_id, label);
1296 }
1297
1298 true
1299 }
1300
1301 fn replace_relationship_properties(
1302 &mut self,
1303 rel_id: RelationshipId,
1304 properties: Properties,
1305 ) -> bool
1306 where
1307 Self: Sized,
1308 {
1309 if !self.contains_relationship(rel_id) {
1310 return false;
1311 }
1312
1313 let existing_keys = match self.relationship_properties(rel_id) {
1314 Some(props) => props.into_keys().collect::<Vec<_>>(),
1315 None => return false,
1316 };
1317
1318 for key in existing_keys {
1319 self.remove_relationship_property(rel_id, &key);
1320 }
1321
1322 for (k, v) in properties {
1323 self.set_relationship_property(rel_id, k.to_string(), v);
1324 }
1325
1326 true
1327 }
1328
1329 fn merge_relationship_properties(
1330 &mut self,
1331 rel_id: RelationshipId,
1332 properties: Properties,
1333 ) -> bool {
1334 if !self.contains_relationship(rel_id) {
1335 return false;
1336 }
1337
1338 for (k, v) in properties {
1339 self.set_relationship_property(rel_id, k.to_string(), v);
1340 }
1341
1342 true
1343 }
1344
1345 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1346 let rel_ids = self.relationship_ids_of(node_id, direction);
1347 self.delete_relationships(&rel_ids)
1348 }
1349
1350 fn delete_relationships(&mut self, rel_ids: &[RelationshipId]) -> usize {
1355 rel_ids
1356 .iter()
1357 .filter(|&&rel_id| self.delete_relationship(rel_id))
1358 .count()
1359 }
1360
1361 fn detach_delete_nodes(&mut self, node_ids: &[NodeId]) -> usize {
1365 node_ids
1366 .iter()
1367 .filter(|&&node_id| self.detach_delete_node(node_id))
1368 .count()
1369 }
1370
1371 fn get_or_create_node(
1372 &mut self,
1373 labels: Vec<String>,
1374 match_key: &str,
1375 match_value: &PropertyValue,
1376 init_properties: Properties,
1377 ) -> NodeRecord
1378 where
1379 Self: Sized,
1380 {
1381 for label in &labels {
1382 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1383 if let Some(node) = matches.into_iter().next() {
1384 return node;
1385 }
1386 }
1387
1388 self.create_node(labels, init_properties)
1389 }
1390}