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 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 vector_search(
610 &self,
611 _name: &str,
612 _query: &LoraVector,
613 _k: usize,
614 _restrict_to: Option<&std::collections::BTreeSet<u64>>,
615 ) -> Vec<(u64, f64)> {
616 Vec::new()
617 }
618
619 fn list_constraints(&self) -> Vec<ConstraintDefinition> {
622 Vec::new()
623 }
624
625 fn get_constraint(&self, _name: &str) -> Option<ConstraintDefinition> {
626 None
627 }
628
629 fn check_node_create_against_constraints(
635 &self,
636 _labels: &[String],
637 _properties: &Properties,
638 ) -> Result<(), String> {
639 Ok(())
640 }
641
642 fn check_relationship_create_against_constraints(
644 &self,
645 _rel_type: &str,
646 _properties: &Properties,
647 ) -> Result<(), String> {
648 Ok(())
649 }
650
651 fn check_node_set_property_against_constraints(
654 &self,
655 _node_id: NodeId,
656 _key: &str,
657 _value: &PropertyValue,
658 ) -> Result<(), String> {
659 Ok(())
660 }
661
662 fn check_node_remove_property_against_constraints(
665 &self,
666 _node_id: NodeId,
667 _key: &str,
668 ) -> Result<(), String> {
669 Ok(())
670 }
671
672 fn check_node_replace_properties_against_constraints(
676 &self,
677 _node_id: NodeId,
678 _properties: &Properties,
679 ) -> Result<(), String> {
680 Ok(())
681 }
682
683 fn check_relationship_set_property_against_constraints(
686 &self,
687 _rel_id: RelationshipId,
688 _key: &str,
689 _value: &PropertyValue,
690 ) -> Result<(), String> {
691 Ok(())
692 }
693
694 fn check_relationship_remove_property_against_constraints(
695 &self,
696 _rel_id: RelationshipId,
697 _key: &str,
698 ) -> Result<(), String> {
699 Ok(())
700 }
701
702 fn check_relationship_replace_properties_against_constraints(
706 &self,
707 _rel_id: RelationshipId,
708 _properties: &Properties,
709 ) -> Result<(), String> {
710 Ok(())
711 }
712
713 fn check_node_add_label_against_constraints(
716 &self,
717 _node_id: NodeId,
718 _label: &str,
719 ) -> Result<(), String> {
720 Ok(())
721 }
722
723 fn graph_stats(&self) -> GraphStats {
727 GraphStats::default()
728 }
729
730 fn node_text_candidates(
739 &self,
740 _label: &str,
741 _property: &str,
742 _query: &str,
743 ) -> Option<Vec<NodeId>> {
744 None
745 }
746
747 fn node_range_candidates(
753 &self,
754 _label: &str,
755 _property: &str,
756 _lo: Option<&PropertyValue>,
757 _hi: Option<&PropertyValue>,
758 ) -> Option<Vec<NodeId>> {
759 None
760 }
761
762 fn node_point_within_bbox(
767 &self,
768 _label: &str,
769 _property: &str,
770 _ll: (f64, f64),
771 _ur: (f64, f64),
772 ) -> Option<Vec<NodeId>> {
773 None
774 }
775
776 fn node_point_within_distance(
780 &self,
781 _label: &str,
782 _property: &str,
783 _center: (f64, f64),
784 _max_distance: f64,
785 ) -> Option<Vec<NodeId>> {
786 None
787 }
788
789 fn relationship_text_candidates(
793 &self,
794 _rel_type: &str,
795 _property: &str,
796 _query: &str,
797 ) -> Option<Vec<RelationshipId>> {
798 None
799 }
800
801 fn relationship_range_candidates(
804 &self,
805 _rel_type: &str,
806 _property: &str,
807 _lo: Option<&PropertyValue>,
808 _hi: Option<&PropertyValue>,
809 ) -> Option<Vec<RelationshipId>> {
810 None
811 }
812
813 fn relationship_point_within_bbox(
817 &self,
818 _rel_type: &str,
819 _property: &str,
820 _ll: (f64, f64),
821 _ur: (f64, f64),
822 ) -> Option<Vec<RelationshipId>> {
823 None
824 }
825
826 fn relationship_point_within_distance(
830 &self,
831 _rel_type: &str,
832 _property: &str,
833 _center: (f64, f64),
834 _max_distance: f64,
835 ) -> Option<Vec<RelationshipId>> {
836 None
837 }
838}
839
840pub trait GraphCatalog {
848 fn node_count(&self) -> usize;
849 fn relationship_count(&self) -> usize;
850 fn has_label_name(&self, label: &str) -> bool;
851 fn has_relationship_type_name(&self, rel_type: &str) -> bool;
852 fn has_property_key(&self, key: &str) -> bool;
853}
854
855impl<T: GraphStorage> GraphCatalog for T {
856 fn node_count(&self) -> usize {
857 GraphStorage::node_count(self)
858 }
859 fn relationship_count(&self) -> usize {
860 GraphStorage::relationship_count(self)
861 }
862 fn has_label_name(&self, label: &str) -> bool {
863 GraphStorage::has_label_name(self, label)
864 }
865 fn has_relationship_type_name(&self, rel_type: &str) -> bool {
866 GraphStorage::has_relationship_type_name(self, rel_type)
867 }
868 fn has_property_key(&self, key: &str) -> bool {
869 GraphStorage::has_property_key(self, key)
870 }
871}
872
873pub trait BorrowedGraphStorage: GraphStorage {
884 fn node_ref(&self, id: NodeId) -> Option<&NodeRecord>;
885 fn relationship_ref(&self, id: RelationshipId) -> Option<&RelationshipRecord>;
886
887 fn node_refs(&self) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
888 Box::new(
889 self.all_node_ids()
890 .into_iter()
891 .filter_map(|id| self.node_ref(id)),
892 )
893 }
894
895 fn node_refs_by_label(&self, label: &str) -> Box<dyn Iterator<Item = &NodeRecord> + '_> {
896 Box::new(
897 self.node_ids_by_label(label)
898 .into_iter()
899 .filter_map(|id| self.node_ref(id)),
900 )
901 }
902
903 fn relationship_refs(&self) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
904 Box::new(
905 self.all_rel_ids()
906 .into_iter()
907 .filter_map(|id| self.relationship_ref(id)),
908 )
909 }
910
911 fn relationship_refs_by_type(
912 &self,
913 rel_type: &str,
914 ) -> Box<dyn Iterator<Item = &RelationshipRecord> + '_> {
915 Box::new(
916 self.rel_ids_by_type(rel_type)
917 .into_iter()
918 .filter_map(|id| self.relationship_ref(id)),
919 )
920 }
921}
922
923pub trait GraphStorageMut: GraphStorage {
933 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord;
936
937 fn create_relationship(
938 &mut self,
939 src: NodeId,
940 dst: NodeId,
941 rel_type: &str,
942 properties: Properties,
943 ) -> Option<RelationshipRecord>;
944
945 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
948
949 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
950
951 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
952 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
953
954 fn set_relationship_property(
957 &mut self,
958 rel_id: RelationshipId,
959 key: String,
960 value: PropertyValue,
961 ) -> bool;
962
963 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
964
965 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
968
969 fn delete_node(&mut self, node_id: NodeId) -> bool;
971
972 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
974
975 fn clear(&mut self);
984
985 #[allow(clippy::result_large_err)]
992 fn create_index(
993 &mut self,
994 _request: IndexRequest,
995 _if_not_exists: bool,
996 ) -> Result<CreateIndexOutcome, CreateIndexError> {
997 Err(CreateIndexError::Unsupported(
998 "this backend does not maintain an index catalog",
999 ))
1000 }
1001
1002 fn drop_index(
1007 &mut self,
1008 _name: &str,
1009 _if_exists: bool,
1010 ) -> Result<DropIndexOutcome, DropIndexError> {
1011 Err(DropIndexError::Unsupported(
1012 "this backend does not maintain an index catalog",
1013 ))
1014 }
1015
1016 fn create_constraint(
1021 &mut self,
1022 _request: ConstraintRequest,
1023 _if_not_exists: bool,
1024 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1025 Err(CreateConstraintError::Unsupported(
1026 "this backend does not maintain a constraint catalog",
1027 ))
1028 }
1029
1030 fn drop_constraint(
1033 &mut self,
1034 _name: &str,
1035 _if_exists: bool,
1036 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1037 Err(DropConstraintError::Unsupported(
1038 "this backend does not maintain a constraint catalog",
1039 ))
1040 }
1041
1042 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1045 where
1046 Self: Sized,
1047 {
1048 if !self.contains_node(node_id) {
1049 return false;
1050 }
1051
1052 let existing_keys = match self.node_properties(node_id) {
1053 Some(props) => props.into_keys().collect::<Vec<_>>(),
1054 None => return false,
1055 };
1056
1057 for key in existing_keys {
1058 self.remove_node_property(node_id, &key);
1059 }
1060
1061 for (k, v) in properties {
1062 self.set_node_property(node_id, k, v);
1063 }
1064
1065 true
1066 }
1067
1068 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1069 if !self.contains_node(node_id) {
1070 return false;
1071 }
1072
1073 for (k, v) in properties {
1074 self.set_node_property(node_id, k, v);
1075 }
1076
1077 true
1078 }
1079
1080 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1081 where
1082 Self: Sized,
1083 {
1084 if !self.contains_node(node_id) {
1085 return false;
1086 }
1087
1088 let current = match self.node_labels(node_id) {
1089 Some(labels) => labels,
1090 None => return false,
1091 };
1092
1093 for label in ¤t {
1094 self.remove_node_label(node_id, label);
1095 }
1096
1097 for label in &labels {
1098 self.add_node_label(node_id, label);
1099 }
1100
1101 true
1102 }
1103
1104 fn replace_relationship_properties(
1105 &mut self,
1106 rel_id: RelationshipId,
1107 properties: Properties,
1108 ) -> bool
1109 where
1110 Self: Sized,
1111 {
1112 if !self.contains_relationship(rel_id) {
1113 return false;
1114 }
1115
1116 let existing_keys = match self.relationship_properties(rel_id) {
1117 Some(props) => props.into_keys().collect::<Vec<_>>(),
1118 None => return false,
1119 };
1120
1121 for key in existing_keys {
1122 self.remove_relationship_property(rel_id, &key);
1123 }
1124
1125 for (k, v) in properties {
1126 self.set_relationship_property(rel_id, k, v);
1127 }
1128
1129 true
1130 }
1131
1132 fn merge_relationship_properties(
1133 &mut self,
1134 rel_id: RelationshipId,
1135 properties: Properties,
1136 ) -> bool {
1137 if !self.contains_relationship(rel_id) {
1138 return false;
1139 }
1140
1141 for (k, v) in properties {
1142 self.set_relationship_property(rel_id, k, v);
1143 }
1144
1145 true
1146 }
1147
1148 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1149 let rel_ids = self.relationship_ids_of(node_id, direction);
1150
1151 let mut deleted = 0;
1152 for rel_id in rel_ids {
1153 if self.delete_relationship(rel_id) {
1154 deleted += 1;
1155 }
1156 }
1157 deleted
1158 }
1159
1160 fn get_or_create_node(
1161 &mut self,
1162 labels: Vec<String>,
1163 match_key: &str,
1164 match_value: &PropertyValue,
1165 init_properties: Properties,
1166 ) -> NodeRecord
1167 where
1168 Self: Sized,
1169 {
1170 for label in &labels {
1171 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1172 if let Some(node) = matches.into_iter().next() {
1173 return node;
1174 }
1175 }
1176
1177 self.create_node(labels, init_properties)
1178 }
1179}