Skip to content

Commit b1a5f56

Browse files
committed
make sure we cannot add constant edge properties for layers that don't have updates for that edge
1 parent 0a9ba26 commit b1a5f56

File tree

3 files changed

+114
-26
lines changed

3 files changed

+114
-26
lines changed

raphtory/src/core/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ impl PartialOrd for Prop {
162162
}
163163

164164
impl Prop {
165-
pub fn map(vals: impl IntoIterator<Item = (impl Into<ArcStr>, Prop)>) -> Self {
166-
let h_map: FxHashMap<_, _> = vals.into_iter().map(|(k, v)| (k.into(), v)).collect();
165+
pub fn map(vals: impl IntoIterator<Item = (impl Into<ArcStr>, impl Into<Prop>)>) -> Self {
166+
let h_map: FxHashMap<_, _> = vals
167+
.into_iter()
168+
.map(|(k, v)| (k.into(), v.into()))
169+
.collect();
167170
Prop::Map(h_map.into())
168171
}
169172

raphtory/src/core/storage/raw_edges.rs

+18
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,19 @@ impl<'a> MutEdge<'a> {
232232
&mut self.guard.deletions[layer_id][self.i]
233233
}
234234

235+
fn has_layer(&self, layer_id: usize) -> bool {
236+
if let Some(additions) = self.guard.additions.get(layer_id) {
237+
if let Some(additions) = additions.get(self.i) {
238+
return !additions.is_empty();
239+
}
240+
}
241+
if let Some(deletions) = self.guard.deletions.get(layer_id) {
242+
if let Some(deletions) = deletions.get(self.i) {
243+
return !deletions.is_empty();
244+
}
245+
}
246+
false
247+
}
235248
pub fn additions_mut(&mut self, layer_id: usize) -> &mut TimeIndex<TimeIndexEntry> {
236249
if layer_id >= self.guard.additions.len() {
237250
self.guard
@@ -254,6 +267,11 @@ impl<'a> MutEdge<'a> {
254267

255268
&mut self.guard.props[layer_id][self.i]
256269
}
270+
271+
/// Get a mutable reference to the layer only if it already exists but don't create a new one
272+
pub fn get_layer_mut(&mut self, layer_id: usize) -> Option<&mut EdgeLayer> {
273+
self.has_layer(layer_id).then(|| self.layer_mut(layer_id))
274+
}
257275
}
258276

259277
#[derive(Debug)]

raphtory/src/db/api/storage/graph/storage_ops/prop_add.rs

+91-24
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,34 @@ use raphtory_api::core::{
66
use super::GraphStorage;
77
use crate::{
88
core::{entities::graph::tgraph::TemporalGraph, utils::errors::GraphError},
9-
db::api::mutation::internal::InternalPropertyAdditionOps,
9+
db::api::{
10+
mutation::internal::InternalPropertyAdditionOps,
11+
storage::graph::edges::edge_storage_ops::{EdgeStorageOps, MemEdge},
12+
},
1013
prelude::Prop,
1114
};
1215

16+
impl TemporalGraph {
17+
fn missing_layer_error(&self, edge: MemEdge, layer_id: usize) -> GraphError {
18+
let layer = self.get_layer_name(layer_id).to_string();
19+
let src = self
20+
.storage
21+
.get_node(edge.src())
22+
.get_entry()
23+
.node()
24+
.global_id
25+
.to_string();
26+
let dst = self
27+
.storage
28+
.get_node(edge.dst())
29+
.get_entry()
30+
.node()
31+
.global_id
32+
.to_string();
33+
GraphError::InvalidEdgeLayer { layer, src, dst }
34+
}
35+
}
36+
1337
impl InternalPropertyAdditionOps for TemporalGraph {
1438
fn internal_add_properties(
1539
&self,
@@ -87,24 +111,27 @@ impl InternalPropertyAdditionOps for TemporalGraph {
87111
props: &[(usize, Prop)],
88112
) -> Result<(), GraphError> {
89113
let mut edge = self.storage.get_edge_mut(eid);
90-
let mut edge = edge.as_mut();
91-
let edge_layer = edge.layer_mut(layer);
92-
for (prop_id, prop) in props {
93-
let prop = self.process_prop_value(prop);
94-
edge_layer
95-
.add_constant_prop(*prop_id, prop)
96-
.map_err(|err| {
97-
let name = self.edge_meta.get_prop_name(*prop_id, true);
98-
GraphError::ConstantPropertyMutationError {
99-
name,
100-
new: err.new_value.expect("new value exists"),
101-
old: err
102-
.previous_value
103-
.expect("previous value exists if set failed"),
104-
}
105-
})?;
114+
let mut edge_mut = edge.as_mut();
115+
if let Some(edge_layer) = edge_mut.get_layer_mut(layer) {
116+
for (prop_id, prop) in props {
117+
let prop = self.process_prop_value(prop);
118+
edge_layer
119+
.add_constant_prop(*prop_id, prop)
120+
.map_err(|err| {
121+
let name = self.edge_meta.get_prop_name(*prop_id, true);
122+
GraphError::ConstantPropertyMutationError {
123+
name,
124+
new: err.new_value.expect("new value exists"),
125+
old: err
126+
.previous_value
127+
.expect("previous value exists if set failed"),
128+
}
129+
})?;
130+
}
131+
Ok(())
132+
} else {
133+
Err(self.missing_layer_error(edge.as_ref(), layer))
106134
}
107-
Ok(())
108135
}
109136

110137
fn internal_update_constant_edge_properties(
@@ -114,13 +141,16 @@ impl InternalPropertyAdditionOps for TemporalGraph {
114141
props: &[(usize, Prop)],
115142
) -> Result<(), GraphError> {
116143
let mut edge = self.storage.get_edge_mut(eid);
117-
let mut edge = edge.as_mut();
118-
let edge_layer = edge.layer_mut(layer);
119-
for (prop_id, prop) in props {
120-
let prop = self.process_prop_value(prop);
121-
edge_layer.update_constant_prop(*prop_id, prop)?;
144+
let mut edge_mut = edge.as_mut();
145+
if let Some(edge_layer) = edge_mut.get_layer_mut(layer) {
146+
for (prop_id, prop) in props {
147+
let prop = self.process_prop_value(prop);
148+
edge_layer.update_constant_prop(*prop_id, prop)?;
149+
}
150+
Ok(())
151+
} else {
152+
Err(self.missing_layer_error(edge.as_ref(), layer))
122153
}
123-
Ok(())
124154
}
125155
}
126156

@@ -233,4 +263,41 @@ mod test {
233263
);
234264
});
235265
}
266+
267+
#[test]
268+
fn test_constant_edge_prop_updates_multiple_layers() {
269+
let graph = Graph::new();
270+
graph.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
271+
let edge = graph.edge(1, 2).unwrap();
272+
// check that it is not possible to add constant properties for layers that do not have updates
273+
assert!(edge
274+
.add_constant_properties([("test", "test")], None)
275+
.is_err());
276+
assert!(edge
277+
.add_constant_properties([("test", "test")], Some("2"))
278+
.is_err());
279+
assert!(edge
280+
.update_constant_properties([("test", "test")], None)
281+
.is_err());
282+
assert!(edge
283+
.update_constant_properties([("test", "test")], Some("2"))
284+
.is_err());
285+
286+
// make sure we didn't accidentally create a new layer in the failed updates
287+
assert!(graph.layers("2").is_err());
288+
289+
// make sure constant property updates for existing layers work
290+
edge.add_constant_properties([("test", "test")], Some("1"))
291+
.unwrap();
292+
assert_eq!(
293+
edge.properties().constant().get("test"),
294+
Some(Prop::map([("1", "test")]))
295+
);
296+
edge.update_constant_properties([("test", "test2")], Some("1"))
297+
.unwrap();
298+
assert_eq!(
299+
edge.properties().constant().get("test"),
300+
Some(Prop::map([("1", "test2")]))
301+
);
302+
}
236303
}

0 commit comments

Comments
 (0)