use super::super::result::EdgeBinding;
use crate::graph::schema::DirGraph;
use crate::graph::storage::GraphRead;
use petgraph::graph::NodeIndex;
use std::collections::HashSet;
pub(super) fn enforce_write_scope(graph: &DirGraph, node_type: &str) -> Result<(), String> {
if let Some(scope) = &graph.active_write_scope {
if !scope.contains(node_type) {
return Err(format!(
"write scope violation: node type '{}' is not in the allowed write set ({})",
node_type,
allowed_write_set(scope)
));
}
}
Ok(())
}
fn allowed_write_set(scope: &HashSet<String>) -> String {
let mut types: Vec<&str> = scope.iter().map(|s| s.as_str()).collect();
types.sort_unstable();
types.join(", ")
}
fn stored_node_type(graph: &DirGraph, node_idx: NodeIndex) -> String {
let _arena_guard = graph.graph.begin_query();
graph
.node_view(node_idx)
.map(|n| n.get_node_type_ref(&graph.interner).to_string())
.unwrap_or_default()
}
pub(super) fn enforce_node_write_scope(
graph: &DirGraph,
node_idx: NodeIndex,
) -> Result<(), String> {
if graph.active_write_scope.is_none() {
return Ok(());
}
enforce_write_scope(graph, &stored_node_type(graph, node_idx))
}
pub(super) fn enforce_edge_write_scope(
graph: &DirGraph,
rel_type: &str,
source: NodeIndex,
target: NodeIndex,
) -> Result<(), String> {
let Some(scope) = &graph.active_write_scope else {
return Ok(());
};
let source_type = stored_node_type(graph, source);
let target_type = stored_node_type(graph, target);
if scope.contains(&source_type) || scope.contains(&target_type) {
return Ok(());
}
Err(format!(
"write scope violation: relationship '{}' connects '{}' to '{}' and neither endpoint \
type is in the allowed write set ({})",
rel_type,
source_type,
target_type,
allowed_write_set(scope)
))
}
pub(super) fn enforce_bound_edge_write_scope(
graph: &DirGraph,
binding: &EdgeBinding,
) -> Result<(), String> {
if graph.active_write_scope.is_none() {
return Ok(());
}
let rel_type = {
let _arena_guard = graph.graph.begin_query();
graph
.graph
.edge_weight(binding.edge_index)
.map(|e| e.connection_type)
}
.map(|key| graph.interner.resolve(key).to_string())
.unwrap_or_default();
enforce_edge_write_scope(graph, &rel_type, binding.source, binding.target)
}