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 #[allow(clippy::too_many_arguments)]
811 fn node_range_ordered_chunk(
812 &self,
813 _label: &str,
814 _property: &str,
815 _lo: Option<&PropertyValue>,
816 _hi: Option<&PropertyValue>,
817 _descending: bool,
818 _after: Option<(&PropertyValue, NodeId)>,
819 _max: usize,
820 ) -> Option<Vec<NodeId>> {
821 None
822 }
823
824 fn node_point_within_bbox(
829 &self,
830 _label: &str,
831 _property: &str,
832 _ll: (f64, f64),
833 _ur: (f64, f64),
834 ) -> Option<Vec<NodeId>> {
835 None
836 }
837
838 fn node_point_within_distance(
842 &self,
843 _label: &str,
844 _property: &str,
845 _center: (f64, f64),
846 _max_distance: f64,
847 ) -> Option<Vec<NodeId>> {
848 None
849 }
850
851 fn relationship_text_candidates(
855 &self,
856 _rel_type: &str,
857 _property: &str,
858 _query: &str,
859 ) -> Option<Vec<RelationshipId>> {
860 None
861 }
862
863 fn relationship_range_candidates(
866 &self,
867 _rel_type: &str,
868 _property: &str,
869 _lo: Option<&PropertyValue>,
870 _hi: Option<&PropertyValue>,
871 ) -> Option<Vec<RelationshipId>> {
872 None
873 }
874
875 fn relationship_point_within_bbox(
879 &self,
880 _rel_type: &str,
881 _property: &str,
882 _ll: (f64, f64),
883 _ur: (f64, f64),
884 ) -> Option<Vec<RelationshipId>> {
885 None
886 }
887
888 fn relationship_point_within_distance(
892 &self,
893 _rel_type: &str,
894 _property: &str,
895 _center: (f64, f64),
896 _max_distance: f64,
897 ) -> Option<Vec<RelationshipId>> {
898 None
899 }
900}
901
902pub trait GraphCatalog {
910 fn node_count(&self) -> usize;
911 fn relationship_count(&self) -> usize;
912 fn has_label_name(&self, label: &str) -> bool;
913 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
914 fn has_property_key(&self, key: &str) -> bool;
915}
916
917impl<T: GraphStorage> GraphCatalog for T {
918 fn node_count(&self) -> usize {
919 GraphStorage::node_count(self)
920 }
921 fn relationship_count(&self) -> usize {
922 GraphStorage::relationship_count(self)
923 }
924 fn has_label_name(&self, label: &str) -> bool {
925 GraphStorage::has_label_name(self, label)
926 }
927 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
928 GraphStorage::has_relationship_type_name(self, rel_type)
929 }
930 fn has_property_key(&self, key: &str) -> bool {
931 GraphStorage::has_property_key(self, key)
932 }
933}
934
935pub trait BorrowedGraphStorage: GraphStorage {
946 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
947 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
948
949 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
950 Box::new(
951 self.all_node_ids()
952 .into_iter()
953 .filter_map(|id| self.node_ref(id)),
954 )
955 }
956
957 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
958 Box::new(
959 self.node_ids_by_label(label)
960 .into_iter()
961 .filter_map(|id| self.node_ref(id)),
962 )
963 }
964
965 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
966 Box::new(
967 self.all_rel_ids()
968 .into_iter()
969 .filter_map(|id| self.relationship_ref(id)),
970 )
971 }
972
973 fn relationship_refs_by_type(
974 &self,
975 rel_type: &str,
976 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
977 Box::new(
978 self.rel_ids_by_type(rel_type)
979 .into_iter()
980 .filter_map(|id| self.relationship_ref(id)),
981 )
982 }
983}
984
985pub trait GraphStorageMut: GraphStorage {
995 fn try_create_node(
998 &mut self,
999 labels: Vec<String>,
1000 properties: Properties,
1001 ) -> Option<NodeRecord>;
1002
1003 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord
1008 where
1009 Self: Sized,
1010 {
1011 self.try_create_node(labels, properties)
1012 .unwrap_or_else(|| NodeRecord {
1013 id: NodeId::MAX,
1014 labels: Vec::new(),
1015 properties: Properties::new(),
1016 })
1017 }
1018
1019 fn create_relationship(
1020 &mut self,
1021 src: NodeId,
1022 dst: NodeId,
1023 rel_type: &str,
1024 properties: Properties,
1025 ) -> Option<RelationshipRecord>;
1026
1027 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
1030
1031 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
1032
1033 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1034 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
1035
1036 fn set_relationship_property(
1039 &mut self,
1040 rel_id: RelationshipId,
1041 key: String,
1042 value: PropertyValue,
1043 ) -> bool;
1044
1045 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
1046
1047 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
1050
1051 fn delete_node(&mut self, node_id: NodeId) -> bool;
1053
1054 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
1056
1057 fn clear(&mut self);
1066
1067 #[allow(clippy::result_large_err)]
1074 fn create_index(
1075 &mut self,
1076 _request: IndexRequest,
1077 _if_not_exists: bool,
1078 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1079 Err(CreateIndexError::Unsupported(
1080 "this backend does not maintain an index catalog",
1081 ))
1082 }
1083
1084 fn drop_index(
1089 &mut self,
1090 _name: &str,
1091 _if_exists: bool,
1092 ) -> Result<DropIndexOutcome, DropIndexError> {
1093 Err(DropIndexError::Unsupported(
1094 "this backend does not maintain an index catalog",
1095 ))
1096 }
1097
1098 fn create_constraint(
1103 &mut self,
1104 _request: ConstraintRequest,
1105 _if_not_exists: bool,
1106 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1107 Err(CreateConstraintError::Unsupported(
1108 "this backend does not maintain a constraint catalog",
1109 ))
1110 }
1111
1112 fn drop_constraint(
1115 &mut self,
1116 _name: &str,
1117 _if_exists: bool,
1118 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1119 Err(DropConstraintError::Unsupported(
1120 "this backend does not maintain a constraint catalog",
1121 ))
1122 }
1123
1124 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1127 where
1128 Self: Sized,
1129 {
1130 if !self.contains_node(node_id) {
1131 return false;
1132 }
1133
1134 let existing_keys = match self.node_properties(node_id) {
1135 Some(props) => props.into_keys().collect::<Vec<_>>(),
1136 None => return false,
1137 };
1138
1139 for key in existing_keys {
1140 self.remove_node_property(node_id, &key);
1141 }
1142
1143 for (k, v) in properties {
1144 self.set_node_property(node_id, k.to_string(), v);
1145 }
1146
1147 true
1148 }
1149
1150 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1151 if !self.contains_node(node_id) {
1152 return false;
1153 }
1154
1155 for (k, v) in properties {
1156 self.set_node_property(node_id, k.to_string(), v);
1157 }
1158
1159 true
1160 }
1161
1162 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1163 where
1164 Self: Sized,
1165 {
1166 if !self.contains_node(node_id) {
1167 return false;
1168 }
1169
1170 let current = match self.node_labels(node_id) {
1171 Some(labels) => labels,
1172 None => return false,
1173 };
1174
1175 for label in ¤t {
1176 self.remove_node_label(node_id, label);
1177 }
1178
1179 for label in &labels {
1180 self.add_node_label(node_id, label);
1181 }
1182
1183 true
1184 }
1185
1186 fn replace_relationship_properties(
1187 &mut self,
1188 rel_id: RelationshipId,
1189 properties: Properties,
1190 ) -> bool
1191 where
1192 Self: Sized,
1193 {
1194 if !self.contains_relationship(rel_id) {
1195 return false;
1196 }
1197
1198 let existing_keys = match self.relationship_properties(rel_id) {
1199 Some(props) => props.into_keys().collect::<Vec<_>>(),
1200 None => return false,
1201 };
1202
1203 for key in existing_keys {
1204 self.remove_relationship_property(rel_id, &key);
1205 }
1206
1207 for (k, v) in properties {
1208 self.set_relationship_property(rel_id, k.to_string(), v);
1209 }
1210
1211 true
1212 }
1213
1214 fn merge_relationship_properties(
1215 &mut self,
1216 rel_id: RelationshipId,
1217 properties: Properties,
1218 ) -> bool {
1219 if !self.contains_relationship(rel_id) {
1220 return false;
1221 }
1222
1223 for (k, v) in properties {
1224 self.set_relationship_property(rel_id, k.to_string(), v);
1225 }
1226
1227 true
1228 }
1229
1230 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1231 let rel_ids = self.relationship_ids_of(node_id, direction);
1232
1233 let mut deleted = 0;
1234 for rel_id in rel_ids {
1235 if self.delete_relationship(rel_id) {
1236 deleted += 1;
1237 }
1238 }
1239 deleted
1240 }
1241
1242 fn get_or_create_node(
1243 &mut self,
1244 labels: Vec<String>,
1245 match_key: &str,
1246 match_value: &PropertyValue,
1247 init_properties: Properties,
1248 ) -> NodeRecord
1249 where
1250 Self: Sized,
1251 {
1252 for label in &labels {
1253 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1254 if let Some(node) = matches.into_iter().next() {
1255 return node;
1256 }
1257 }
1258
1259 self.create_node(labels, init_properties)
1260 }
1261}