Skip to main content

selene_graph/mutator/
property_index.rs

1//! Property-index mutation methods for the transaction mutator.
2
3use selene_core::{Change, DbString, SchemaChange};
4
5use crate::graph::PropertyIndexEntry;
6use crate::schema_index_kind::schema_kind_from;
7use crate::{GraphError, GraphResult, Mutator, TypedIndexKind};
8
9impl<'tx, 'g> Mutator<'tx, 'g> {
10    /// Register a durable node property index in the active write transaction.
11    ///
12    /// # Errors
13    ///
14    /// Returns [`GraphError::PropertyIndexAlreadyExists`] if the pair already
15    /// exists, or [`GraphError::IndexValueRejected`] if any existing non-null
16    /// value for `(label, property)` cannot be admitted to `kind`.
17    pub fn create_property_index(
18        &mut self,
19        label: DbString,
20        property: DbString,
21        kind: TypedIndexKind,
22    ) -> GraphResult<()> {
23        self.create_property_index_named(label, property, kind, None)
24    }
25
26    /// Register a durable node property index with optional catalog name.
27    pub fn create_property_index_named(
28        &mut self,
29        label: DbString,
30        property: DbString,
31        kind: TypedIndexKind,
32        name: Option<DbString>,
33    ) -> GraphResult<()> {
34        if self
35            .txn
36            .read()
37            .property_index
38            .contains_key(&(label.clone(), property.clone()))
39        {
40            return Err(GraphError::PropertyIndexAlreadyExists { label, property });
41        }
42        let index = crate::property_index::build_property_index(
43            self.txn.read(),
44            label.clone(),
45            property.clone(),
46            kind,
47        )?;
48        let graph_id = self.txn.read().graph_id();
49        self.txn.guard_mut().property_index.insert(
50            (label.clone(), property.clone()),
51            PropertyIndexEntry::new(index, name.clone()),
52        );
53        self.txn.changes.push(Change::SchemaChanged {
54            graph: graph_id,
55            change: SchemaChange::PropertyIndexCreatedNamed {
56                label,
57                property,
58                kind: schema_kind_from(kind),
59                name,
60            },
61        });
62        Ok(())
63    }
64
65    /// Drop a durable node property index from the active write transaction.
66    ///
67    /// The operation is idempotent. Dropping an absent index succeeds and emits
68    /// no WAL change.
69    pub fn drop_property_index(&mut self, label: DbString, property: DbString) -> GraphResult<()> {
70        if !self
71            .txn
72            .read()
73            .property_index
74            .contains_key(&(label.clone(), property.clone()))
75        {
76            return Ok(());
77        }
78        let graph_id = self.txn.read().graph_id();
79        self.txn
80            .guard_mut()
81            .property_index
82            .remove(&(label.clone(), property.clone()));
83        self.txn.changes.push(Change::SchemaChanged {
84            graph: graph_id,
85            change: SchemaChange::PropertyIndexDropped { label, property },
86        });
87        Ok(())
88    }
89}
90
91#[cfg(test)]
92#[path = "property_index/tests.rs"]
93mod tests;