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.to_string());
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.to_string());
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.to_string());
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.to_string());
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 try_create_node(
936 &mut self,
937 labels: Vec<String>,
938 properties: Properties,
939 ) -> Option<NodeRecord>;
940
941 fn create_node(&mut self, labels: Vec<String>, properties: Properties) -> NodeRecord
946 where
947 Self: Sized,
948 {
949 self.try_create_node(labels, properties)
950 .unwrap_or_else(|| NodeRecord {
951 id: NodeId::MAX,
952 labels: Vec::new(),
953 properties: Properties::new(),
954 })
955 }
956
957 fn create_relationship(
958 &mut self,
959 src: NodeId,
960 dst: NodeId,
961 rel_type: &str,
962 properties: Properties,
963 ) -> Option<RelationshipRecord>;
964
965 fn set_node_property(&mut self, node_id: NodeId, key: String, value: PropertyValue) -> bool;
968
969 fn remove_node_property(&mut self, node_id: NodeId, key: &str) -> bool;
970
971 fn add_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
972 fn remove_node_label(&mut self, node_id: NodeId, label: &str) -> bool;
973
974 fn set_relationship_property(
977 &mut self,
978 rel_id: RelationshipId,
979 key: String,
980 value: PropertyValue,
981 ) -> bool;
982
983 fn remove_relationship_property(&mut self, rel_id: RelationshipId, key: &str) -> bool;
984
985 fn delete_relationship(&mut self, rel_id: RelationshipId) -> bool;
988
989 fn delete_node(&mut self, node_id: NodeId) -> bool;
991
992 fn detach_delete_node(&mut self, node_id: NodeId) -> bool;
994
995 fn clear(&mut self);
1004
1005 #[allow(clippy::result_large_err)]
1012 fn create_index(
1013 &mut self,
1014 _request: IndexRequest,
1015 _if_not_exists: bool,
1016 ) -> Result<CreateIndexOutcome, CreateIndexError> {
1017 Err(CreateIndexError::Unsupported(
1018 "this backend does not maintain an index catalog",
1019 ))
1020 }
1021
1022 fn drop_index(
1027 &mut self,
1028 _name: &str,
1029 _if_exists: bool,
1030 ) -> Result<DropIndexOutcome, DropIndexError> {
1031 Err(DropIndexError::Unsupported(
1032 "this backend does not maintain an index catalog",
1033 ))
1034 }
1035
1036 fn create_constraint(
1041 &mut self,
1042 _request: ConstraintRequest,
1043 _if_not_exists: bool,
1044 ) -> Result<CreateConstraintOutcome, CreateConstraintError> {
1045 Err(CreateConstraintError::Unsupported(
1046 "this backend does not maintain a constraint catalog",
1047 ))
1048 }
1049
1050 fn drop_constraint(
1053 &mut self,
1054 _name: &str,
1055 _if_exists: bool,
1056 ) -> Result<DropConstraintOutcome, DropConstraintError> {
1057 Err(DropConstraintError::Unsupported(
1058 "this backend does not maintain a constraint catalog",
1059 ))
1060 }
1061
1062 fn replace_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool
1065 where
1066 Self: Sized,
1067 {
1068 if !self.contains_node(node_id) {
1069 return false;
1070 }
1071
1072 let existing_keys = match self.node_properties(node_id) {
1073 Some(props) => props.into_keys().collect::<Vec<_>>(),
1074 None => return false,
1075 };
1076
1077 for key in existing_keys {
1078 self.remove_node_property(node_id, &key);
1079 }
1080
1081 for (k, v) in properties {
1082 self.set_node_property(node_id, k.to_string(), v);
1083 }
1084
1085 true
1086 }
1087
1088 fn merge_node_properties(&mut self, node_id: NodeId, properties: Properties) -> bool {
1089 if !self.contains_node(node_id) {
1090 return false;
1091 }
1092
1093 for (k, v) in properties {
1094 self.set_node_property(node_id, k.to_string(), v);
1095 }
1096
1097 true
1098 }
1099
1100 fn set_node_labels(&mut self, node_id: NodeId, labels: Vec<String>) -> bool
1101 where
1102 Self: Sized,
1103 {
1104 if !self.contains_node(node_id) {
1105 return false;
1106 }
1107
1108 let current = match self.node_labels(node_id) {
1109 Some(labels) => labels,
1110 None => return false,
1111 };
1112
1113 for label in ¤t {
1114 self.remove_node_label(node_id, label);
1115 }
1116
1117 for label in &labels {
1118 self.add_node_label(node_id, label);
1119 }
1120
1121 true
1122 }
1123
1124 fn replace_relationship_properties(
1125 &mut self,
1126 rel_id: RelationshipId,
1127 properties: Properties,
1128 ) -> bool
1129 where
1130 Self: Sized,
1131 {
1132 if !self.contains_relationship(rel_id) {
1133 return false;
1134 }
1135
1136 let existing_keys = match self.relationship_properties(rel_id) {
1137 Some(props) => props.into_keys().collect::<Vec<_>>(),
1138 None => return false,
1139 };
1140
1141 for key in existing_keys {
1142 self.remove_relationship_property(rel_id, &key);
1143 }
1144
1145 for (k, v) in properties {
1146 self.set_relationship_property(rel_id, k.to_string(), v);
1147 }
1148
1149 true
1150 }
1151
1152 fn merge_relationship_properties(
1153 &mut self,
1154 rel_id: RelationshipId,
1155 properties: Properties,
1156 ) -> bool {
1157 if !self.contains_relationship(rel_id) {
1158 return false;
1159 }
1160
1161 for (k, v) in properties {
1162 self.set_relationship_property(rel_id, k.to_string(), v);
1163 }
1164
1165 true
1166 }
1167
1168 fn delete_relationships_of(&mut self, node_id: NodeId, direction: Direction) -> usize {
1169 let rel_ids = self.relationship_ids_of(node_id, direction);
1170
1171 let mut deleted = 0;
1172 for rel_id in rel_ids {
1173 if self.delete_relationship(rel_id) {
1174 deleted += 1;
1175 }
1176 }
1177 deleted
1178 }
1179
1180 fn get_or_create_node(
1181 &mut self,
1182 labels: Vec<String>,
1183 match_key: &str,
1184 match_value: &PropertyValue,
1185 init_properties: Properties,
1186 ) -> NodeRecord
1187 where
1188 Self: Sized,
1189 {
1190 for label in &labels {
1191 let matches = self.find_nodes_by_property(Some(label), match_key, match_value);
1192 if let Some(node) = matches.into_iter().next() {
1193 return node;
1194 }
1195 }
1196
1197 self.create_node(labels, init_properties)
1198 }
1199}