helix_db/utils/
items.rs

1//! Node and Edge types for the graph.
2//!
3//! Nodes are the main entities in the graph and edges are the connections between them.
4//!
5//! Nodes and edges are serialised without enum variant names in JSON format.
6
7use crate::protocol::value::Value;
8use crate::helix_engine::types::GraphError;
9use sonic_rs::{Deserialize, Serialize};
10use std::{cmp::Ordering, collections::HashMap};
11
12/// A node in the graph containing an ID, label, and property map.
13/// Properties are serialised without enum variant names in JSON format.
14#[derive(Clone, Serialize, Deserialize, PartialEq)]
15pub struct Node {
16    /// The ID of the node.
17    ///
18    /// This is not serialized when stored as it is the key.
19    #[serde(skip)]
20    pub id: u128,
21    /// The label of the node.
22    pub label: String,
23    /// The properties of the node.
24    ///
25    /// Properties are optional and can be None.
26    /// Properties are serialised without enum variant names in JSON format.
27    #[serde(default)]
28    pub properties: Option<HashMap<String, Value>>,
29}
30
31impl Node {
32    /// The number of properties in a node.
33    ///
34    /// This is used as a constant in the return value mixin methods.
35    pub const NUM_PROPERTIES: usize = 2;
36
37    /// Decodes a node from a byte slice.
38    ///
39    /// Takes ID as the ID is not serialized when stored as it is the key.
40    /// Uses the known ID (either from the query or the key in an LMDB iterator) to construct a new node.
41    pub fn decode_node(bytes: &[u8], id: u128) -> Result<Node, GraphError> {
42        match bincode::deserialize::<Node>(bytes) {
43            Ok(node) => Ok(Node {
44                id,
45                label: node.label,
46                properties: node.properties,
47            }),
48            Err(e) => Err(GraphError::ConversionError(format!(
49                "Error deserializing node: {}",
50                e
51            ))),
52        }
53    }
54
55    /// Encodes a node into a byte slice
56    ///
57    /// This skips the ID and if the properties are None, it skips the properties.
58    pub fn encode_node(&self) -> Result<Vec<u8>, GraphError> {
59        bincode::serialize(&self)
60            .map_err(|e| GraphError::ConversionError(format!("Error serializing node: {}", e)))
61    }
62}
63
64// Core trait implementations for Node
65impl std::fmt::Display for Node {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        write!(
68            f,
69            "{{ id: {}, label: {}, properties: {:?} }}",
70            uuid::Uuid::from_u128(self.id).to_string(),
71            self.label,
72            self.properties
73        )
74    }
75}
76impl std::fmt::Debug for Node {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        write!(
79            f,
80            "{{ \nid:{},\nlabel:{},\nproperties:{:#?} }}",
81            uuid::Uuid::from_u128(self.id).to_string(),
82            self.label,
83            self.properties
84        )
85    }
86}
87impl Eq for Node {}
88impl Ord for Node {
89    fn cmp(&self, other: &Self) -> Ordering {
90        self.id.cmp(&other.id)
91    }
92}
93impl PartialOrd for Node {
94    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
95        Some(self.cmp(other))
96    }
97}
98
99/// An edge in the graph connecting two nodes with an ID, label, and property map.
100/// Properties are serialised without enum variant names in JSON format.
101#[derive(Serialize, Deserialize, Clone, PartialEq)]
102pub struct Edge {
103    /// The ID of the edge.
104    ///
105    /// This is not serialized when stored as it is the key.
106    #[serde(skip)]
107    pub id: u128,
108    /// The label of the edge.
109    pub label: String,
110    /// The ID of the from node.
111    pub from_node: u128,
112    /// The ID of the to node.
113    pub to_node: u128,
114    /// The properties of the edge.
115    ///
116    /// Properties are optional and can be None.
117    /// Properties are serialised without enum variant names in JSON format.
118    #[serde(default)]
119    pub properties: Option<HashMap<String, Value>>,
120}
121
122impl Edge {
123    /// The number of properties in an edge.
124    ///
125    /// This is used as a constant in the return value mixin methods.
126    pub const NUM_PROPERTIES: usize = 4;
127
128    /// Decodes an edge from a byte slice.
129    ///
130    /// Takes ID as the ID is not serialized when stored as it is the key.
131    /// Uses the known ID (either from the query or the key in an LMDB iterator) to construct a new edge.
132    pub fn decode_edge(bytes: &[u8], id: u128) -> Result<Edge, GraphError> {
133        match bincode::deserialize::<Edge>(bytes) {
134            Ok(edge) => Ok(Edge {
135                id,
136                label: edge.label,
137                from_node: edge.from_node,
138                to_node: edge.to_node,
139                properties: edge.properties,
140            }),
141            Err(e) => Err(GraphError::ConversionError(format!(
142                "Error deserializing edge: {}",
143                e
144            ))),
145        }
146    }
147
148    /// Encodes an edge into a byte slice
149    ///
150    /// This skips the ID and if the properties are None, it skips the properties.
151    pub fn encode_edge(&self) -> Result<Vec<u8>, GraphError> {
152        bincode::serialize(self)
153            .map_err(|e| GraphError::ConversionError(format!("Error serializing edge: {}", e)))
154    }
155}
156
157
158// Core trait implementations for Edge
159impl std::fmt::Display for Edge {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        write!(
162            f,
163            "{{ id: {}, label: {}, from_node: {}, to_node: {}, properties: {:?} }}",
164            uuid::Uuid::from_u128(self.id).to_string(),
165            self.label,
166            uuid::Uuid::from_u128(self.from_node).to_string(),
167            uuid::Uuid::from_u128(self.to_node).to_string(),
168            self.properties
169        )
170    }
171}
172impl std::fmt::Debug for Edge {
173    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174        write!(
175            f,
176            "{{ \nid: {},\nlabel: {},\nfrom_node: {},\nto_node: {},\nproperties: {:#?} }}",
177            uuid::Uuid::from_u128(self.id).to_string(),
178            self.label,
179            uuid::Uuid::from_u128(self.from_node).to_string(),
180            uuid::Uuid::from_u128(self.to_node).to_string(),
181            self.properties
182        )
183    }
184}
185impl Eq for Edge {}
186impl Ord for Edge {
187    fn cmp(&self, other: &Self) -> Ordering {
188        self.id.cmp(&other.id)
189    }
190}
191impl PartialOrd for Edge {
192    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
193        Some(self.cmp(other))
194    }
195}
196
197