1use crate::types::{Label, NodeId, Properties, PropertyValue};
4use bincode::{Decode, Encode};
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use uuid::Uuid;
8
9#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
10pub struct Node {
11 pub id: NodeId,
12 pub labels: Vec<Label>,
13 pub properties: Properties,
14}
15
16impl Node {
17 pub fn new(id: NodeId, labels: Vec<Label>, properties: Properties) -> Self {
18 Self {
19 id,
20 labels,
21 properties,
22 }
23 }
24
25 pub fn has_label(&self, label_name: &str) -> bool {
27 self.labels.iter().any(|l| l.name == label_name)
28 }
29
30 pub fn get_property(&self, key: &str) -> Option<&PropertyValue> {
32 self.properties.get(key)
33 }
34
35 pub fn set_property(&mut self, key: impl Into<String>, value: PropertyValue) {
37 self.properties.insert(key.into(), value);
38 }
39
40 pub fn add_label(&mut self, label: impl Into<String>) {
42 self.labels.push(Label::new(label));
43 }
44
45 pub fn remove_label(&mut self, label_name: &str) -> bool {
47 let len_before = self.labels.len();
48 self.labels.retain(|l| l.name != label_name);
49 self.labels.len() < len_before
50 }
51}
52
53#[derive(Debug, Clone, Default)]
55pub struct NodeBuilder {
56 id: Option<NodeId>,
57 labels: Vec<Label>,
58 properties: Properties,
59}
60
61impl NodeBuilder {
62 pub fn new() -> Self {
64 Self::default()
65 }
66
67 pub fn id(mut self, id: impl Into<String>) -> Self {
69 self.id = Some(id.into());
70 self
71 }
72
73 pub fn label(mut self, label: impl Into<String>) -> Self {
75 self.labels.push(Label::new(label));
76 self
77 }
78
79 pub fn labels(mut self, labels: impl IntoIterator<Item = impl Into<String>>) -> Self {
81 for label in labels {
82 self.labels.push(Label::new(label));
83 }
84 self
85 }
86
87 pub fn property<V: Into<PropertyValue>>(mut self, key: impl Into<String>, value: V) -> Self {
89 self.properties.insert(key.into(), value.into());
90 self
91 }
92
93 pub fn properties(mut self, props: Properties) -> Self {
95 self.properties.extend(props);
96 self
97 }
98
99 pub fn build(self) -> Node {
101 Node {
102 id: self.id.unwrap_or_else(|| Uuid::new_v4().to_string()),
103 labels: self.labels,
104 properties: self.properties,
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_node_builder() {
115 let node = NodeBuilder::new()
116 .label("Person")
117 .property("name", "Alice")
118 .property("age", 30i64)
119 .build();
120
121 assert!(node.has_label("Person"));
122 assert!(!node.has_label("Organization"));
123 assert_eq!(
124 node.get_property("name"),
125 Some(&PropertyValue::String("Alice".to_string()))
126 );
127 }
128
129 #[test]
130 fn test_node_has_label() {
131 let node = NodeBuilder::new().label("Person").label("Employee").build();
132
133 assert!(node.has_label("Person"));
134 assert!(node.has_label("Employee"));
135 assert!(!node.has_label("Company"));
136 }
137
138 #[test]
139 fn test_node_modify_labels() {
140 let mut node = NodeBuilder::new().label("Person").build();
141
142 node.add_label("Employee");
143 assert!(node.has_label("Employee"));
144
145 let removed = node.remove_label("Person");
146 assert!(removed);
147 assert!(!node.has_label("Person"));
148 }
149}