use crate::types::*;
use std::collections::HashMap;
impl DeltaState {
pub fn new() -> Self {
Self::default()
}
pub fn add_edge(&mut self, src: NodeId, etype: ETypeId, dst: NodeId) {
let patch = EdgePatch { etype, other: dst };
if let Some(del_set) = self.out_del.get_mut(&src) {
if del_set.remove(&patch) {
if del_set.is_empty() {
self.out_del.remove(&src);
}
} else {
self.out_add.entry(src).or_default().insert(patch);
}
} else {
self.out_add.entry(src).or_default().insert(patch);
}
let in_patch = EdgePatch { etype, other: src };
if let Some(del_set) = self.in_del.get_mut(&dst) {
if del_set.remove(&in_patch) {
if del_set.is_empty() {
self.in_del.remove(&dst);
}
} else {
self.in_add.entry(dst).or_default().insert(in_patch);
}
} else {
self.in_add.entry(dst).or_default().insert(in_patch);
}
self
.incoming_edge_sources
.entry(dst)
.or_default()
.insert(src);
}
pub fn delete_edge(&mut self, src: NodeId, etype: ETypeId, dst: NodeId) {
let patch = EdgePatch { etype, other: dst };
if let Some(add_set) = self.out_add.get_mut(&src) {
if add_set.remove(&patch) {
if add_set.is_empty() {
self.out_add.remove(&src);
}
if let Some(in_add_set) = self.in_add.get_mut(&dst) {
let in_patch = EdgePatch { etype, other: src };
in_add_set.remove(&in_patch);
if in_add_set.is_empty() {
self.in_add.remove(&dst);
}
}
return;
}
}
self.out_del.entry(src).or_default().insert(patch);
let in_patch = EdgePatch { etype, other: src };
self.in_del.entry(dst).or_default().insert(in_patch);
}
pub fn is_edge_deleted(&self, src: NodeId, etype: ETypeId, dst: NodeId) -> bool {
self
.out_del
.get(&src)
.map(|s| s.contains(&EdgePatch { etype, other: dst }))
.unwrap_or(false)
}
pub fn is_edge_added(&self, src: NodeId, etype: ETypeId, dst: NodeId) -> bool {
self
.out_add
.get(&src)
.map(|s| s.contains(&EdgePatch { etype, other: dst }))
.unwrap_or(false)
}
pub fn clear(&mut self) {
self.created_nodes.clear();
self.deleted_nodes.clear();
self.modified_nodes.clear();
self.out_add.clear();
self.out_del.clear();
self.in_add.clear();
self.in_del.clear();
self.edge_props.clear();
self.new_labels.clear();
self.new_etypes.clear();
self.new_propkeys.clear();
self.key_index.clear();
self.key_index_deleted.clear();
self.incoming_edge_sources.clear();
self.pending_vectors.clear();
}
pub fn edges_added_count(&self, src: NodeId) -> usize {
self.out_add.get(&src).map(|s| s.len()).unwrap_or(0)
}
pub fn edges_deleted_count(&self, src: NodeId) -> usize {
self.out_del.get(&src).map(|s| s.len()).unwrap_or(0)
}
pub fn total_edges_added(&self) -> usize {
self.out_add.values().map(|s| s.len()).sum()
}
pub fn total_edges_deleted(&self) -> usize {
self.out_del.values().map(|s| s.len()).sum()
}
pub fn create_node(&mut self, node_id: NodeId, key: Option<&str>) {
let node_delta = NodeDelta {
key: key.map(|s| s.to_string()),
labels: None,
labels_deleted: None,
props: None,
};
self.created_nodes.insert(node_id, node_delta);
if let Some(k) = key {
self.key_index.insert(k.to_string(), node_id);
}
}
pub fn delete_node(&mut self, node_id: NodeId) {
if let Some(removed) = self.created_nodes.remove(&node_id) {
if let Some(key) = &removed.key {
self.key_index.remove(key);
}
self.out_add.remove(&node_id);
if let Some(sources) = self.incoming_edge_sources.remove(&node_id) {
for src in sources {
if let Some(patches) = self.out_add.get_mut(&src) {
patches.retain(|p| p.other != node_id);
if patches.is_empty() {
self.out_add.remove(&src);
}
}
}
}
self.in_add.remove(&node_id);
for (_, patches) in self.in_add.iter_mut() {
patches.retain(|p| p.other != node_id);
}
self.in_add.retain(|_, patches| !patches.is_empty());
return;
}
self.deleted_nodes.insert(node_id);
self.modified_nodes.remove(&node_id);
}
pub fn is_node_created(&self, node_id: NodeId) -> bool {
self.created_nodes.contains_key(&node_id)
}
pub fn is_node_deleted(&self, node_id: NodeId) -> bool {
self.deleted_nodes.contains(&node_id)
}
pub fn node_delta(&self, node_id: NodeId) -> Option<&NodeDelta> {
self
.created_nodes
.get(&node_id)
.or_else(|| self.modified_nodes.get(&node_id))
}
pub fn set_node_prop(&mut self, node_id: NodeId, key_id: PropKeyId, value: PropValue) {
self.set_node_prop_ref(node_id, key_id, std::sync::Arc::new(value));
}
pub fn set_node_prop_ref(&mut self, node_id: NodeId, key_id: PropKeyId, value: PropValueRef) {
let node_delta = if let Some(node_delta) = self.created_nodes.get_mut(&node_id) {
node_delta
} else {
self
.modified_nodes
.entry(node_id)
.or_insert_with(|| NodeDelta {
key: None,
labels: None,
labels_deleted: None,
props: None,
})
};
let props = node_delta
.props
.get_or_insert_with(std::collections::HashMap::new);
props.insert(key_id, Some(value));
}
pub fn delete_node_prop(&mut self, node_id: NodeId, key_id: PropKeyId) {
let node_delta = if let Some(node_delta) = self.created_nodes.get_mut(&node_id) {
node_delta
} else {
self
.modified_nodes
.entry(node_id)
.or_insert_with(|| NodeDelta {
key: None,
labels: None,
labels_deleted: None,
props: None,
})
};
let props = node_delta
.props
.get_or_insert_with(std::collections::HashMap::new);
props.insert(key_id, None);
}
pub fn node_prop(&self, node_id: NodeId, key_id: PropKeyId) -> Option<Option<&PropValue>> {
let node_delta = self
.created_nodes
.get(&node_id)
.or_else(|| self.modified_nodes.get(&node_id))?;
let props = node_delta.props.as_ref()?;
props.get(&key_id).map(|v| v.as_deref())
}
pub fn add_node_label(&mut self, node_id: NodeId, label_id: LabelId) {
let node_delta = if let Some(node_delta) = self.created_nodes.get_mut(&node_id) {
node_delta
} else {
self
.modified_nodes
.entry(node_id)
.or_insert_with(|| NodeDelta {
key: None,
labels: None,
labels_deleted: None,
props: None,
})
};
if let Some(ref mut deleted) = node_delta.labels_deleted {
deleted.remove(&label_id);
}
let labels = node_delta
.labels
.get_or_insert_with(std::collections::HashSet::new);
labels.insert(label_id);
}
pub fn remove_node_label(&mut self, node_id: NodeId, label_id: LabelId) {
let is_created = self.created_nodes.contains_key(&node_id);
let node_delta = if let Some(node_delta) = self.created_nodes.get_mut(&node_id) {
node_delta
} else {
self
.modified_nodes
.entry(node_id)
.or_insert_with(|| NodeDelta {
key: None,
labels: None,
labels_deleted: None,
props: None,
})
};
if let Some(ref mut labels) = node_delta.labels {
labels.remove(&label_id);
}
if !is_created {
let deleted = node_delta
.labels_deleted
.get_or_insert_with(std::collections::HashSet::new);
deleted.insert(label_id);
}
}
pub fn is_label_added(&self, node_id: NodeId, label_id: LabelId) -> bool {
if let Some(node_delta) = self
.created_nodes
.get(&node_id)
.or_else(|| self.modified_nodes.get(&node_id))
{
if let Some(ref labels) = node_delta.labels {
return labels.contains(&label_id);
}
}
false
}
pub fn is_label_removed(&self, node_id: NodeId, label_id: LabelId) -> bool {
if let Some(node_delta) = self.modified_nodes.get(&node_id) {
if let Some(ref deleted) = node_delta.labels_deleted {
return deleted.contains(&label_id);
}
}
false
}
pub fn added_labels(&self, node_id: NodeId) -> Option<&std::collections::HashSet<LabelId>> {
self
.created_nodes
.get(&node_id)
.or_else(|| self.modified_nodes.get(&node_id))
.and_then(|d| d.labels.as_ref())
}
pub fn removed_labels(&self, node_id: NodeId) -> Option<&std::collections::HashSet<LabelId>> {
self
.modified_nodes
.get(&node_id)
.and_then(|d| d.labels_deleted.as_ref())
}
pub fn define_label(&mut self, label_id: LabelId, name: &str) {
self.new_labels.insert(label_id, name.to_string());
}
pub fn define_etype(&mut self, etype_id: ETypeId, name: &str) {
self.new_etypes.insert(etype_id, name.to_string());
}
pub fn define_propkey(&mut self, propkey_id: PropKeyId, name: &str) {
self.new_propkeys.insert(propkey_id, name.to_string());
}
pub fn set_edge_prop(
&mut self,
src: NodeId,
etype: ETypeId,
dst: NodeId,
key_id: PropKeyId,
value: PropValue,
) {
self.set_edge_prop_ref(src, etype, dst, key_id, std::sync::Arc::new(value));
}
pub fn set_edge_prop_ref(
&mut self,
src: NodeId,
etype: ETypeId,
dst: NodeId,
key_id: PropKeyId,
value: PropValueRef,
) {
let edge_key = (src, etype, dst);
let props = self.edge_props.entry(edge_key).or_default();
props.insert(key_id, Some(value));
}
pub fn delete_edge_prop(&mut self, src: NodeId, etype: ETypeId, dst: NodeId, key_id: PropKeyId) {
let edge_key = (src, etype, dst);
let props = self.edge_props.entry(edge_key).or_default();
props.insert(key_id, None);
}
pub fn edge_prop(
&self,
src: NodeId,
etype: ETypeId,
dst: NodeId,
key_id: PropKeyId,
) -> Option<Option<&PropValue>> {
let edge_key = (src, etype, dst);
self
.edge_props
.get(&edge_key)
.and_then(|props| props.get(&key_id))
.map(|v| v.as_deref())
}
pub fn edge_props_delta(
&self,
src: NodeId,
etype: ETypeId,
dst: NodeId,
) -> Option<&HashMap<PropKeyId, Option<PropValueRef>>> {
self.edge_props.get(&(src, etype, dst))
}
pub fn node_by_key(&self, key: &str) -> Option<NodeId> {
if self.key_index_deleted.contains(key) {
return None;
}
self.key_index.get(key).copied()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_edge() {
let mut delta = DeltaState::new();
delta.add_edge(1, 10, 2);
assert!(delta.is_edge_added(1, 10, 2));
assert!(!delta.is_edge_deleted(1, 10, 2));
}
#[test]
fn test_delete_edge() {
let mut delta = DeltaState::new();
delta.delete_edge(1, 10, 2);
assert!(delta.is_edge_deleted(1, 10, 2));
assert!(!delta.is_edge_added(1, 10, 2));
}
#[test]
fn test_add_cancels_delete() {
let mut delta = DeltaState::new();
delta.delete_edge(1, 10, 2);
assert!(delta.is_edge_deleted(1, 10, 2));
delta.add_edge(1, 10, 2);
assert!(!delta.is_edge_deleted(1, 10, 2));
assert!(!delta.is_edge_added(1, 10, 2)); }
#[test]
fn test_delete_cancels_add() {
let mut delta = DeltaState::new();
delta.add_edge(1, 10, 2);
assert!(delta.is_edge_added(1, 10, 2));
delta.delete_edge(1, 10, 2);
assert!(!delta.is_edge_added(1, 10, 2));
assert!(!delta.is_edge_deleted(1, 10, 2)); }
}