1use hashbrown::HashMap;
2use smol_str::SmolStr;
3
4use crate::node_key::NodeKey;
5use crate::value::DeltaValue;
6
7#[derive(Clone, Debug, PartialEq)]
13pub enum GraphDelta {
14 UpsertNode {
17 key: NodeKey,
18 labels: Vec<SmolStr>,
19 props: HashMap<SmolStr, DeltaValue>,
20 },
21
22 UpsertEdge {
24 src: NodeKey,
25 rel_type: SmolStr,
26 dst: NodeKey,
27 props: HashMap<SmolStr, DeltaValue>,
28 },
29
30 DeleteNode { key: NodeKey },
32
33 DeleteEdge {
35 src: NodeKey,
36 rel_type: SmolStr,
37 dst: NodeKey,
38 },
39}
40
41impl GraphDelta {
42 pub fn is_node_op(&self) -> bool {
43 matches!(self, Self::UpsertNode { .. } | Self::DeleteNode { .. })
44 }
45
46 pub fn is_edge_op(&self) -> bool {
47 matches!(self, Self::UpsertEdge { .. } | Self::DeleteEdge { .. })
48 }
49
50 pub fn is_delete(&self) -> bool {
51 matches!(self, Self::DeleteNode { .. } | Self::DeleteEdge { .. })
52 }
53
54 pub fn is_upsert(&self) -> bool {
55 matches!(self, Self::UpsertNode { .. } | Self::UpsertEdge { .. })
56 }
57
58 pub fn primary_key(&self) -> &NodeKey {
61 match self {
62 Self::UpsertNode { key, .. } | Self::DeleteNode { key } => key,
63 Self::UpsertEdge { src, .. } | Self::DeleteEdge { src, .. } => src,
64 }
65 }
66
67 pub fn referenced_keys(&self) -> Vec<&NodeKey> {
69 match self {
70 Self::UpsertNode { key, .. } | Self::DeleteNode { key } => vec![key],
71 Self::UpsertEdge { src, dst, .. } | Self::DeleteEdge { src, dst, .. } => {
72 vec![src, dst]
73 }
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 fn sample_upsert_node() -> GraphDelta {
83 GraphDelta::UpsertNode {
84 key: NodeKey::new("Function", "main"),
85 labels: vec![],
86 props: HashMap::new(),
87 }
88 }
89
90 fn sample_upsert_edge() -> GraphDelta {
91 GraphDelta::UpsertEdge {
92 src: NodeKey::new("Function", "main"),
93 rel_type: SmolStr::new("calls"),
94 dst: NodeKey::new("Function", "helper"),
95 props: HashMap::new(),
96 }
97 }
98
99 fn sample_delete_node() -> GraphDelta {
100 GraphDelta::DeleteNode {
101 key: NodeKey::new("Function", "old"),
102 }
103 }
104
105 fn sample_delete_edge() -> GraphDelta {
106 GraphDelta::DeleteEdge {
107 src: NodeKey::new("Function", "main"),
108 rel_type: SmolStr::new("calls"),
109 dst: NodeKey::new("Function", "removed"),
110 }
111 }
112
113 #[test]
114 fn upsert_node_is_node_op() {
115 assert!(sample_upsert_node().is_node_op());
116 assert!(!sample_upsert_node().is_edge_op());
117 }
118
119 #[test]
120 fn upsert_edge_is_edge_op() {
121 assert!(sample_upsert_edge().is_edge_op());
122 assert!(!sample_upsert_edge().is_node_op());
123 }
124
125 #[test]
126 fn delete_node_is_delete() {
127 assert!(sample_delete_node().is_delete());
128 assert!(!sample_delete_node().is_upsert());
129 }
130
131 #[test]
132 fn delete_edge_is_delete() {
133 assert!(sample_delete_edge().is_delete());
134 assert!(!sample_delete_edge().is_upsert());
135 }
136
137 #[test]
138 fn upsert_is_not_delete() {
139 assert!(sample_upsert_node().is_upsert());
140 assert!(!sample_upsert_node().is_delete());
141 }
142
143 #[test]
144 fn primary_key_for_node() {
145 let d = sample_upsert_node();
146 assert_eq!(d.primary_key().label, "Function");
147 assert_eq!(d.primary_key().primary_key, "main");
148 }
149
150 #[test]
151 fn primary_key_for_edge_is_src() {
152 let d = sample_upsert_edge();
153 assert_eq!(d.primary_key().label, "Function");
154 assert_eq!(d.primary_key().primary_key, "main");
155 }
156
157 #[test]
158 fn referenced_keys_node() {
159 let d = sample_upsert_node();
160 assert_eq!(d.referenced_keys().len(), 1);
161 }
162
163 #[test]
164 fn referenced_keys_edge() {
165 let d = sample_upsert_edge();
166 let keys = d.referenced_keys();
167 assert_eq!(keys.len(), 2);
168 assert_eq!(keys[0].primary_key, "main");
169 assert_eq!(keys[1].primary_key, "helper");
170 }
171
172 #[test]
173 fn clone_and_eq() {
174 let a = sample_upsert_node();
175 let b = a.clone();
176 assert_eq!(a, b);
177 }
178}