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