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, NodeId, NodeRecord, Properties, PropertyValue, RelationshipId,
19 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 all_nodes(&self) -> Vec<NodeRecord> {
155 self.all_node_ids()
156 .into_iter()
157 .filter_map(|id| self.node(id))
158 .collect()
159 }
160
161 fn nodes_by_label(&self, label: &str) -> Vec<NodeRecord> {
162 self.node_ids_by_label(label)
163 .into_iter()
164 .filter_map(|id| self.node(id))
165 .collect()
166 }
167
168 fn all_relationships(&self) -> Vec<RelationshipRecord> {
169 self.all_rel_ids()
170 .into_iter()
171 .filter_map(|id| self.relationship(id))
172 .collect()
173 }
174
175 fn relationships_by_type(&self, rel_type: &str) -> Vec<RelationshipRecord> {
176 self.rel_ids_by_type(rel_type)
177 .into_iter()
178 .filter_map(|id| self.relationship(id))
179 .collect()
180 }
181
182 fn relationship_ids_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipId> {
185 self.expand_ids(node_id, direction, &[])
186 .into_iter()
187 .map(|(rel_id, _)| rel_id)
188 .collect()
189 }
190
191 fn outgoing_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
192 self.relationship_ids_of(node_id, Direction::Right)
193 .into_iter()
194 .filter_map(|id| self.relationship(id))
195 .collect()
196 }
197
198 fn incoming_relationships(&self, node_id: NodeId) -> Vec<RelationshipRecord> {
199 self.relationship_ids_of(node_id, Direction::Left)
200 .into_iter()
201 .filter_map(|id| self.relationship(id))
202 .collect()
203 }
204
205 fn relationships_of(&self, node_id: NodeId, direction: Direction) -> Vec<RelationshipRecord> {
206 self.relationship_ids_of(node_id, direction)
207 .into_iter()
208 .filter_map(|id| self.relationship(id))
209 .collect()
210 }
211
212 fn degree(&self, node_id: NodeId, direction: Direction) -> usize {
213 self.expand_ids(node_id, direction, &[]).len()
214 }
215
216 fn is_isolated(&self, node_id: NodeId) -> bool {
217 self.degree(node_id, Direction::Undirected) == 0
218 }
219
220 fn expand(
221 &self,
222 node_id: NodeId,
223 direction: Direction,
224 types: &[String],
225 ) -> Vec<(RelationshipRecord, NodeRecord)> {
226 self.expand_ids(node_id, direction, types)
227 .into_iter()
228 .filter_map(|(rid, nid)| {
229 let rel = self.relationship(rid)?;
230 let node = self.node(nid)?;
231 Some((rel, node))
232 })
233 .collect()
234 }
235
236 fn expand_detailed(
237 &self,
238 node_id: NodeId,
239 direction: Direction,
240 types: &[String],
241 ) -> Vec<ExpandedRelationship> {
242 self.expand(node_id, direction, types)
243 .into_iter()
244 .map(|(relationship, other_node)| ExpandedRelationship {
245 relationship,
246 other_node,
247 })
248 .collect()
249 }
250
251 fn neighbors(
252 &self,
253 node_id: NodeId,
254 direction: Direction,
255 types: &[String],
256 ) -> Vec<NodeRecord> {
257 self.expand_ids(node_id, direction, types)
258 .into_iter()
259 .filter_map(|(_, nid)| self.node(nid))
260 .collect()
261 }
262
263 fn node_has_label(&self, node_id: NodeId, label: &str) -> bool
266 where
267 Self: Sized,
268 {
269 self.with_node(node_id, |n| n.labels.iter().any(|l| l == label))
270 .unwrap_or(false)
271 }
272
273 fn node_labels(&self, node_id: NodeId) -> Option<Vec<String>>
274 where
275 Self: Sized,
276 {
277 self.with_node(node_id, |n| n.labels.clone())
278 }
279
280 fn node_properties(&self, node_id: NodeId) -> Option<Properties>
281 where
282 Self: Sized,
283 {
284 self.with_node(node_id, |n| n.properties.clone())
285 }
286
287 fn node_property(&self, node_id: NodeId, key: &str) -> Option<PropertyValue>
288 where
289 Self: Sized,
290 {
291 self.with_node(node_id, |n| n.properties.get(key).cloned())
292 .flatten()
293 }
294
295 fn relationship_type(&self, rel_id: RelationshipId) -> Option<String>
298 where
299 Self: Sized,
300 {
301 self.with_relationship(rel_id, |r| r.rel_type.clone())
302 }
303
304 fn relationship_properties(&self, rel_id: RelationshipId) -> Option<Properties>
305 where
306 Self: Sized,
307 {
308 self.with_relationship(rel_id, |r| r.properties.clone())
309 }
310
311 fn relationship_property(&self, rel_id: RelationshipId, key: &str) -> Option<PropertyValue>
312 where
313 Self: Sized,
314 {
315 self.with_relationship(rel_id, |r| r.properties.get(key).cloned())
316 .flatten()
317 }
318
319 fn relationship_source(&self, rel_id: RelationshipId) -> Option<NodeId> {
320 self.relationship_endpoints(rel_id).map(|(s, _)| s)
321 }
322
323 fn relationship_target(&self, rel_id: RelationshipId) -> Option<NodeId> {
324 self.relationship_endpoints(rel_id).map(|(_, d)| d)
325 }
326
327 fn other_node(&self, rel_id: RelationshipId, node_id: NodeId) -> Option<NodeId> {
328 let (src, dst) = self.relationship_endpoints(rel_id)?;
329 if src == node_id {
330 Some(dst)
331 } else if dst == node_id {
332 Some(src)
333 } else {
334 None
335 }
336 }
337
338 fn has_label_name(&self, label: &str) -> bool {
341 self.all_labels().iter().any(|l| l == label)
342 }
343
344 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
345 self.all_relationship_types().iter().any(|t| t == rel_type)
346 }
347
348 fn all_node_property_keys(&self) -> Vec<String>
349 where
350 Self: Sized,
351 {
352 let mut keys = BTreeSet::new();
353 for id in self.all_node_ids() {
354 self.with_node(id, |n| {
355 for key in n.properties.keys() {
356 keys.insert(key.clone());
357 }
358 });
359 }
360 keys.into_iter().collect()
361 }
362
363 fn all_relationship_property_keys(&self) -> Vec<String>
364 where
365 Self: Sized,
366 {
367 let mut keys = BTreeSet::new();
368 for id in self.all_rel_ids() {
369 self.with_relationship(id, |r| {
370 for key in r.properties.keys() {
371 keys.insert(key.clone());
372 }
373 });
374 }
375 keys.into_iter().collect()
376 }
377
378 fn all_property_keys(&self) -> Vec<String>
379 where
380 Self: Sized,
381 {
382 let mut keys = BTreeSet::new();
383 for key in self.all_node_property_keys() {
384 keys.insert(key);
385 }
386 for key in self.all_relationship_property_keys() {
387 keys.insert(key);
388 }
389 keys.into_iter().collect()
390 }
391
392 fn has_property_key(&self, key: &str) -> bool
393 where
394 Self: Sized,
395 {
396 self.all_node_property_keys().iter().any(|k| k == key)
397 || self
398 .all_relationship_property_keys()
399 .iter()
400 .any(|k| k == key)
401 }
402
403 fn label_property_keys(&self, label: &str) -> Vec<String>
404 where
405 Self: Sized,
406 {
407 let mut keys = BTreeSet::new();
408 for id in self.node_ids_by_label(label) {
409 self.with_node(id, |n| {
410 for key in n.properties.keys() {
411 keys.insert(key.clone());
412 }
413 });
414 }
415 keys.into_iter().collect()
416 }
417
418 fn rel_type_property_keys(&self, rel_type: &str) -> Vec<String>
419 where
420 Self: Sized,
421 {
422 let mut keys = BTreeSet::new();
423 for id in self.rel_ids_by_type(rel_type) {
424 self.with_relationship(id, |r| {
425 for key in r.properties.keys() {
426 keys.insert(key.clone());
427 }
428 });
429 }
430 keys.into_iter().collect()
431 }
432
433 fn label_has_property_key(&self, label: &str, key: &str) -> bool
434 where
435 Self: Sized,
436 {
437 self.node_ids_by_label(label).into_iter().any(|id| {
438 self.with_node(id, |n| n.properties.contains_key(key))
439 .unwrap_or(false)
440 })
441 }
442
443 fn rel_type_has_property_key(&self, rel_type: &str, key: &str) -> bool
444 where
445 Self: Sized,
446 {
447 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
448 self.with_relationship(id, |r| r.properties.contains_key(key))
449 .unwrap_or(false)
450 })
451 }
452
453 fn find_nodes_by_property(
456 &self,
457 label: Option<&str>,
458 key: &str,
459 value: &PropertyValue,
460 ) -> Vec<NodeRecord>
461 where
462 Self: Sized,
463 {
464 let ids = match label {
465 Some(label) => self.node_ids_by_label(label),
466 None => self.all_node_ids(),
467 };
468
469 ids.into_iter()
470 .filter_map(|id| {
471 let matches = self
472 .with_node(id, |n| n.properties.get(key) == Some(value))
473 .unwrap_or(false);
474 if matches {
475 self.node(id)
476 } else {
477 None
478 }
479 })
480 .collect()
481 }
482
483 fn find_node_ids_by_property(
484 &self,
485 label: Option<&str>,
486 key: &str,
487 value: &PropertyValue,
488 ) -> Vec<NodeId>
489 where
490 Self: Sized,
491 {
492 self.find_nodes_by_property(label, key, value)
493 .into_iter()
494 .map(|n| n.id)
495 .collect()
496 }
497
498 fn find_relationships_by_property(
499 &self,
500 rel_type: Option<&str>,
501 key: &str,
502 value: &PropertyValue,
503 ) -> Vec<RelationshipRecord>
504 where
505 Self: Sized,
506 {
507 let ids = match rel_type {
508 Some(rel_type) => self.rel_ids_by_type(rel_type),
509 None => self.all_rel_ids(),
510 };
511
512 ids.into_iter()
513 .filter_map(|id| {
514 let matches = self
515 .with_relationship(id, |r| r.properties.get(key) == Some(value))
516 .unwrap_or(false);
517 if matches {
518 self.relationship(id)
519 } else {
520 None
521 }
522 })
523 .collect()
524 }
525
526 fn find_relationship_ids_by_property(
527 &self,
528 rel_type: Option<&str>,
529 key: &str,
530 value: &PropertyValue,
531 ) -> Vec<RelationshipId>
532 where
533 Self: Sized,
534 {
535 self.find_relationships_by_property(rel_type, key, value)
536 .into_iter()
537 .map(|r| r.id)
538 .collect()
539 }
540
541 fn node_exists_with_label_and_property(
542 &self,
543 label: &str,
544 key: &str,
545 value: &PropertyValue,
546 ) -> bool
547 where
548 Self: Sized,
549 {
550 self.node_ids_by_label(label).into_iter().any(|id| {
551 self.with_node(id, |n| n.properties.get(key) == Some(value))
552 .unwrap_or(false)
553 })
554 }
555
556 fn relationship_exists_with_type_and_property(
557 &self,
558 rel_type: &str,
559 key: &str,
560 value: &PropertyValue,
561 ) -> bool
562 where
563 Self: Sized,
564 {
565 self.rel_ids_by_type(rel_type).into_iter().any(|id| {
566 self.with_relationship(id, |r| r.properties.get(key) == Some(value))
567 .unwrap_or(false)
568 })
569 }
570
571 fn list_indexes(&self) -> Vec<IndexDefinition> {
578 Vec::new()
579 }
580
581 fn get_index(&self, _name: &str) -> Option<IndexDefinition> {
582 None
583 }
584
585 fn fulltext_search(&self, _name: &str, _query: &str) -> Vec<(u64, f64)> {
591 Vec::new()
592 }
593
594 fn list_constraints(&self) -> Vec<ConstraintDefinition> {
597 Vec::new()
598 }
599
600 fn get_constraint(&self, _name: &str) -> Option<ConstraintDefinition> {
601 None
602 }
603
604 fn check_node_create_against_constraints(
610 &self,
611 _labels: &[String],
612 _properties: &Properties,
613 ) -> Result<(), String> {
614 Ok(())
615 }
616
617 fn check_relationship_create_against_constraints(
619 &self,
620 _rel_type: &str,
621 _properties: &Properties,
622 ) -> Result<(), String> {
623 Ok(())
624 }
625
626 fn check_node_set_property_against_constraints(
629 &self,
630 _node_id: NodeId,
631 _key: &str,
632 _value: &PropertyValue,
633 ) -> Result<(), String> {
634 Ok(())
635 }
636
637 fn check_node_remove_property_against_constraints(
640 &self,
641 _node_id: NodeId,
642 _key: &str,
643 ) -> Result<(), String> {
644 Ok(())
645 }
646
647 fn check_node_replace_properties_against_constraints(
651 &self,
652 _node_id: NodeId,
653 _properties: &Properties,
654 ) -> Result<(), String> {
655 Ok(())
656 }
657
658 fn check_relationship_set_property_against_constraints(
661 &self,
662 _rel_id: RelationshipId,
663 _key: &str,
664 _value: &PropertyValue,
665 ) -> Result<(), String> {
666 Ok(())
667 }
668
669 fn check_relationship_remove_property_against_constraints(
670 &self,
671 _rel_id: RelationshipId,
672 _key: &str,
673 ) -> Result<(), String> {
674 Ok(())
675 }
676
677 fn check_relationship_replace_properties_against_constraints(
681 &self,
682 _rel_id: RelationshipId,
683 _properties: &Properties,
684 ) -> Result<(), String> {
685 Ok(())
686 }
687
688 fn check_node_add_label_against_constraints(
691 &self,
692 _node_id: NodeId,
693 _label: &str,
694 ) -> Result<(), String> {
695 Ok(())
696 }
697
698 fn graph_stats(&self) -> GraphStats {
702 GraphStats::default()
703 }
704
705 fn node_text_candidates(
714 &self,
715 _label: &str,
716 _property: &str,
717 _query: &str,
718 ) -> Option<Vec<NodeId>> {
719 None
720 }
721
722 fn node_range_candidates(
728 &self,
729 _label: &str,
730 _property: &str,
731 _lo: Option<&PropertyValue>,
732 _hi: Option<&PropertyValue>,
733 ) -> Option<Vec<NodeId>> {
734 None
735 }
736
737 fn node_point_within_bbox(
742 &self,
743 _label: &str,
744 _property: &str,
745 _ll: (f64, f64),
746 _ur: (f64, f64),
747 ) -> Option<Vec<NodeId>> {
748 None
749 }
750
751 fn node_point_within_distance(
755 &self,
756 _label: &str,
757 _property: &str,
758 _center: (f64, f64),
759 _max_distance: f64,
760 ) -> Option<Vec<NodeId>> {
761 None
762 }
763
764 fn relationship_text_candidates(
768 &self,
769 _rel_type: &str,
770 _property: &str,
771 _query: &str,
772 ) -> Option<Vec<RelationshipId>> {
773 None
774 }
775
776 fn relationship_range_candidates(
779 &self,
780 _rel_type: &str,
781 _property: &str,
782 _lo: Option<&PropertyValue>,
783 _hi: Option<&PropertyValue>,
784 ) -> Option<Vec<RelationshipId>> {
785 None
786 }
787
788 fn relationship_point_within_bbox(
792 &self,
793 _rel_type: &str,
794 _property: &str,
795 _ll: (f64, f64),
796 _ur: (f64, f64),
797 ) -> Option<Vec<RelationshipId>> {
798 None
799 }
800
801 fn relationship_point_within_distance(
805 &self,
806 _rel_type: &str,
807 _property: &str,
808 _center: (f64, f64),
809 _max_distance: f64,
810 ) -> Option<Vec<RelationshipId>> {
811 None
812 }
813}
814
815pub trait GraphCatalog {
823 fn node_count(&self) -> usize;
824 fn relationship_count(&self) -> usize;
825 fn has_label_name(&self, label: &str) -> bool;
826 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
827 fn has_property_key(&self, key: &str) -> bool;
828}
829
830impl<T: GraphStorage> GraphCatalog for T {
831 fn node_count(&self) -> usize {
832 GraphStorage::node_count(self)
833 }
834 fn relationship_count(&self) -> usize {
835 GraphStorage::relationship_count(self)
836 }
837 fn has_label_name(&self, label: &str) -> bool {
838 GraphStorage::has_label_name(self, label)
839 }
840 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
841 GraphStorage::has_relationship_type_name(self, rel_type)
842 }
843 fn has_property_key(&self, key: &str) -> bool {
844 GraphStorage::has_property_key(self, key)
845 }
846}
847
848pub trait BorrowedGraphStorage: GraphStorage {
859 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
860 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
861
862 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
863 Box::new(
864 self.all_node_ids()
865 .into_iter()
866 .filter_map(|id| self.node_ref(id)),
867 )
868 }
869
870 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
871 Box::new(
872 self.node_ids_by_label(label)
873 .into_iter()
874 .filter_map(|id| self.node_ref(id)),
875 )
876 }
877
878 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
879 Box::new(
880 self.all_rel_ids()
881 .into_iter()
882 .filter_map(|id| self.relationship_ref(id)),
883 )
884 }
885
886 fn relationship_refs_by_type(
887 &self,
888 rel_type: &str,
889 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
890 Box::new(
891 self.rel_ids_by_type(rel_type)
892 .into_iter()
893 .filter_map(|id| self.relationship_ref(id)),
894 )
895 }
896}
897
898pub trait GraphStorageMut: GraphStorage {
908 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord;
911
912 fn create_relationship(
913 &mut self,
914 src: NodeId,
915 dst: NodeId,
916 rel_type: &str,
917 properties: Properties,
918 ) -> Option<RelationshipRecord>;
919
920 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
923
924 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
925
926 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
927 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
928
929 fn set_relationship_property(
932 &mut self,
933 rel_id: RelationshipId,
934 key: String,
935 value: PropertyValue,
936 ) -> bool;
937
938 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
939
940 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
943
944 fn delete_node(&mut self, node_id: NodeId) -> bool;
946
947 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
949
950 fn clear(&mut self);
959
960 #[allow(clippy::result_large_err)]
967 fn create_index(
968 &mut self,
969 _request: IndexRequest,
970 _if_not_exists: bool,
971 ) -> Result<CreateIndexOutcome, CreateIndexError> {
972 Err(CreateIndexError::Unsupported(
973 "this backend does not maintain an index catalog",
974 ))
975 }
976
977 fn drop_index(
982 &mut self,
983 _name: &str,
984 _if_exists: bool,
985 ) -> Result<DropIndexOutcome, DropIndexError> {
986 Err(DropIndexError::Unsupported(
987 "this backend does not maintain an index catalog",
988 ))
989 }
990
991 fn create_constraint(
996 &mut self,
997 _request: ConstraintRequest,
998 _if_not_exists: bool,
999 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1000 Err(CreateConstraintError::Unsupported(
1001 "this backend does not maintain a constraint catalog",
1002 ))
1003 }
1004
1005 fn drop_constraint(
1008 &mut self,
1009 _name: &str,
1010 _if_exists: bool,
1011 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1012 Err(DropConstraintError::Unsupported(
1013 "this backend does not maintain a constraint catalog",
1014 ))
1015 }
1016
1017 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1020 where
1021 Self: Sized,
1022 {
1023 if !self.contains_node(node_id) {
1024 return false;
1025 }
1026
1027 let existing_keys = match self.node_properties(node_id) {
1028 Some(props) => props.into_keys().collect::<Vec<_>>(),
1029 None => return false,
1030 };
1031
1032 for key in existing_keys {
1033 self.remove_node_property(node_id, &key);
1034 }
1035
1036 for (k, v) in properties {
1037 self.set_node_property(node_id, k, v);
1038 }
1039
1040 true
1041 }
1042
1043 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1044 if !self.contains_node(node_id) {
1045 return false;
1046 }
1047
1048 for (k, v) in properties {
1049 self.set_node_property(node_id, k, v);
1050 }
1051
1052 true
1053 }
1054
1055 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1056 where
1057 Self: Sized,
1058 {
1059 if !self.contains_node(node_id) {
1060 return false;
1061 }
1062
1063 let current = match self.node_labels(node_id) {
1064 Some(labels) => labels,
1065 None => return false,
1066 };
1067
1068 for label in ¤t {
1069 self.remove_node_label(node_id, label);
1070 }
1071
1072 for label in &labels {
1073 self.add_node_label(node_id, label);
1074 }
1075
1076 true
1077 }
1078
1079 fn replace_relationship_properties(
1080 &mut self,
1081 rel_id: RelationshipId,
1082 properties: Properties,
1083 ) -> bool
1084 where
1085 Self: Sized,
1086 {
1087 if !self.contains_relationship(rel_id) {
1088 return false;
1089 }
1090
1091 let existing_keys = match self.relationship_properties(rel_id) {
1092 Some(props) => props.into_keys().collect::<Vec<_>>(),
1093 None => return false,
1094 };
1095
1096 for key in existing_keys {
1097 self.remove_relationship_property(rel_id, &key);
1098 }
1099
1100 for (k, v) in properties {
1101 self.set_relationship_property(rel_id, k, v);
1102 }
1103
1104 true
1105 }
1106
1107 fn merge_relationship_properties(
1108 &mut self,
1109 rel_id: RelationshipId,
1110 properties: Properties,
1111 ) -> bool {
1112 if !self.contains_relationship(rel_id) {
1113 return false;
1114 }
1115
1116 for (k, v) in properties {
1117 self.set_relationship_property(rel_id, k, v);
1118 }
1119
1120 true
1121 }
1122
1123 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1124 let rel_ids = self.relationship_ids_of(node_id, direction);
1125
1126 let mut deleted = 0;
1127 for rel_id in rel_ids {
1128 if self.delete_relationship(rel_id) {
1129 deleted += 1;
1130 }
1131 }
1132 deleted
1133 }
1134
1135 fn get_or_create_node(
1136 &mut self,
1137 labels: Vec<String>,
1138 match_key: &str,
1139 match_value: &PropertyValue,
1140 init_properties: Properties,
1141 ) -> NodeRecord
1142 where
1143 Self: Sized,
1144 {
1145 for label in &labels {
1146 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1147 if let Some(node) = matches.into_iter().next() {
1148 return node;
1149 }
1150 }
1151
1152 self.create_node(labels, init_properties)
1153 }
1154}