Skip to main content

selene_graph/mutator/
delete_set.rs

1use std::collections::BTreeSet;
2
3use selene_core::{EdgeId, NodeId};
4
5use super::Mutator;
6use crate::{GraphError, GraphResult};
7
8impl<'tx, 'g> Mutator<'tx, 'g> {
9    /// Delete a set of node and edge references.
10    ///
11    /// Nodes are deleted first through [`Self::delete_node`], so incident edges
12    /// keep the same cascade behavior and change ordering as a direct node
13    /// delete. Explicit edges already removed by a node cascade are skipped
14    /// during the edge pass. IDs that are mapped but already invalidated are
15    /// clean no-ops, matching set-oriented query deletion where duplicate rows
16    /// may reference the same graph element more than once. IDs that were never
17    /// allocated still return the same not-found errors as single-element
18    /// delete calls. The full set is validated before the first row is removed,
19    /// so a mixed set cannot partially mutate the transaction before surfacing a
20    /// missing-id error.
21    pub fn delete_elements(
22        &mut self,
23        nodes: BTreeSet<NodeId>,
24        edges: BTreeSet<EdgeId>,
25    ) -> GraphResult<()> {
26        self.validate_delete_set(&nodes, &edges)?;
27        for node in nodes {
28            if self.node_can_be_deleted(node)? {
29                self.delete_node(node)?;
30            }
31        }
32        for edge in edges {
33            if self.edge_can_be_deleted(edge)? {
34                self.delete_edge(edge)?;
35            }
36        }
37        Ok(())
38    }
39
40    fn validate_delete_set(
41        &self,
42        nodes: &BTreeSet<NodeId>,
43        edges: &BTreeSet<EdgeId>,
44    ) -> GraphResult<()> {
45        for node in nodes {
46            self.node_can_be_deleted(*node)?;
47        }
48        for edge in edges {
49            self.edge_can_be_deleted(*edge)?;
50        }
51        Ok(())
52    }
53
54    fn node_can_be_deleted(&self, id: NodeId) -> GraphResult<bool> {
55        let graph = self.txn.read();
56        let row = graph
57            .row_for_node_id(id)
58            .ok_or(GraphError::NodeNotFound { id })?
59            .get();
60        if row as usize >= graph.node_store.len() {
61            return Err(GraphError::NodeNotFound { id });
62        }
63        Ok(graph.node_store.is_alive(row))
64    }
65
66    fn edge_can_be_deleted(&self, id: EdgeId) -> GraphResult<bool> {
67        let graph = self.txn.read();
68        let row = graph
69            .row_for_edge_id(id)
70            .ok_or(GraphError::EdgeNotFound { id })?
71            .get();
72        if row as usize >= graph.edge_store.len() {
73            return Err(GraphError::EdgeNotFound { id });
74        }
75        Ok(graph.edge_store.is_alive(row))
76    }
77}