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 graph_stats(&self) -> GraphStats {
770 GraphStats::default()
771 }
772
773 fn node_text_candidates(
782 &self,
783 _label: &str,
784 _property: &str,
785 _query: &str,
786 ) -> Option<Vec<NodeId>> {
787 None
788 }
789
790 fn node_range_candidates(
796 &self,
797 _label: &str,
798 _property: &str,
799 _lo: Option<&PropertyValue>,
800 _hi: Option<&PropertyValue>,
801 ) -> Option<Vec<NodeId>> {
802 None
803 }
804
805 fn node_range_other_temporal_kind_ids(
812 &self,
813 _label: &str,
814 _property: &str,
815 _like: &PropertyValue,
816 ) -> Option<Vec<NodeId>> {
817 None
818 }
819
820 #[allow(clippy::too_many_arguments)]
826 fn node_range_ordered_chunk(
827 &self,
828 _label: &str,
829 _property: &str,
830 _lo: Option<&PropertyValue>,
831 _hi: Option<&PropertyValue>,
832 _descending: bool,
833 _after: Option<(&PropertyValue, NodeId)>,
834 _max: usize,
835 ) -> Option<Vec<NodeId>> {
836 None
837 }
838
839 fn node_point_within_bbox(
844 &self,
845 _label: &str,
846 _property: &str,
847 _ll: (f64, f64),
848 _ur: (f64, f64),
849 ) -> Option<Vec<NodeId>> {
850 None
851 }
852
853 fn node_point_within_distance(
857 &self,
858 _label: &str,
859 _property: &str,
860 _center: (f64, f64),
861 _max_distance: f64,
862 ) -> Option<Vec<NodeId>> {
863 None
864 }
865
866 fn relationship_text_candidates(
870 &self,
871 _rel_type: &str,
872 _property: &str,
873 _query: &str,
874 ) -> Option<Vec<RelationshipId>> {
875 None
876 }
877
878 fn relationship_range_candidates(
881 &self,
882 _rel_type: &str,
883 _property: &str,
884 _lo: Option<&PropertyValue>,
885 _hi: Option<&PropertyValue>,
886 ) -> Option<Vec<RelationshipId>> {
887 None
888 }
889
890 fn relationship_range_other_temporal_kind_ids(
893 &self,
894 _rel_type: &str,
895 _property: &str,
896 _like: &PropertyValue,
897 ) -> Option<Vec<RelationshipId>> {
898 None
899 }
900
901 fn relationship_point_within_bbox(
905 &self,
906 _rel_type: &str,
907 _property: &str,
908 _ll: (f64, f64),
909 _ur: (f64, f64),
910 ) -> Option<Vec<RelationshipId>> {
911 None
912 }
913
914 fn relationship_point_within_distance(
918 &self,
919 _rel_type: &str,
920 _property: &str,
921 _center: (f64, f64),
922 _max_distance: f64,
923 ) -> Option<Vec<RelationshipId>> {
924 None
925 }
926}
927
928pub trait GraphCatalog {
936 fn node_count(&self) -> usize;
937 fn relationship_count(&self) -> usize;
938 fn has_label_name(&self, label: &str) -> bool;
939 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
940 fn has_property_key(&self, key: &str) -> bool;
941}
942
943impl<T: GraphStorage> GraphCatalog for T {
944 fn node_count(&self) -> usize {
945 GraphStorage::node_count(self)
946 }
947 fn relationship_count(&self) -> usize {
948 GraphStorage::relationship_count(self)
949 }
950 fn has_label_name(&self, label: &str) -> bool {
951 GraphStorage::has_label_name(self, label)
952 }
953 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
954 GraphStorage::has_relationship_type_name(self, rel_type)
955 }
956 fn has_property_key(&self, key: &str) -> bool {
957 GraphStorage::has_property_key(self, key)
958 }
959}
960
961pub trait BorrowedGraphStorage: GraphStorage {
972 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
973 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
974
975 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
976 Box::new(
977 self.all_node_ids()
978 .into_iter()
979 .filter_map(|id| self.node_ref(id)),
980 )
981 }
982
983 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
984 Box::new(
985 self.node_ids_by_label(label)
986 .into_iter()
987 .filter_map(|id| self.node_ref(id)),
988 )
989 }
990
991 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
992 Box::new(
993 self.all_rel_ids()
994 .into_iter()
995 .filter_map(|id| self.relationship_ref(id)),
996 )
997 }
998
999 fn relationship_refs_by_type(
1000 &self,
1001 rel_type: &str,
1002 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
1003 Box::new(
1004 self.rel_ids_by_type(rel_type)
1005 .into_iter()
1006 .filter_map(|id| self.relationship_ref(id)),
1007 )
1008 }
1009}
1010
1011pub trait GraphStorageMut: GraphStorage {
1021 fn try_create_node(
1024 &mut self,
1025 labels: Vec<String>,
1026 properties: Properties,
1027 ) -> Option<NodeRecord>;
1028
1029 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord
1034 where
1035 Self: Sized,
1036 {
1037 self.try_create_node(labels, properties)
1038 .unwrap_or_else(|| NodeRecord {
1039 id: NodeId::MAX,
1040 labels: Vec::new(),
1041 properties: Properties::new(),
1042 })
1043 }
1044
1045 fn create_relationship(
1046 &mut self,
1047 src: NodeId,
1048 dst: NodeId,
1049 rel_type: &str,
1050 properties: Properties,
1051 ) -> Option<RelationshipRecord>;
1052
1053 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
1056
1057 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
1058
1059 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1060 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1061
1062 fn set_relationship_property(
1065 &mut self,
1066 rel_id: RelationshipId,
1067 key: String,
1068 value: PropertyValue,
1069 ) -> bool;
1070
1071 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
1072
1073 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
1076
1077 fn delete_node(&mut self, node_id: NodeId) -> bool;
1079
1080 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
1082
1083 fn clear(&mut self);
1092
1093 #[allow(clippy::result_large_err)]
1100 fn create_index(
1101 &mut self,
1102 _request: IndexRequest,
1103 _if_not_exists: bool,
1104 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1105 Err(CreateIndexError::Unsupported(
1106 "this backend does not maintain an index catalog",
1107 ))
1108 }
1109
1110 fn drop_index(
1115 &mut self,
1116 _name: &str,
1117 _if_exists: bool,
1118 ) -> Result<DropIndexOutcome, DropIndexError> {
1119 Err(DropIndexError::Unsupported(
1120 "this backend does not maintain an index catalog",
1121 ))
1122 }
1123
1124 fn create_constraint(
1129 &mut self,
1130 _request: ConstraintRequest,
1131 _if_not_exists: bool,
1132 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1133 Err(CreateConstraintError::Unsupported(
1134 "this backend does not maintain a constraint catalog",
1135 ))
1136 }
1137
1138 fn drop_constraint(
1141 &mut self,
1142 _name: &str,
1143 _if_exists: bool,
1144 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1145 Err(DropConstraintError::Unsupported(
1146 "this backend does not maintain a constraint catalog",
1147 ))
1148 }
1149
1150 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1153 where
1154 Self: Sized,
1155 {
1156 if !self.contains_node(node_id) {
1157 return false;
1158 }
1159
1160 let existing_keys = match self.node_properties(node_id) {
1161 Some(props) => props.into_keys().collect::<Vec<_>>(),
1162 None => return false,
1163 };
1164
1165 for key in existing_keys {
1166 self.remove_node_property(node_id, &key);
1167 }
1168
1169 for (k, v) in properties {
1170 self.set_node_property(node_id, k.to_string(), v);
1171 }
1172
1173 true
1174 }
1175
1176 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1177 if !self.contains_node(node_id) {
1178 return false;
1179 }
1180
1181 for (k, v) in properties {
1182 self.set_node_property(node_id, k.to_string(), v);
1183 }
1184
1185 true
1186 }
1187
1188 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1189 where
1190 Self: Sized,
1191 {
1192 if !self.contains_node(node_id) {
1193 return false;
1194 }
1195
1196 let current = match self.node_labels(node_id) {
1197 Some(labels) => labels,
1198 None => return false,
1199 };
1200
1201 for label in ¤t {
1202 self.remove_node_label(node_id, label);
1203 }
1204
1205 for label in &labels {
1206 self.add_node_label(node_id, label);
1207 }
1208
1209 true
1210 }
1211
1212 fn replace_relationship_properties(
1213 &mut self,
1214 rel_id: RelationshipId,
1215 properties: Properties,
1216 ) -> bool
1217 where
1218 Self: Sized,
1219 {
1220 if !self.contains_relationship(rel_id) {
1221 return false;
1222 }
1223
1224 let existing_keys = match self.relationship_properties(rel_id) {
1225 Some(props) => props.into_keys().collect::<Vec<_>>(),
1226 None => return false,
1227 };
1228
1229 for key in existing_keys {
1230 self.remove_relationship_property(rel_id, &key);
1231 }
1232
1233 for (k, v) in properties {
1234 self.set_relationship_property(rel_id, k.to_string(), v);
1235 }
1236
1237 true
1238 }
1239
1240 fn merge_relationship_properties(
1241 &mut self,
1242 rel_id: RelationshipId,
1243 properties: Properties,
1244 ) -> bool {
1245 if !self.contains_relationship(rel_id) {
1246 return false;
1247 }
1248
1249 for (k, v) in properties {
1250 self.set_relationship_property(rel_id, k.to_string(), v);
1251 }
1252
1253 true
1254 }
1255
1256 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1257 let rel_ids = self.relationship_ids_of(node_id, direction);
1258
1259 let mut deleted = 0;
1260 for rel_id in rel_ids {
1261 if self.delete_relationship(rel_id) {
1262 deleted += 1;
1263 }
1264 }
1265 deleted
1266 }
1267
1268 fn get_or_create_node(
1269 &mut self,
1270 labels: Vec<String>,
1271 match_key: &str,
1272 match_value: &PropertyValue,
1273 init_properties: Properties,
1274 ) -> NodeRecord
1275 where
1276 Self: Sized,
1277 {
1278 for label in &labels {
1279 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1280 if let Some(node) = matches.into_iter().next() {
1281 return node;
1282 }
1283 }
1284
1285 self.create_node(labels, init_properties)
1286 }
1287}