use compact_str::CompactString;
use petgraph::Direction;
use petgraph::visit::{EdgeRef, IntoEdgeReferences, IntoNodeReferences};
use std::sync::Arc;
use crate::error::GraphError;
use crate::graph::change::{ChangeSet, CommitMetadata};
use crate::graph::definition::{Definition, DefinitionKind};
use crate::graph::hooks::{Mark, RollbackReason};
use crate::graph::schema::{GraphSchema, PropertySchema, SchemaInferer};
use crate::graph::undo::UndoEntry;
use crate::graph::{
EdgeHandle, GraphNodeType, GraphStatistics, NodeIndex, TraversalGraph, VertexHandle,
};
use crate::graph::{IsolationLevel, StorageCapabilities};
use crate::value::{ElementProperty, PropertyMap};
use crate::graph::write_checks::{
check_label, check_properties, check_property_value, normalize_vertex_labels,
path_property_name, remove_path, single_segment_name, write_path, write_path_in,
};
pub(crate) fn stored_vertex_id<S: GraphStorage>(
storage: &S,
vertex: S::VertexId,
) -> Result<&str, GraphError> {
match storage.vertex_id(vertex) {
Some(id) => Ok(id),
None if !storage.contains_vertex(vertex) => Err(GraphError::vertex_removed()),
None => Err(GraphError::InvalidElementState {
reason: "vertex has no id".to_string(),
}),
}
}
pub(crate) fn stored_edge_id<S: GraphStorage>(
storage: &S,
edge: S::EdgeId,
) -> Result<&str, GraphError> {
match storage.edge_id(edge) {
Some(id) => Ok(id),
None if !storage.contains_edge(edge) => Err(GraphError::edge_removed()),
None => Err(GraphError::InvalidElementState {
reason: "edge has no id".to_string(),
}),
}
}
pub(crate) fn filter_vertex_id<S: GraphStorage>(
storage: &S,
vertex: S::VertexId,
) -> Result<Option<&str>, GraphError> {
match stored_vertex_id(storage, vertex) {
Ok(id) => Ok(Some(id)),
Err(GraphError::ElementRemoved { .. }) => Ok(None),
Err(err) => Err(err),
}
}
pub(crate) fn filter_edge_id<S: GraphStorage>(
storage: &S,
edge: S::EdgeId,
) -> Result<Option<&str>, GraphError> {
match stored_edge_id(storage, edge) {
Ok(id) => Ok(Some(id)),
Err(GraphError::ElementRemoved { .. }) => Ok(None),
Err(err) => Err(err),
}
}
pub(crate) fn stored_vertex_label<S: GraphStorage>(
storage: &S,
vertex: S::VertexId,
) -> Result<Option<&str>, GraphError> {
match storage.vertex_label(vertex) {
Some(label) => Ok(Some(label)),
None if !storage.contains_vertex(vertex) => Err(GraphError::vertex_removed()),
None => Ok(None),
}
}
pub(crate) fn stored_vertex_labels<S: GraphStorage>(
storage: &S,
vertex: S::VertexId,
) -> Result<&[CompactString], GraphError> {
let labels = storage.vertex_labels(vertex);
if labels.is_empty() && !storage.contains_vertex(vertex) {
return Err(GraphError::vertex_removed());
}
Ok(labels)
}
pub(crate) fn stored_edge_label<S: GraphStorage>(
storage: &S,
edge: S::EdgeId,
) -> Result<Option<&str>, GraphError> {
match storage.edge_label(edge) {
Some(label) => Ok(Some(label)),
None if !storage.contains_edge(edge) => Err(GraphError::edge_removed()),
None => Ok(None),
}
}
pub trait GraphStorage: Send + Sync {
type VertexId: Eq + std::hash::Hash + Clone + Copy + Send + Sync + std::fmt::Debug;
type EdgeId: Eq + std::hash::Hash + Clone + Copy + Send + Sync + std::fmt::Debug;
fn vertex_count(&self) -> usize;
fn edge_count(&self) -> usize;
fn vertices(&self) -> impl Iterator<Item = Self::VertexId> + '_;
fn edges(&self) -> impl Iterator<Item = Self::EdgeId> + '_;
fn get_vertex_by_id(&self, id: &str) -> Option<Self::VertexId>;
fn get_edge_by_id(&self, id: &str) -> Option<Self::EdgeId>;
fn out_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_;
fn in_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_;
fn vertex_id(&self, node: Self::VertexId) -> Option<&str>;
fn edge_id(&self, edge: Self::EdgeId) -> Option<&str>;
fn vertex_label(&self, node: Self::VertexId) -> Option<&str>;
fn edge_label(&self, edge: Self::EdgeId) -> Option<&str>;
fn vertex_labels(&self, node: Self::VertexId) -> &[CompactString];
#[inline]
fn vertex_has_label(&self, node: Self::VertexId, label: &str) -> bool {
self.vertex_labels(node).iter().any(|l| l.as_str() == label)
}
fn vertex_properties(&self, node: Self::VertexId) -> Option<&PropertyMap>;
fn edge_properties(&self, edge: Self::EdgeId) -> Option<&PropertyMap>;
fn edge_endpoints(&self, edge: Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)>;
fn contains_vertex(&self, node: Self::VertexId) -> bool {
self.vertex_properties(node).is_some()
}
fn contains_edge(&self, edge: Self::EdgeId) -> bool {
self.edge_endpoints(edge).is_some()
}
fn vertices_by_label<'a>(
&'a self,
label: &'a str,
) -> Box<dyn Iterator<Item = Self::VertexId> + 'a> {
Box::new(
self.vertices()
.filter(move |&n| self.vertex_has_label(n, label)),
)
}
fn edges_by_label<'a>(&'a self, label: &'a str) -> Box<dyn Iterator<Item = Self::EdgeId> + 'a> {
Box::new(
self.edges()
.filter(move |&e| self.edge_label(e) == Some(label)),
)
}
fn statistics(&self) -> Option<&GraphStatistics> {
None
}
fn infer_schema(&self) -> GraphSchema
where
Self: Sized,
{
SchemaInferer::infer_from_storage(self)
}
fn set_schema(&mut self, schema: GraphSchema) -> Result<(), GraphError> {
let _ = schema;
Err(GraphError::Unsupported {
operation: "schemas",
})
}
fn get_schema(&self) -> Option<GraphSchema> {
None
}
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
let _ = (kind, labels, key);
None
}
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
std::iter::empty()
}
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
let _ = (kind, name);
None
}
fn set_definition(&mut self, definition: Definition) -> Result<(), GraphError> {
let _ = definition;
Err(GraphError::Unsupported {
operation: "definitions",
})
}
fn remove_definition(&mut self, kind: DefinitionKind, name: &str) -> Result<bool, GraphError> {
let _ = (kind, name);
Err(GraphError::Unsupported {
operation: "definitions",
})
}
fn recompress(&mut self, name: &str) -> Result<bool, GraphError> {
let _ = name;
Err(GraphError::unsupported("compressed properties"))
}
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
let _ = name;
None
}
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
properties: PropertyMap,
) -> Result<Self::VertexId, GraphError>;
fn add_vertex_label(
&mut self,
node: Self::VertexId,
label: CompactString,
) -> Result<bool, GraphError>;
fn remove_vertex_label(
&mut self,
node: Self::VertexId,
label: &str,
) -> Result<bool, GraphError>;
fn set_edge_label(
&mut self,
edge: Self::EdgeId,
label: CompactString,
) -> Result<bool, GraphError> {
let _ = (edge, label);
Err(GraphError::Unsupported {
operation: "changing an edge label",
})
}
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: Self::VertexId,
to: Self::VertexId,
properties: PropertyMap,
) -> Result<Self::EdgeId, GraphError>;
fn set_vertex_property(
&mut self,
node: Self::VertexId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError>;
fn set_edge_property(
&mut self,
edge: Self::EdgeId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError>;
fn set_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
let name = path_property_name(path)?;
let existing = self
.vertex_properties(node)
.and_then(|props| props.get(name.as_str()));
let (key, resulting) = write_path(existing, path, value)?;
self.set_vertex_property(node, key, resulting)
}
fn set_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
let name = path_property_name(path)?;
let existing = self
.edge_properties(edge)
.and_then(|props| props.get(name.as_str()));
let (key, resulting) = write_path(existing, path, value)?;
self.set_edge_property(edge, key, resulting)
}
fn remove_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(name) = single_segment_name(path) {
return self.drop_vertex_property(name, node);
}
let Some(props) = self.vertex_properties(node) else {
return Err(GraphError::vertex_removed());
};
let existing = match path.segments().first() {
Some(crate::value::json_path::JsonPathSegment::Key(name)) => props.get(name.as_str()),
_ => None,
};
match remove_path(existing, path) {
Some((key, resulting)) => self.set_vertex_property(node, key, resulting),
None => Ok(()),
}
}
fn remove_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(name) = single_segment_name(path) {
return self.drop_edge_property(name, edge);
}
let existing = match path.segments().first() {
Some(crate::value::json_path::JsonPathSegment::Key(name)) => self
.edge_properties(edge)
.and_then(|props| props.get(name.as_str())),
_ => None,
};
match remove_path(existing, path) {
Some((key, resulting)) => self.set_edge_property(edge, key, resulting),
None => Ok(()),
}
}
fn drop_vertex(&mut self, node: Self::VertexId) -> Result<(), GraphError>;
fn drop_vertex_property(&mut self, prop: &str, node: Self::VertexId) -> Result<(), GraphError>;
fn drop_edge(&mut self, edge: Self::EdgeId) -> Result<(), GraphError>;
fn drop_edge_property(&mut self, prop: &str, edge: Self::EdgeId) -> Result<(), GraphError>;
fn shrink_to_fit(&mut self) {}
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
None
}
fn memory_footprint_bytes(&self) -> Option<u64> {
self.memory_usage().map(|stats| stats.total_bytes())
}
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
crate::graph::ExecutionPolicy::permissive()
}
fn begin_unit(&mut self) -> UnitMark {
UnitMark::default()
}
fn commit_unit(&mut self, mark: UnitMark) -> Result<(), GraphError> {
let _ = mark;
Ok(())
}
fn rollback_unit(&mut self, mark: UnitMark, reason: &RollbackReason) {
let _ = (mark, reason);
}
fn unit_changes(&self, mark: UnitMark) -> UnitChanges {
let _ = mark;
UnitChanges::NONE
}
fn set_unit_metadata(&mut self, metadata: CommitMetadata) {
let _ = metadata;
}
fn discard_unit(&mut self, mark: UnitMark) -> Result<ChangeSet, GraphError> {
let error = GraphError::Unsupported {
operation: DRY_RUN_OPERATION,
};
self.rollback_unit(mark, &RollbackReason::failed(&error));
Err(error)
}
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
let _ = name;
Err(GraphError::mark_unavailable(
"this storage keeps no journal",
))
}
fn capabilities(&self) -> StorageCapabilities {
StorageCapabilities::none()
}
fn register_commit_hook(
&mut self,
hook: Box<dyn crate::graph::CommitHook>,
) -> Result<(), GraphError> {
let _ = hook;
Err(GraphError::Unsupported {
operation: "commit hooks",
})
}
fn last_commit_seq(&self) -> u64 {
0
}
fn raise_id_sequences(
&mut self,
node_sequence: u64,
edge_sequence: u64,
) -> Result<(), GraphError> {
let _ = (node_sequence, edge_sequence);
Ok(())
}
fn apply_change_set(&mut self, changes: &ChangeSet) -> Result<(), GraphError> {
let mut budget =
crate::traversal::memory_budget::UnitBudget::start(&*self, None, CHANGE_SET_OPERATION);
let mark = self.begin_unit();
let applied = close_on_unwind(
self,
|this| {
crate::graph::replay::apply_mutations(this, changes, &mut budget)?;
crate::traversal::memory_budget::check(&budget, &*this)?;
this.raise_id_sequences(changes.node_sequence(), changes.edge_sequence())
},
|this| this.rollback_unit(mark, &RollbackReason::failed(&UNWOUND)),
);
match applied {
Ok(()) => self.commit_unit(mark),
Err(err) => {
self.rollback_unit(mark, &RollbackReason::failed(&err));
Err(err)
}
}
}
}
pub(crate) const DRY_RUN_OPERATION: &str = "dry runs (discarding a unit with its changes)";
const READ_ONLY_MARK: &str = "marks on a read-only view";
pub(crate) const CHANGE_SET_OPERATION: &str = "change set apply";
pub(crate) const UNWOUND: &str =
"a panic unwound through the unit (an engine bug); its changes were rolled back";
#[inline]
pub(crate) fn close_on_unwind<X: ?Sized, T>(
target: &mut X,
body: impl FnOnce(&mut X) -> T,
on_unwind: impl FnOnce(&mut X),
) -> T {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| body(&mut *target))) {
Ok(value) => value,
Err(payload) => {
on_unwind(target);
std::panic::resume_unwind(payload)
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct UnitChanges {
pub data: bool,
pub schema: bool,
pub definitions: bool,
}
impl UnitChanges {
pub const NONE: UnitChanges = UnitChanges {
data: false,
schema: false,
definitions: false,
};
pub const fn new(data: bool, schema: bool) -> Self {
UnitChanges {
data,
schema,
definitions: false,
}
}
pub const fn with_definitions(mut self, changed: bool) -> Self {
self.definitions = changed;
self
}
pub const fn any(&self) -> bool {
self.data || self.schema || self.definitions
}
pub const fn union(self, other: UnitChanges) -> UnitChanges {
UnitChanges {
data: self.data || other.data,
schema: self.schema || other.schema,
definitions: self.definitions || other.definitions,
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct UnitMark(u64);
impl UnitMark {
pub const fn new(raw: u64) -> Self {
Self(raw)
}
pub const fn raw(self) -> u64 {
self.0
}
}
impl GraphStorage for TraversalGraph {
type VertexId = VertexHandle;
type EdgeId = EdgeHandle;
#[inline]
fn vertex_count(&self) -> usize {
self.graph.node_count()
}
#[inline]
fn edge_count(&self) -> usize {
self.graph.edge_count()
}
#[inline]
fn vertices(&self) -> impl Iterator<Item = VertexHandle> + '_ {
self.graph
.node_references()
.map(|(index, vertex)| VertexHandle::new(index, vertex.3))
}
#[inline]
fn edges(&self) -> impl Iterator<Item = EdgeHandle> + '_ {
self.graph
.edge_references()
.map(|edge| EdgeHandle::new(edge.id(), edge.weight().3.own))
}
#[inline]
fn get_vertex_by_id(&self, id: &str) -> Option<VertexHandle> {
self.index.get_node(id)
}
#[inline]
fn get_edge_by_id(&self, id: &str) -> Option<EdgeHandle> {
self.index.get_edge(id)
}
#[inline]
fn out_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
let index = self.resolve_vertex(node).unwrap_or_else(NodeIndex::end);
self.graph
.edges_directed(index, Direction::Outgoing)
.map(|e| EdgeHandle::new(e.id(), e.weight().3.own))
}
#[inline]
fn in_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
let index = self.resolve_vertex(node).unwrap_or_else(NodeIndex::end);
self.graph
.edges_directed(index, Direction::Incoming)
.map(|e| EdgeHandle::new(e.id(), e.weight().3.own))
}
#[inline]
fn vertex_id(&self, node: VertexHandle) -> Option<&str> {
self.vertex_weight(node).map(|v| v.0.as_str())
}
#[inline]
fn edge_id(&self, edge: EdgeHandle) -> Option<&str> {
self.edge_weight(edge).map(|e| e.0.as_str())
}
#[inline]
fn vertex_label(&self, node: VertexHandle) -> Option<&str> {
self.vertex_weight(node)
.and_then(|v| v.1.first())
.map(|l| l.as_str())
}
#[inline]
fn edge_label(&self, edge: EdgeHandle) -> Option<&str> {
self.edge_weight(edge).and_then(|e| e.1.as_deref())
}
#[inline]
fn vertex_labels(&self, node: VertexHandle) -> &[CompactString] {
self.vertex_weight(node)
.map(|v| v.1.as_slice())
.unwrap_or(&[])
}
#[inline]
fn vertex_properties(&self, node: VertexHandle) -> Option<&PropertyMap> {
self.vertex_weight(node).map(|v| &v.2)
}
#[inline]
fn edge_properties(&self, edge: EdgeHandle) -> Option<&PropertyMap> {
self.edge_weight(edge).and_then(|e| e.2.as_ref())
}
#[inline]
fn edge_endpoints(&self, edge: EdgeHandle) -> Option<(VertexHandle, VertexHandle)> {
let generations = self.edge_weight(edge)?.3;
let (source, target) = self.graph.edge_endpoints(edge.index())?;
Some((
VertexHandle::new(source, generations.source),
VertexHandle::new(target, generations.target),
))
}
#[inline]
fn contains_vertex(&self, node: VertexHandle) -> bool {
self.resolve_vertex(node).is_some()
}
#[inline]
fn contains_edge(&self, edge: EdgeHandle) -> bool {
self.resolve_edge(edge).is_some()
}
#[inline]
fn vertices_by_label<'a>(
&'a self,
label: &'a str,
) -> Box<dyn Iterator<Item = VertexHandle> + 'a> {
match self.index.get_nodes_by_label(label) {
Some(nodes) => Box::new(nodes),
None => Box::new(std::iter::empty()),
}
}
#[inline]
fn edges_by_label<'a>(&'a self, label: &'a str) -> Box<dyn Iterator<Item = EdgeHandle> + 'a> {
match self.index.get_edges_by_label(label) {
Some(edges) => Box::new(edges),
None => Box::new(std::iter::empty()),
}
}
#[inline]
fn statistics(&self) -> Option<&GraphStatistics> {
Some(&self.statistics)
}
#[inline]
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
mut properties: PropertyMap,
) -> Result<VertexHandle, GraphError> {
let labels = normalize_vertex_labels(labels)?;
check_properties(&properties)?;
{
let schema = self.schema.read();
crate::graph::schema::SchemaValidator::validate_vertex(
&schema,
&labels,
&mut properties,
)?;
}
self.compression_prepare_vertex(&labels, &mut properties);
let sequence = self.node_sequence;
let id = match id {
Some(id_str) => {
if let Ok(parsed_id) = id_str.parse::<u64>() {
self.node_sequence = self.node_sequence.max(parsed_id);
}
id_str
}
None => self.next_value_node_sequence()?,
};
if self.index.contains_node(&id) {
self.node_sequence = sequence;
Err(GraphError::VertexIdUniqueConstraint { id: id.to_string() })
} else {
if self.undo.is_recording() {
self.undo.record(UndoEntry::AddedVertex { id: id.clone() });
}
Ok(self.insert_vertex_raw(id, labels, properties))
}
}
#[inline]
fn add_vertex_label(
&mut self,
node: VertexHandle,
label: CompactString,
) -> Result<bool, GraphError> {
check_label(&label)?;
match self.vertex_weight(node) {
Some(vertex) => {
if vertex.1.contains(&label) {
return Ok(false);
}
let mut new_labels = vertex.1.clone();
new_labels.push(label.clone());
crate::graph::schema::SchemaValidator::check_vertex(
&self.schema.read(),
&new_labels,
&vertex.2,
)?;
self.check_incident_topology(node.index(), &new_labels)?;
let recording = self.undo.is_recording();
if let Some(vertex) = self
.graph
.node_weight_mut(node.index())
.filter(|vertex| vertex.3 == node.generation())
{
let old = std::mem::replace(&mut vertex.1, new_labels);
self.statistics.vertex_relabeled(&old, &vertex.1);
if recording {
let id = vertex.0.clone();
self.undo.record(UndoEntry::VertexLabels { id, old });
}
}
self.index.insert_node_label(label, node);
self.compression_normalize_vertex(node);
Ok(true)
}
None => Err(GraphError::vertex_removed()),
}
}
#[inline]
fn remove_vertex_label(&mut self, node: VertexHandle, label: &str) -> Result<bool, GraphError> {
match self.vertex_weight(node) {
Some(vertex) => {
if !vertex.1.iter().any(|l| l.as_str() == label) {
return Ok(false);
}
let new_labels: Vec<CompactString> = vertex
.1
.iter()
.filter(|l| l.as_str() != label)
.cloned()
.collect();
crate::graph::schema::SchemaValidator::check_vertex(
&self.schema.read(),
&new_labels,
&vertex.2,
)?;
self.check_incident_topology(node.index(), &new_labels)?;
let recording = self.undo.is_recording();
if let Some(vertex) = self
.graph
.node_weight_mut(node.index())
.filter(|vertex| vertex.3 == node.generation())
{
let old = std::mem::replace(&mut vertex.1, new_labels);
self.statistics.vertex_relabeled(&old, &vertex.1);
if recording {
let id = vertex.0.clone();
self.undo.record(UndoEntry::VertexLabels { id, old });
}
}
self.index.remove_node_label(label, node);
self.compression_normalize_vertex(node);
Ok(true)
}
None => Err(GraphError::vertex_removed()),
}
}
fn set_edge_label(
&mut self,
edge: EdgeHandle,
label: CompactString,
) -> Result<bool, GraphError> {
let Some(index) = self.resolve_edge(edge) else {
return Err(GraphError::edge_removed());
};
let (Some(weight), Some((from, to))) = (
self.graph.edge_weight(index),
self.graph.edge_endpoints(index),
) else {
return Err(GraphError::edge_removed());
};
if weight.1.as_deref() == Some(label.as_str()) {
return Ok(false);
}
{
let schema = self.schema.read();
if schema.mode != crate::graph::schema::SchemaMode::None {
let empty = PropertyMap::default();
let (Some(source), Some(target)) =
(self.graph.node_weight(from), self.graph.node_weight(to))
else {
return Err(GraphError::vertex_removed());
};
crate::graph::schema::SchemaValidator::check_edge(
&schema,
Some(label.as_str()),
&source.1,
&target.1,
weight.2.as_ref().unwrap_or(&empty),
)?;
}
}
let recording = self.undo.is_recording();
let Some(weight) = self.graph.edge_weight_mut(index) else {
return Err(GraphError::edge_removed());
};
let old = weight.1.replace(label.clone());
self.statistics
.edge_relabeled(old.as_deref(), Some(label.as_str()));
if recording {
let id = weight.0.clone();
self.undo.record(UndoEntry::EdgeLabel {
id,
old: old.clone(),
});
}
if let Some(old) = old {
self.index.remove_edge_label(&old, edge);
}
self.index.insert_edge_label(label, edge);
self.compression_normalize_edge(edge);
Ok(true)
}
#[inline]
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: VertexHandle,
to: VertexHandle,
mut properties: PropertyMap,
) -> Result<EdgeHandle, GraphError> {
let (Some(source), Some(target)) = (self.vertex_weight(from), self.vertex_weight(to))
else {
return Err(GraphError::vertex_removed());
};
check_properties(&properties)?;
let source_labels: &[CompactString] = source.1.as_slice();
let target_labels: &[CompactString] = target.1.as_slice();
{
let schema = self.schema.read();
crate::graph::schema::SchemaValidator::validate_edge(
&schema,
label.as_deref(),
source_labels,
target_labels,
&mut properties,
)?;
}
self.compression_prepare_edge(label.as_deref(), &mut properties);
let edge_id = match id {
Some(edge_id_str) => {
if self.index.get_edge(&edge_id_str).is_some() {
return Err(GraphError::EdgeIdUniqueConstraint {
id: edge_id_str.to_string(),
});
}
if let Ok(parsed_id) = edge_id_str.parse::<u64>() {
self.edge_sequence = self.edge_sequence.max(parsed_id);
}
edge_id_str
}
None => self.next_value_edge_sequence()?,
};
if self.undo.is_recording() {
self.undo.record(UndoEntry::AddedEdge {
id: edge_id.clone(),
});
}
Ok(self.insert_edge_raw(edge_id, label, Some(properties), from, to))
}
#[inline]
fn set_vertex_property(
&mut self,
node: VertexHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
check_property_value(&key, &value)?;
let Some(index) = self.resolve_vertex(node) else {
return Err(GraphError::vertex_removed());
};
match self.graph.node_weight_mut(index) {
Some(node_ref) => {
let value = {
let schema = self.schema.read();
crate::graph::schema::SchemaValidator::validate_element_property(
&schema,
"vertex",
&node_ref.1,
&key,
value,
)?
};
let mut value = value;
self.compression
.prepare_vertex_value(&node_ref.1, &key, &mut value);
let undo_key = self.undo.is_recording().then(|| key.clone());
let (position, old) = node_ref.2.0.insert_full(key, value);
if let Some(key) = undo_key {
self.undo.record(UndoEntry::VertexProperty {
id: node_ref.0.clone(),
key,
old: old.map(|value| (position, value)),
});
}
Ok(())
}
None => Err(GraphError::vertex_removed()),
}
}
#[inline]
fn set_edge_property(
&mut self,
edge: EdgeHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
check_property_value(&key, &value)?;
let Some(index) = self.resolve_edge(edge) else {
return Err(GraphError::edge_removed());
};
match self.graph.edge_weight_mut(index) {
Some(edge_ref) => {
let value = {
let schema = self.schema.read();
crate::graph::schema::SchemaValidator::validate_element_property(
&schema,
"edge",
edge_ref.1.as_slice(),
&key,
value,
)?
};
let mut value = value;
self.compression
.prepare_edge_value(edge_ref.1.as_deref(), &key, &mut value);
let undo_key = self.undo.is_recording().then(|| key.clone());
let map_was_none = edge_ref.2.is_none();
let (position, old) = edge_ref
.2
.get_or_insert_with(PropertyMap::default)
.0
.insert_full(key, value);
if let Some(key) = undo_key {
self.undo.record(UndoEntry::EdgeProperty {
id: edge_ref.0.clone(),
key,
old: old.map(|value| (position, value)),
map_was_none,
});
}
Ok(())
}
None => Err(GraphError::edge_removed()),
}
}
fn set_vertex_property_path(
&mut self,
node: VertexHandle,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
let name = path_property_name(path)?;
check_property_value(name, &value)?;
if matches!(
self.schema.read().mode,
crate::graph::schema::SchemaMode::None
) {
self.record_vertex_property(node, name);
let written = match self.vertex_weight_mut(node) {
Some(node_ref) => write_path_in(&mut node_ref.2, path, value),
None => Err(GraphError::vertex_removed()),
};
self.compression_normalize_vertex_key(node, name);
return written;
}
let (key, resulting) = {
let Some(vertex) = self.vertex_weight(node) else {
return Err(GraphError::vertex_removed());
};
let schema = self.schema.read();
let value = crate::graph::schema::SchemaValidator::coerce_path_leaf(
&schema, "vertex", &vertex.1, path, value,
)?;
let (key, resulting) = write_path(vertex.2.get(name.as_str()), path, value)?;
crate::graph::schema::SchemaValidator::check_element_property(
&schema, "vertex", &vertex.1, &key, &resulting,
)?;
(key, resulting)
};
self.record_vertex_property(node, &key);
if let Some(vertex) = self.vertex_weight_mut(node) {
vertex.2.insert(key.clone(), resulting);
}
self.compression_normalize_vertex_key(node, &key);
Ok(())
}
fn set_edge_property_path(
&mut self,
edge: EdgeHandle,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
let name = path_property_name(path)?;
check_property_value(name, &value)?;
if matches!(
self.schema.read().mode,
crate::graph::schema::SchemaMode::None
) {
self.record_edge_property(edge, name);
let written = match self.edge_weight_mut(edge) {
Some(edge_ref) => {
let properties = edge_ref.2.get_or_insert_with(PropertyMap::default);
write_path_in(properties, path, value)
}
None => Err(GraphError::edge_removed()),
};
self.compression_normalize_edge_key(edge, name);
return written;
}
let (key, resulting) = {
let Some(edge_ref) = self.edge_weight(edge) else {
return Err(GraphError::edge_removed());
};
let schema = self.schema.read();
let value = crate::graph::schema::SchemaValidator::coerce_path_leaf(
&schema,
"edge",
edge_ref.1.as_slice(),
path,
value,
)?;
let existing = edge_ref
.2
.as_ref()
.and_then(|props| props.get(name.as_str()));
let (key, resulting) = write_path(existing, path, value)?;
crate::graph::schema::SchemaValidator::check_element_property(
&schema,
"edge",
edge_ref.1.as_slice(),
&key,
&resulting,
)?;
(key, resulting)
};
self.record_edge_property(edge, &key);
if let Some(edge_ref) = self.edge_weight_mut(edge) {
edge_ref
.2
.get_or_insert_with(PropertyMap::default)
.insert(key.clone(), resulting);
}
self.compression_normalize_edge_key(edge, &key);
Ok(())
}
fn remove_vertex_property_path(
&mut self,
node: VertexHandle,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(name) = single_segment_name(path) {
return self.drop_vertex_property(name, node);
}
let schema_off = matches!(
self.schema.read().mode,
crate::graph::schema::SchemaMode::None
);
if schema_off {
if let Some(crate::value::json_path::JsonPathSegment::Key(name)) =
path.segments().first()
&& self.vertex_weight(node).is_some_and(|vertex| {
crate::value::json_path::descend_properties(&vertex.2, path.segments())
.is_some()
})
{
self.record_vertex_property(node, name.as_str());
}
return match self.vertex_weight_mut(node) {
Some(vertex) => {
crate::graph::write_checks::remove_path_in(&mut vertex.2, path);
Ok(())
}
None => Err(GraphError::vertex_removed()),
};
}
let Some(vertex) = self.vertex_weight(node) else {
return Err(GraphError::vertex_removed());
};
let existing = match path.segments().first() {
Some(crate::value::json_path::JsonPathSegment::Key(name)) => {
vertex.2.get(name.as_str())
}
_ => None,
};
match remove_path(existing, path) {
Some((key, resulting)) => {
crate::graph::schema::SchemaValidator::check_element_property(
&self.schema.read(),
"vertex",
&vertex.1,
&key,
&resulting,
)?;
self.record_vertex_property(node, &key);
if let Some(vertex) = self.vertex_weight_mut(node) {
vertex.2.insert(key, resulting);
}
Ok(())
}
None => Ok(()),
}
}
fn remove_edge_property_path(
&mut self,
edge: EdgeHandle,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(name) = single_segment_name(path) {
return self.drop_edge_property(name, edge);
}
let schema_off = matches!(
self.schema.read().mode,
crate::graph::schema::SchemaMode::None
);
if schema_off {
if let Some(crate::value::json_path::JsonPathSegment::Key(name)) =
path.segments().first()
&& self.edge_weight(edge).is_some_and(|edge_ref| {
edge_ref.2.as_ref().is_some_and(|properties| {
crate::value::json_path::descend_properties(properties, path.segments())
.is_some()
})
})
{
self.record_edge_property(edge, name.as_str());
}
return match self.edge_weight_mut(edge) {
Some(edge_ref) => {
if let Some(properties) = edge_ref.2.as_mut() {
crate::graph::write_checks::remove_path_in(properties, path);
}
Ok(())
}
None => Err(GraphError::edge_removed()),
};
}
let Some(edge_ref) = self.edge_weight(edge) else {
return Err(GraphError::edge_removed());
};
let existing = match (path.segments().first(), edge_ref.2.as_ref()) {
(Some(crate::value::json_path::JsonPathSegment::Key(name)), Some(props)) => {
props.get(name.as_str())
}
_ => None,
};
match remove_path(existing, path) {
Some((key, resulting)) => {
crate::graph::schema::SchemaValidator::check_element_property(
&self.schema.read(),
"edge",
edge_ref.1.as_slice(),
&key,
&resulting,
)?;
self.record_edge_property(edge, &key);
if let Some(edge_ref) = self.edge_weight_mut(edge) {
edge_ref
.2
.get_or_insert_with(PropertyMap::default)
.insert(key, resulting);
}
Ok(())
}
None => Ok(()),
}
}
#[inline]
fn drop_vertex(&mut self, node: VertexHandle) -> Result<(), GraphError> {
let capture = self.undo.is_recording();
if let Some(entry) = self.remove_vertex_raw(node, capture) {
self.undo.record(entry);
}
Ok(())
}
#[inline]
fn drop_vertex_property(&mut self, prop: &str, node: VertexHandle) -> Result<(), GraphError> {
if let Some(vertex) = self.vertex_weight(node)
&& vertex.2.contains_key(prop)
{
crate::graph::schema::SchemaValidator::check_removal(
&self.schema.read(),
"vertex",
&vertex.1,
prop,
)?;
}
let recording = self.undo.is_recording();
let entry = match self.vertex_weight_mut(node) {
Some(vertex) => vertex
.2
.0
.shift_remove_full(prop)
.filter(|_| recording)
.map(|(position, key, value)| UndoEntry::VertexProperty {
id: vertex.0.clone(),
key,
old: Some((position, value)),
}),
None => return Err(GraphError::vertex_removed()),
};
if let Some(entry) = entry {
self.undo.record(entry);
}
Ok(())
}
#[inline]
fn drop_edge(&mut self, edge: EdgeHandle) -> Result<(), GraphError> {
let capture = self.undo.is_recording();
if let Some(image) = self.remove_edge_raw(edge, capture) {
self.undo.record(UndoEntry::DroppedEdge(Box::new(image)));
}
Ok(())
}
#[inline]
fn drop_edge_property(&mut self, prop: &str, edge: EdgeHandle) -> Result<(), GraphError> {
if let Some(edge_weight) = self.edge_weight(edge)
&& edge_weight.2.as_ref().is_some_and(|p| p.contains_key(prop))
{
crate::graph::schema::SchemaValidator::check_removal(
&self.schema.read(),
"edge",
edge_weight.1.as_slice(),
prop,
)?;
}
let recording = self.undo.is_recording();
let entry = match self.edge_weight_mut(edge) {
Some(edge_weight) => edge_weight
.2
.as_mut()
.and_then(|props| props.0.shift_remove_full(prop))
.filter(|_| recording)
.map(|(position, key, value)| UndoEntry::EdgeProperty {
id: edge_weight.0.clone(),
key,
old: Some((position, value)),
map_was_none: false,
}),
None => return Err(GraphError::edge_removed()),
};
if let Some(entry) = entry {
self.undo.record(entry);
}
Ok(())
}
#[inline]
fn set_schema(&mut self, schema: GraphSchema) -> Result<(), GraphError> {
self.in_own_unit(|this| this.set_schema_recorded(schema))
}
#[inline]
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
self.definitions.iter()
}
#[inline]
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
self.definitions.get(kind, name)
}
fn set_definition(&mut self, definition: Definition) -> Result<(), GraphError> {
self.in_own_unit(|this| this.set_definition_recorded(definition))
}
fn remove_definition(&mut self, kind: DefinitionKind, name: &str) -> Result<bool, GraphError> {
self.in_own_unit(|this| Ok(this.remove_definition_recorded(kind, name)))
}
fn recompress(&mut self, name: &str) -> Result<bool, GraphError> {
Ok(self.recompress_rule(name))
}
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
TraversalGraph::compression_stats(self, name)
}
#[inline]
fn get_schema(&self) -> Option<GraphSchema> {
let active = self.schema.read();
(!active.is_empty()).then(|| active.clone())
}
#[inline]
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
self.schema
.read()
.declared_property(kind, labels, key)
.cloned()
}
#[inline]
fn shrink_to_fit(&mut self) {
self.shrink_to_fit();
}
#[inline]
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
Some(crate::graph::memory::compute(self))
}
#[inline]
fn memory_footprint_bytes(&self) -> Option<u64> {
Some(crate::graph::memory::footprint_bytes(self))
}
#[inline]
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
self.execution_policy.clone()
}
#[inline]
fn begin_unit(&mut self) -> UnitMark {
self.begin_undo_unit()
}
#[inline]
fn commit_unit(&mut self, mark: UnitMark) -> Result<(), GraphError> {
self.commit_undo_unit(mark)
}
#[inline]
fn rollback_unit(&mut self, mark: UnitMark, reason: &RollbackReason) {
self.rollback_undo_unit(mark, reason);
}
#[inline]
fn unit_changes(&self, mark: UnitMark) -> UnitChanges {
self.undo_unit_changes(mark)
}
fn set_unit_metadata(&mut self, metadata: CommitMetadata) {
self.set_undo_metadata(metadata);
}
fn discard_unit(&mut self, mark: UnitMark) -> Result<ChangeSet, GraphError> {
Ok(self.discard_undo_unit_with_changes(mark))
}
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
self.journal_mark(name)
}
#[inline]
fn capabilities(&self) -> StorageCapabilities {
TRAVERSAL_GRAPH_CAPABILITIES
}
fn register_commit_hook(
&mut self,
hook: Box<dyn crate::graph::CommitHook>,
) -> Result<(), GraphError> {
self.undo.hooks.register(hook);
Ok(())
}
#[inline]
fn last_commit_seq(&self) -> u64 {
self.commit_seq()
}
#[inline]
fn raise_id_sequences(
&mut self,
node_sequence: u64,
edge_sequence: u64,
) -> Result<(), GraphError> {
if node_sequence > self.node_sequence || edge_sequence > self.edge_sequence {
self.node_sequence = self.node_sequence.max(node_sequence);
self.edge_sequence = self.edge_sequence.max(edge_sequence);
if self.undo.is_recording() {
self.undo.mark_sequences_raised();
}
}
Ok(())
}
}
impl TraversalGraph {
fn in_own_unit<T>(
&mut self,
change: impl FnOnce(&mut Self) -> Result<T, GraphError>,
) -> Result<T, GraphError> {
if self.undo.is_recording() || self.undo.loading {
return change(self);
}
let mark = self.begin_undo_unit();
let changed = close_on_unwind(self, change, |this| {
this.rollback_undo_unit(mark, &RollbackReason::failed(&UNWOUND))
});
match changed {
Ok(value) => {
self.commit_undo_unit(mark)?;
Ok(value)
}
Err(err) => {
self.rollback_undo_unit(mark, &RollbackReason::failed(&err));
Err(err)
}
}
}
}
const TRAVERSAL_GRAPH_CAPABILITIES: StorageCapabilities = StorageCapabilities::none()
.with_atomic(true)
.with_change_capture(true)
.with_isolation(IsolationLevel::None)
.with_writable(true);
#[inline]
fn read_only_view_error() -> GraphError {
GraphError::InvalidElementState {
reason: "Cannot mutate immutable graph reference".to_string(),
}
}
impl<G: GraphStorage> GraphStorage for &G {
type VertexId = G::VertexId;
type EdgeId = G::EdgeId;
#[inline]
fn vertex_count(&self) -> usize {
(**self).vertex_count()
}
#[inline]
fn edge_count(&self) -> usize {
(**self).edge_count()
}
#[inline]
fn vertices(&self) -> impl Iterator<Item = Self::VertexId> + '_ {
(**self).vertices()
}
#[inline]
fn edges(&self) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).edges()
}
#[inline]
fn get_vertex_by_id(&self, id: &str) -> Option<Self::VertexId> {
(**self).get_vertex_by_id(id)
}
#[inline]
fn get_edge_by_id(&self, id: &str) -> Option<Self::EdgeId> {
(**self).get_edge_by_id(id)
}
#[inline]
fn out_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).out_edges(node)
}
#[inline]
fn in_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).in_edges(node)
}
#[inline]
fn vertices_by_label<'b>(
&'b self,
label: &'b str,
) -> Box<dyn Iterator<Item = Self::VertexId> + 'b> {
(**self).vertices_by_label(label)
}
#[inline]
fn edges_by_label<'b>(&'b self, label: &'b str) -> Box<dyn Iterator<Item = Self::EdgeId> + 'b> {
(**self).edges_by_label(label)
}
#[inline]
fn vertex_id(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_id(node)
}
#[inline]
fn edge_id(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_id(edge)
}
#[inline]
fn vertex_label(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_label(node)
}
#[inline]
fn edge_label(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_label(edge)
}
#[inline]
fn vertex_labels(&self, node: Self::VertexId) -> &[CompactString] {
(**self).vertex_labels(node)
}
#[inline]
fn vertex_has_label(&self, node: Self::VertexId, label: &str) -> bool {
(**self).vertex_has_label(node, label)
}
#[inline]
fn vertex_properties(&self, node: Self::VertexId) -> Option<&PropertyMap> {
(**self).vertex_properties(node)
}
#[inline]
fn edge_properties(&self, edge: Self::EdgeId) -> Option<&PropertyMap> {
(**self).edge_properties(edge)
}
#[inline]
fn edge_endpoints(&self, edge: Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> {
(**self).edge_endpoints(edge)
}
#[inline]
fn contains_vertex(&self, node: Self::VertexId) -> bool {
(**self).contains_vertex(node)
}
#[inline]
fn contains_edge(&self, edge: Self::EdgeId) -> bool {
(**self).contains_edge(edge)
}
#[inline]
fn statistics(&self) -> Option<&GraphStatistics> {
(**self).statistics()
}
#[inline]
fn add_vertex(
&mut self,
_id: Option<CompactString>,
_labels: Vec<CompactString>,
_properties: PropertyMap,
) -> Result<Self::VertexId, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn add_vertex_label(
&mut self,
_node: Self::VertexId,
_label: CompactString,
) -> Result<bool, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn remove_vertex_label(
&mut self,
_node: Self::VertexId,
_label: &str,
) -> Result<bool, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn set_edge_label(
&mut self,
_edge: Self::EdgeId,
_label: CompactString,
) -> Result<bool, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn add_edge(
&mut self,
_id: Option<CompactString>,
_label: Option<CompactString>,
_from: Self::VertexId,
_to: Self::VertexId,
_properties: PropertyMap,
) -> Result<Self::EdgeId, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn set_vertex_property(
&mut self,
_node: Self::VertexId,
_key: CompactString,
_value: ElementProperty,
) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn set_edge_property(
&mut self,
_edge: Self::EdgeId,
_key: CompactString,
_value: ElementProperty,
) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn drop_vertex(&mut self, _node: Self::VertexId) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn drop_vertex_property(
&mut self,
_prop: &str,
_node: Self::VertexId,
) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn drop_edge(&mut self, _edge: Self::EdgeId) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn drop_edge_property(&mut self, _prop: &str, _edge: Self::EdgeId) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn set_schema(&mut self, _schema: GraphSchema) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn get_schema(&self) -> Option<GraphSchema> {
(**self).get_schema()
}
#[inline]
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
(**self).definitions()
}
#[inline]
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
(**self).definition(kind, name)
}
#[inline]
fn set_definition(&mut self, _definition: Definition) -> Result<(), GraphError> {
Err(read_only_view_error())
}
#[inline]
fn remove_definition(
&mut self,
_kind: DefinitionKind,
_name: &str,
) -> Result<bool, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn recompress(&mut self, _name: &str) -> Result<bool, GraphError> {
Err(read_only_view_error())
}
#[inline]
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
(**self).compression_stats(name)
}
#[inline]
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
(**self).declared_property_schema(kind, labels, key)
}
#[inline]
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
(**self).memory_usage()
}
#[inline]
fn memory_footprint_bytes(&self) -> Option<u64> {
(**self).memory_footprint_bytes()
}
#[inline]
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
(**self).execution_policy()
}
#[inline]
fn capabilities(&self) -> StorageCapabilities {
StorageCapabilities::none()
}
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
let _ = name;
Err(GraphError::Unsupported {
operation: READ_ONLY_MARK,
})
}
#[inline]
fn last_commit_seq(&self) -> u64 {
(**self).last_commit_seq()
}
}
impl<G: GraphStorage> GraphStorage for Box<G> {
type VertexId = G::VertexId;
type EdgeId = G::EdgeId;
#[inline]
fn vertex_count(&self) -> usize {
(**self).vertex_count()
}
#[inline]
fn edge_count(&self) -> usize {
(**self).edge_count()
}
#[inline]
fn vertices(&self) -> impl Iterator<Item = Self::VertexId> + '_ {
(**self).vertices()
}
#[inline]
fn edges(&self) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).edges()
}
#[inline]
fn get_vertex_by_id(&self, id: &str) -> Option<Self::VertexId> {
(**self).get_vertex_by_id(id)
}
#[inline]
fn get_edge_by_id(&self, id: &str) -> Option<Self::EdgeId> {
(**self).get_edge_by_id(id)
}
#[inline]
fn out_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).out_edges(node)
}
#[inline]
fn in_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).in_edges(node)
}
#[inline]
fn vertices_by_label<'b>(
&'b self,
label: &'b str,
) -> Box<dyn Iterator<Item = Self::VertexId> + 'b> {
(**self).vertices_by_label(label)
}
#[inline]
fn edges_by_label<'b>(&'b self, label: &'b str) -> Box<dyn Iterator<Item = Self::EdgeId> + 'b> {
(**self).edges_by_label(label)
}
#[inline]
fn vertex_id(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_id(node)
}
#[inline]
fn edge_id(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_id(edge)
}
#[inline]
fn vertex_label(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_label(node)
}
#[inline]
fn edge_label(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_label(edge)
}
#[inline]
fn vertex_labels(&self, node: Self::VertexId) -> &[CompactString] {
(**self).vertex_labels(node)
}
#[inline]
fn vertex_properties(&self, node: Self::VertexId) -> Option<&PropertyMap> {
(**self).vertex_properties(node)
}
#[inline]
fn edge_properties(&self, edge: Self::EdgeId) -> Option<&PropertyMap> {
(**self).edge_properties(edge)
}
#[inline]
fn edge_endpoints(&self, edge: Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> {
(**self).edge_endpoints(edge)
}
#[inline]
fn contains_vertex(&self, node: Self::VertexId) -> bool {
(**self).contains_vertex(node)
}
#[inline]
fn contains_edge(&self, edge: Self::EdgeId) -> bool {
(**self).contains_edge(edge)
}
#[inline]
fn statistics(&self) -> Option<&GraphStatistics> {
(**self).statistics()
}
#[inline]
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
properties: PropertyMap,
) -> Result<Self::VertexId, GraphError> {
(**self).add_vertex(id, labels, properties)
}
#[inline]
fn add_vertex_label(
&mut self,
node: Self::VertexId,
label: CompactString,
) -> Result<bool, GraphError> {
(**self).add_vertex_label(node, label)
}
#[inline]
fn remove_vertex_label(
&mut self,
node: Self::VertexId,
label: &str,
) -> Result<bool, GraphError> {
(**self).remove_vertex_label(node, label)
}
#[inline]
fn set_edge_label(
&mut self,
edge: Self::EdgeId,
label: CompactString,
) -> Result<bool, GraphError> {
(**self).set_edge_label(edge, label)
}
#[inline]
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: Self::VertexId,
to: Self::VertexId,
properties: PropertyMap,
) -> Result<Self::EdgeId, GraphError> {
(**self).add_edge(id, label, from, to, properties)
}
#[inline]
fn set_vertex_property(
&mut self,
node: Self::VertexId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_vertex_property(node, key, value)
}
#[inline]
fn set_edge_property(
&mut self,
edge: Self::EdgeId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_edge_property(edge, key, value)
}
#[inline]
fn set_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_vertex_property_path(node, path, value)
}
#[inline]
fn set_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_edge_property_path(edge, path, value)
}
#[inline]
fn remove_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
(**self).remove_vertex_property_path(node, path)
}
#[inline]
fn remove_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
(**self).remove_edge_property_path(edge, path)
}
#[inline]
fn drop_vertex(&mut self, node: Self::VertexId) -> Result<(), GraphError> {
(**self).drop_vertex(node)
}
#[inline]
fn drop_vertex_property(&mut self, prop: &str, node: Self::VertexId) -> Result<(), GraphError> {
(**self).drop_vertex_property(prop, node)
}
#[inline]
fn drop_edge(&mut self, edge: Self::EdgeId) -> Result<(), GraphError> {
(**self).drop_edge(edge)
}
#[inline]
fn drop_edge_property(&mut self, prop: &str, edge: Self::EdgeId) -> Result<(), GraphError> {
(**self).drop_edge_property(prop, edge)
}
#[inline]
fn set_schema(&mut self, schema: GraphSchema) -> Result<(), GraphError> {
(**self).set_schema(schema)
}
#[inline]
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
(**self).definitions()
}
#[inline]
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
(**self).definition(kind, name)
}
#[inline]
fn set_definition(&mut self, definition: Definition) -> Result<(), GraphError> {
(**self).set_definition(definition)
}
#[inline]
fn remove_definition(&mut self, kind: DefinitionKind, name: &str) -> Result<bool, GraphError> {
(**self).remove_definition(kind, name)
}
#[inline]
fn recompress(&mut self, name: &str) -> Result<bool, GraphError> {
(**self).recompress(name)
}
#[inline]
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
(**self).compression_stats(name)
}
#[inline]
fn get_schema(&self) -> Option<GraphSchema> {
(**self).get_schema()
}
#[inline]
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
(**self).declared_property_schema(kind, labels, key)
}
#[inline]
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
(**self).memory_usage()
}
#[inline]
fn memory_footprint_bytes(&self) -> Option<u64> {
(**self).memory_footprint_bytes()
}
#[inline]
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
(**self).execution_policy()
}
#[inline]
fn begin_unit(&mut self) -> UnitMark {
(**self).begin_unit()
}
#[inline]
fn commit_unit(&mut self, mark: UnitMark) -> Result<(), GraphError> {
(**self).commit_unit(mark)
}
#[inline]
fn rollback_unit(&mut self, mark: UnitMark, reason: &RollbackReason) {
(**self).rollback_unit(mark, reason);
}
#[inline]
fn unit_changes(&self, mark: UnitMark) -> UnitChanges {
(**self).unit_changes(mark)
}
#[inline]
fn set_unit_metadata(&mut self, metadata: CommitMetadata) {
(**self).set_unit_metadata(metadata);
}
#[inline]
fn discard_unit(&mut self, mark: UnitMark) -> Result<ChangeSet, GraphError> {
(**self).discard_unit(mark)
}
#[inline]
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
(**self).mark(name)
}
#[inline]
fn capabilities(&self) -> StorageCapabilities {
(**self).capabilities()
}
#[inline]
fn register_commit_hook(
&mut self,
hook: Box<dyn crate::graph::CommitHook>,
) -> Result<(), GraphError> {
(**self).register_commit_hook(hook)
}
#[inline]
fn last_commit_seq(&self) -> u64 {
(**self).last_commit_seq()
}
#[inline]
fn raise_id_sequences(
&mut self,
node_sequence: u64,
edge_sequence: u64,
) -> Result<(), GraphError> {
(**self).raise_id_sequences(node_sequence, edge_sequence)
}
#[inline]
fn apply_change_set(&mut self, changes: &ChangeSet) -> Result<(), GraphError> {
(**self).apply_change_set(changes)
}
}
impl<G: GraphStorage> GraphStorage for &mut G {
type VertexId = G::VertexId;
type EdgeId = G::EdgeId;
#[inline]
fn vertex_count(&self) -> usize {
(**self).vertex_count()
}
#[inline]
fn edge_count(&self) -> usize {
(**self).edge_count()
}
#[inline]
fn vertices(&self) -> impl Iterator<Item = Self::VertexId> + '_ {
(**self).vertices()
}
#[inline]
fn edges(&self) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).edges()
}
#[inline]
fn get_vertex_by_id(&self, id: &str) -> Option<Self::VertexId> {
(**self).get_vertex_by_id(id)
}
#[inline]
fn get_edge_by_id(&self, id: &str) -> Option<Self::EdgeId> {
(**self).get_edge_by_id(id)
}
#[inline]
fn out_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).out_edges(node)
}
#[inline]
fn in_edges(&self, node: Self::VertexId) -> impl Iterator<Item = Self::EdgeId> + '_ {
(**self).in_edges(node)
}
#[inline]
fn vertices_by_label<'b>(
&'b self,
label: &'b str,
) -> Box<dyn Iterator<Item = Self::VertexId> + 'b> {
(**self).vertices_by_label(label)
}
#[inline]
fn edges_by_label<'b>(&'b self, label: &'b str) -> Box<dyn Iterator<Item = Self::EdgeId> + 'b> {
(**self).edges_by_label(label)
}
#[inline]
fn vertex_id(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_id(node)
}
#[inline]
fn edge_id(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_id(edge)
}
#[inline]
fn vertex_label(&self, node: Self::VertexId) -> Option<&str> {
(**self).vertex_label(node)
}
#[inline]
fn edge_label(&self, edge: Self::EdgeId) -> Option<&str> {
(**self).edge_label(edge)
}
#[inline]
fn vertex_labels(&self, node: Self::VertexId) -> &[CompactString] {
(**self).vertex_labels(node)
}
#[inline]
fn vertex_properties(&self, node: Self::VertexId) -> Option<&PropertyMap> {
(**self).vertex_properties(node)
}
#[inline]
fn edge_properties(&self, edge: Self::EdgeId) -> Option<&PropertyMap> {
(**self).edge_properties(edge)
}
#[inline]
fn edge_endpoints(&self, edge: Self::EdgeId) -> Option<(Self::VertexId, Self::VertexId)> {
(**self).edge_endpoints(edge)
}
#[inline]
fn contains_vertex(&self, node: Self::VertexId) -> bool {
(**self).contains_vertex(node)
}
#[inline]
fn contains_edge(&self, edge: Self::EdgeId) -> bool {
(**self).contains_edge(edge)
}
#[inline]
fn statistics(&self) -> Option<&GraphStatistics> {
(**self).statistics()
}
#[inline]
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
properties: PropertyMap,
) -> Result<Self::VertexId, GraphError> {
(**self).add_vertex(id, labels, properties)
}
#[inline]
fn add_vertex_label(
&mut self,
node: Self::VertexId,
label: CompactString,
) -> Result<bool, GraphError> {
(**self).add_vertex_label(node, label)
}
#[inline]
fn remove_vertex_label(
&mut self,
node: Self::VertexId,
label: &str,
) -> Result<bool, GraphError> {
(**self).remove_vertex_label(node, label)
}
#[inline]
fn set_edge_label(
&mut self,
edge: Self::EdgeId,
label: CompactString,
) -> Result<bool, GraphError> {
(**self).set_edge_label(edge, label)
}
#[inline]
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: Self::VertexId,
to: Self::VertexId,
properties: PropertyMap,
) -> Result<Self::EdgeId, GraphError> {
(**self).add_edge(id, label, from, to, properties)
}
#[inline]
fn set_vertex_property(
&mut self,
node: Self::VertexId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_vertex_property(node, key, value)
}
#[inline]
fn set_edge_property(
&mut self,
edge: Self::EdgeId,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_edge_property(edge, key, value)
}
#[inline]
fn set_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_vertex_property_path(node, path, value)
}
#[inline]
fn set_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
(**self).set_edge_property_path(edge, path, value)
}
#[inline]
fn remove_vertex_property_path(
&mut self,
node: Self::VertexId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
(**self).remove_vertex_property_path(node, path)
}
#[inline]
fn remove_edge_property_path(
&mut self,
edge: Self::EdgeId,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
(**self).remove_edge_property_path(edge, path)
}
#[inline]
fn drop_vertex(&mut self, node: Self::VertexId) -> Result<(), GraphError> {
(**self).drop_vertex(node)
}
#[inline]
fn drop_vertex_property(&mut self, prop: &str, node: Self::VertexId) -> Result<(), GraphError> {
(**self).drop_vertex_property(prop, node)
}
#[inline]
fn drop_edge(&mut self, edge: Self::EdgeId) -> Result<(), GraphError> {
(**self).drop_edge(edge)
}
#[inline]
fn drop_edge_property(&mut self, prop: &str, edge: Self::EdgeId) -> Result<(), GraphError> {
(**self).drop_edge_property(prop, edge)
}
#[inline]
fn set_schema(&mut self, schema: GraphSchema) -> Result<(), GraphError> {
(**self).set_schema(schema)
}
#[inline]
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
(**self).definitions()
}
#[inline]
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
(**self).definition(kind, name)
}
#[inline]
fn set_definition(&mut self, definition: Definition) -> Result<(), GraphError> {
(**self).set_definition(definition)
}
#[inline]
fn remove_definition(&mut self, kind: DefinitionKind, name: &str) -> Result<bool, GraphError> {
(**self).remove_definition(kind, name)
}
#[inline]
fn recompress(&mut self, name: &str) -> Result<bool, GraphError> {
(**self).recompress(name)
}
#[inline]
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
(**self).compression_stats(name)
}
#[inline]
fn get_schema(&self) -> Option<GraphSchema> {
(**self).get_schema()
}
#[inline]
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
(**self).declared_property_schema(kind, labels, key)
}
#[inline]
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
(**self).memory_usage()
}
#[inline]
fn memory_footprint_bytes(&self) -> Option<u64> {
(**self).memory_footprint_bytes()
}
#[inline]
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
(**self).execution_policy()
}
#[inline]
fn begin_unit(&mut self) -> UnitMark {
(**self).begin_unit()
}
#[inline]
fn commit_unit(&mut self, mark: UnitMark) -> Result<(), GraphError> {
(**self).commit_unit(mark)
}
#[inline]
fn rollback_unit(&mut self, mark: UnitMark, reason: &RollbackReason) {
(**self).rollback_unit(mark, reason);
}
#[inline]
fn unit_changes(&self, mark: UnitMark) -> UnitChanges {
(**self).unit_changes(mark)
}
#[inline]
fn set_unit_metadata(&mut self, metadata: CommitMetadata) {
(**self).set_unit_metadata(metadata);
}
#[inline]
fn discard_unit(&mut self, mark: UnitMark) -> Result<ChangeSet, GraphError> {
(**self).discard_unit(mark)
}
#[inline]
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
(**self).mark(name)
}
#[inline]
fn capabilities(&self) -> StorageCapabilities {
(**self).capabilities()
}
#[inline]
fn register_commit_hook(
&mut self,
hook: Box<dyn crate::graph::CommitHook>,
) -> Result<(), GraphError> {
(**self).register_commit_hook(hook)
}
#[inline]
fn last_commit_seq(&self) -> u64 {
(**self).last_commit_seq()
}
#[inline]
fn raise_id_sequences(
&mut self,
node_sequence: u64,
edge_sequence: u64,
) -> Result<(), GraphError> {
(**self).raise_id_sequences(node_sequence, edge_sequence)
}
#[inline]
fn apply_change_set(&mut self, changes: &ChangeSet) -> Result<(), GraphError> {
(**self).apply_change_set(changes)
}
}
impl GraphStorage for Arc<TraversalGraph> {
type VertexId = VertexHandle;
type EdgeId = EdgeHandle;
#[inline]
fn vertex_count(&self) -> usize {
self.as_ref().vertex_count()
}
#[inline]
fn edge_count(&self) -> usize {
self.as_ref().edge_count()
}
#[inline]
fn vertices(&self) -> impl Iterator<Item = VertexHandle> + '_ {
GraphStorage::vertices(self.as_ref())
}
#[inline]
fn edges(&self) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::edges(self.as_ref())
}
#[inline]
fn get_vertex_by_id(&self, id: &str) -> Option<VertexHandle> {
GraphStorage::get_vertex_by_id(self.as_ref(), id)
}
#[inline]
fn get_edge_by_id(&self, id: &str) -> Option<EdgeHandle> {
GraphStorage::get_edge_by_id(self.as_ref(), id)
}
#[inline]
fn out_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::out_edges(self.as_ref(), node)
}
#[inline]
fn in_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::in_edges(self.as_ref(), node)
}
#[inline]
fn vertex_id(&self, node: VertexHandle) -> Option<&str> {
self.as_ref().vertex_id(node)
}
#[inline]
fn edge_id(&self, edge: EdgeHandle) -> Option<&str> {
self.as_ref().edge_id(edge)
}
#[inline]
fn vertex_label(&self, node: VertexHandle) -> Option<&str> {
self.as_ref().vertex_label(node)
}
#[inline]
fn edge_label(&self, edge: EdgeHandle) -> Option<&str> {
self.as_ref().edge_label(edge)
}
#[inline]
fn vertex_labels(&self, node: VertexHandle) -> &[CompactString] {
self.as_ref().vertex_labels(node)
}
#[inline]
fn vertex_properties(&self, node: VertexHandle) -> Option<&PropertyMap> {
self.as_ref().vertex_properties(node)
}
#[inline]
fn edge_properties(&self, edge: EdgeHandle) -> Option<&PropertyMap> {
self.as_ref().edge_properties(edge)
}
#[inline]
fn edge_endpoints(&self, edge: EdgeHandle) -> Option<(VertexHandle, VertexHandle)> {
self.as_ref().edge_endpoints(edge)
}
#[inline]
fn contains_vertex(&self, node: VertexHandle) -> bool {
self.as_ref().contains_vertex(node)
}
#[inline]
fn contains_edge(&self, edge: EdgeHandle) -> bool {
self.as_ref().contains_edge(edge)
}
#[inline]
fn vertices_by_label<'b>(
&'b self,
label: &'b str,
) -> Box<dyn Iterator<Item = VertexHandle> + 'b> {
self.as_ref().vertices_by_label(label)
}
#[inline]
fn edges_by_label<'b>(&'b self, label: &'b str) -> Box<dyn Iterator<Item = EdgeHandle> + 'b> {
self.as_ref().edges_by_label(label)
}
#[inline]
fn statistics(&self) -> Option<&GraphStatistics> {
self.as_ref().statistics()
}
#[inline]
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
properties: PropertyMap,
) -> Result<VertexHandle, GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::add_vertex(graph, id, labels, properties)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn add_vertex_label(
&mut self,
node: VertexHandle,
label: CompactString,
) -> Result<bool, GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::add_vertex_label(graph, node, label)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn remove_vertex_label(&mut self, node: VertexHandle, label: &str) -> Result<bool, GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::remove_vertex_label(graph, node, label)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_edge_label(
&mut self,
edge: EdgeHandle,
label: CompactString,
) -> Result<bool, GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_edge_label(graph, edge, label)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: VertexHandle,
to: VertexHandle,
properties: PropertyMap,
) -> Result<EdgeHandle, GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::add_edge(graph, id, label, from, to, properties)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_vertex_property(
&mut self,
node: VertexHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_vertex_property(graph, node, key, value)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_edge_property(
&mut self,
edge: EdgeHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_edge_property(graph, edge, key, value)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_vertex_property_path(
&mut self,
node: VertexHandle,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_vertex_property_path(graph, node, path, value)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_edge_property_path(
&mut self,
edge: EdgeHandle,
path: &crate::value::JsonPath,
value: ElementProperty,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_edge_property_path(graph, edge, path, value)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn remove_vertex_property_path(
&mut self,
node: VertexHandle,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::remove_vertex_property_path(graph, node, path)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn remove_edge_property_path(
&mut self,
edge: EdgeHandle,
path: &crate::value::JsonPath,
) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::remove_edge_property_path(graph, edge, path)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn drop_vertex(&mut self, node: VertexHandle) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::drop_vertex(graph, node)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn drop_vertex_property(&mut self, prop: &str, node: VertexHandle) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::drop_vertex_property(graph, prop, node)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn drop_edge(&mut self, edge: EdgeHandle) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::drop_edge(graph, edge)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn drop_edge_property(&mut self, prop: &str, edge: EdgeHandle) -> Result<(), GraphError> {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::drop_edge_property(graph, prop, edge)
} else {
Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
})
}
}
#[inline]
fn set_schema(&mut self, schema: GraphSchema) -> Result<(), GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::set_schema(graph, schema),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn definitions(&self) -> impl Iterator<Item = &Definition> + '_ {
self.as_ref().definitions.iter()
}
#[inline]
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<&Definition> {
self.as_ref().definitions.get(kind, name)
}
#[inline]
fn set_definition(&mut self, definition: Definition) -> Result<(), GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::set_definition(graph, definition),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn remove_definition(&mut self, kind: DefinitionKind, name: &str) -> Result<bool, GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::remove_definition(graph, kind, name),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn recompress(&mut self, name: &str) -> Result<bool, GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::recompress(graph, name),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn compression_stats(&self, name: &str) -> Option<crate::graph::CompressionStats> {
TraversalGraph::compression_stats(self, name)
}
#[inline]
fn get_schema(&self) -> Option<GraphSchema> {
self.as_ref().get_schema()
}
#[inline]
fn declared_property_schema(
&self,
kind: GraphNodeType,
labels: &[CompactString],
key: &str,
) -> Option<PropertySchema> {
self.as_ref().declared_property_schema(kind, labels, key)
}
#[inline]
fn memory_usage(&self) -> Option<crate::graph::MemoryStats> {
self.as_ref().memory_usage()
}
#[inline]
fn memory_footprint_bytes(&self) -> Option<u64> {
self.as_ref().memory_footprint_bytes()
}
#[inline]
fn execution_policy(&self) -> crate::graph::ExecutionPolicy {
self.as_ref().execution_policy()
}
#[inline]
fn begin_unit(&mut self) -> UnitMark {
Arc::get_mut(self).map_or_else(UnitMark::default, GraphStorage::begin_unit)
}
#[inline]
fn commit_unit(&mut self, mark: UnitMark) -> Result<(), GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::commit_unit(graph, mark),
None => Ok(()),
}
}
#[inline]
fn rollback_unit(&mut self, mark: UnitMark, reason: &RollbackReason) {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::rollback_unit(graph, mark, reason);
}
}
#[inline]
fn unit_changes(&self, mark: UnitMark) -> UnitChanges {
GraphStorage::unit_changes(self.as_ref(), mark)
}
#[inline]
fn set_unit_metadata(&mut self, metadata: CommitMetadata) {
if let Some(graph) = Arc::get_mut(self) {
GraphStorage::set_unit_metadata(graph, metadata);
}
}
#[inline]
fn discard_unit(&mut self, mark: UnitMark) -> Result<ChangeSet, GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::discard_unit(graph, mark),
None => Err(GraphError::Unsupported {
operation: DRY_RUN_OPERATION,
}),
}
}
#[inline]
fn mark(&mut self, name: &str) -> Result<Mark, GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::mark(graph, name),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn capabilities(&self) -> StorageCapabilities {
if Arc::strong_count(self) == 1 && Arc::weak_count(self) == 0 {
self.as_ref().capabilities()
} else {
StorageCapabilities::none()
}
}
#[inline]
fn register_commit_hook(
&mut self,
hook: Box<dyn crate::graph::CommitHook>,
) -> Result<(), GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::register_commit_hook(graph, hook),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
#[inline]
fn last_commit_seq(&self) -> u64 {
GraphStorage::last_commit_seq(self.as_ref())
}
#[inline]
fn raise_id_sequences(
&mut self,
node_sequence: u64,
edge_sequence: u64,
) -> Result<(), GraphError> {
match Arc::get_mut(self) {
Some(graph) => GraphStorage::raise_id_sequences(graph, node_sequence, edge_sequence),
None => Err(GraphError::InvalidElementState {
reason: "Cannot mutate shared Arc<TraversalGraph>".to_string(),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_generic_storage<S: GraphStorage>(storage: &S) {
assert_eq!(storage.vertex_count(), 2);
assert_eq!(storage.edge_count(), 1);
let v1 = storage.get_vertex_by_id("v1").expect("v1 should exist");
let v2 = storage.get_vertex_by_id("v2").expect("v2 should exist");
assert_eq!(storage.vertex_label(v1), Some("person"));
assert_eq!(storage.vertex_label(v2), Some("person"));
let e1 = storage.get_edge_by_id("e1").expect("e1 should exist");
assert_eq!(storage.edge_label(e1), Some("knows"));
assert_eq!(storage.edge_endpoints(e1), Some((v1, v2)));
let out_e: Vec<_> = storage.out_edges(v1).collect();
assert_eq!(out_e, vec![e1]);
let in_e: Vec<_> = storage.in_edges(v2).collect();
assert_eq!(in_e, vec![e1]);
}
fn build_test_graph() -> TraversalGraph {
let mut tg = TraversalGraph::new();
let v1 = tg
.add_vertex(
Some("v1".into()),
vec!["person".into()],
PropertyMap::default(),
)
.unwrap();
let v2 = tg
.add_vertex(
Some("v2".into()),
vec!["person".into()],
PropertyMap::default(),
)
.unwrap();
GraphStorage::add_edge(
&mut tg,
Some("e1".into()),
Some("knows".into()),
v1,
v2,
PropertyMap::default(),
)
.unwrap();
tg
}
#[test]
fn test_traversal_graph_storage() {
let mut graph = build_test_graph();
test_generic_storage(&graph);
let v3 = graph
.add_vertex(
Some("v3".into()),
vec!["software".into()],
PropertyMap::default(),
)
.unwrap();
assert_eq!(graph.vertex_count(), 3);
assert_eq!(graph.vertex_label(v3), Some("software"));
}
#[test]
fn test_ref_traversal_graph_storage() {
let graph = build_test_graph();
let ref_graph: &TraversalGraph = &graph;
test_generic_storage(&ref_graph);
}
#[test]
fn test_arc_traversal_graph_storage() {
let graph = build_test_graph();
let arc_graph = Arc::new(graph);
test_generic_storage(&arc_graph);
}
#[test]
fn test_label_indexing_and_drop_lifecycle() {
let mut tg = TraversalGraph::new();
let v1 = tg
.add_vertex(
Some("v1".into()),
vec!["person".into()],
PropertyMap::default(),
)
.unwrap();
let v2 = tg
.add_vertex(
Some("v2".into()),
vec!["person".into()],
PropertyMap::default(),
)
.unwrap();
let v3 = tg
.add_vertex(
Some("v3".into()),
vec!["software".into()],
PropertyMap::default(),
)
.unwrap();
let e1 = tg
.add_edge(
Some("e1".into()),
Some("knows".into()),
v1,
v2,
PropertyMap::default(),
)
.unwrap();
let e2 = tg
.add_edge(
Some("e2".into()),
Some("created".into()),
v1,
v3,
PropertyMap::default(),
)
.unwrap();
let persons: Vec<_> = GraphStorage::vertices_by_label(&tg, "person").collect();
assert_eq!(persons, vec![v1, v2]);
let softwares: Vec<_> = GraphStorage::vertices_by_label(&tg, "software").collect();
assert_eq!(softwares, vec![v3]);
let unknown_v: Vec<_> = GraphStorage::vertices_by_label(&tg, "unknown").collect();
assert!(unknown_v.is_empty());
let knows_edges: Vec<_> = GraphStorage::edges_by_label(&tg, "knows").collect();
assert_eq!(knows_edges, vec![e1]);
let created_edges: Vec<_> = GraphStorage::edges_by_label(&tg, "created").collect();
assert_eq!(created_edges, vec![e2]);
let unknown_e: Vec<_> = GraphStorage::edges_by_label(&tg, "unknown").collect();
assert!(unknown_e.is_empty());
let stats = tg.statistics().expect("TraversalGraph keeps statistics");
assert_eq!(stats.vertex_label_count("person"), 2);
assert_eq!(stats.vertex_label_count("software"), 1);
assert_eq!(stats.edge_label_count("knows"), 1);
assert_eq!(stats.edge_label_count("created"), 1);
assert_eq!(stats, &GraphStatistics::from_storage(&tg));
{
let ref_tg: &TraversalGraph = &tg;
assert_eq!(
ref_tg.vertices_by_label("person").collect::<Vec<_>>(),
vec![v1, v2]
);
assert_eq!(ref_tg.edges_by_label("knows").collect::<Vec<_>>(), vec![e1]);
let boxed: Box<&TraversalGraph> = Box::new(ref_tg);
assert_eq!(
boxed.vertices_by_label("person").collect::<Vec<_>>(),
vec![v1, v2]
);
assert_eq!(boxed.edges_by_label("knows").collect::<Vec<_>>(), vec![e1]);
}
tg.drop_edge(e1).unwrap();
let knows_after_drop: Vec<_> = GraphStorage::edges_by_label(&tg, "knows").collect();
assert!(knows_after_drop.is_empty());
assert_eq!(
GraphStorage::edges_by_label(&tg, "created").collect::<Vec<_>>(),
vec![e2]
);
tg.drop_vertex(v2).unwrap();
let persons_after_drop: Vec<_> = GraphStorage::vertices_by_label(&tg, "person").collect();
assert_eq!(persons_after_drop, vec![v1]);
tg.drop_vertex(v1).unwrap();
let persons_empty: Vec<_> = GraphStorage::vertices_by_label(&tg, "person").collect();
assert!(persons_empty.is_empty());
}
struct MockStorage {
tg: TraversalGraph,
}
impl GraphStorage for MockStorage {
type VertexId = VertexHandle;
type EdgeId = EdgeHandle;
fn vertex_count(&self) -> usize {
self.tg.vertex_count()
}
fn edge_count(&self) -> usize {
self.tg.edge_count()
}
fn vertices(&self) -> impl Iterator<Item = VertexHandle> + '_ {
GraphStorage::vertices(&self.tg)
}
fn edges(&self) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::edges(&self.tg)
}
fn get_vertex_by_id(&self, id: &str) -> Option<VertexHandle> {
GraphStorage::get_vertex_by_id(&self.tg, id)
}
fn get_edge_by_id(&self, id: &str) -> Option<EdgeHandle> {
GraphStorage::get_edge_by_id(&self.tg, id)
}
fn out_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::out_edges(&self.tg, node)
}
fn in_edges(&self, node: VertexHandle) -> impl Iterator<Item = EdgeHandle> + '_ {
GraphStorage::in_edges(&self.tg, node)
}
fn vertex_id(&self, node: VertexHandle) -> Option<&str> {
self.tg.vertex_id(node)
}
fn edge_id(&self, edge: EdgeHandle) -> Option<&str> {
self.tg.edge_id(edge)
}
fn vertex_label(&self, node: VertexHandle) -> Option<&str> {
self.tg.vertex_label(node)
}
fn edge_label(&self, edge: EdgeHandle) -> Option<&str> {
self.tg.edge_label(edge)
}
fn vertex_labels(&self, node: VertexHandle) -> &[CompactString] {
self.tg.vertex_labels(node)
}
fn vertex_properties(&self, node: VertexHandle) -> Option<&PropertyMap> {
self.tg.vertex_properties(node)
}
fn edge_properties(&self, edge: EdgeHandle) -> Option<&PropertyMap> {
self.tg.edge_properties(edge)
}
fn edge_endpoints(&self, edge: EdgeHandle) -> Option<(VertexHandle, VertexHandle)> {
self.tg.edge_endpoints(edge)
}
fn add_vertex(
&mut self,
id: Option<CompactString>,
labels: Vec<CompactString>,
properties: PropertyMap,
) -> Result<VertexHandle, GraphError> {
self.tg.add_vertex(id, labels, properties)
}
fn add_vertex_label(
&mut self,
node: VertexHandle,
label: CompactString,
) -> Result<bool, GraphError> {
self.tg.add_vertex_label(node, label)
}
fn remove_vertex_label(
&mut self,
node: VertexHandle,
label: &str,
) -> Result<bool, GraphError> {
self.tg.remove_vertex_label(node, label)
}
fn add_edge(
&mut self,
id: Option<CompactString>,
label: Option<CompactString>,
from: VertexHandle,
to: VertexHandle,
properties: PropertyMap,
) -> Result<EdgeHandle, GraphError> {
self.tg.add_edge(id, label, from, to, properties)
}
fn set_vertex_property(
&mut self,
node: VertexHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
self.tg.set_vertex_property(node, key, value)
}
fn set_edge_property(
&mut self,
edge: EdgeHandle,
key: CompactString,
value: ElementProperty,
) -> Result<(), GraphError> {
self.tg.set_edge_property(edge, key, value)
}
fn drop_vertex(&mut self, node: VertexHandle) -> Result<(), GraphError> {
self.tg.drop_vertex(node)
}
fn drop_vertex_property(
&mut self,
prop: &str,
node: VertexHandle,
) -> Result<(), GraphError> {
self.tg.drop_vertex_property(prop, node)
}
fn drop_edge(&mut self, edge: EdgeHandle) -> Result<(), GraphError> {
self.tg.drop_edge(edge)
}
fn drop_edge_property(&mut self, prop: &str, edge: EdgeHandle) -> Result<(), GraphError> {
self.tg.drop_edge_property(prop, edge)
}
fn capabilities(&self) -> StorageCapabilities {
StorageCapabilities::none().with_writable(true)
}
}
#[test]
fn mock_storage_defaults_reject_hooks_and_count_no_commits() {
let mut mock = MockStorage {
tg: build_test_graph(),
};
assert!(mock.capabilities().is_consistent());
assert!(!mock.capabilities().atomic);
struct Nop;
impl crate::graph::CommitHook for Nop {}
assert!(matches!(
mock.register_commit_hook(Box::new(Nop)),
Err(GraphError::Unsupported { .. })
));
let mark = mock.begin_unit();
mock.add_vertex(Some("m".into()), vec![], PropertyMap::default())
.expect("add");
mock.commit_unit(mark).expect("commit");
assert_eq!(GraphStorage::last_commit_seq(&mock), 0);
let query = Definition::query("q", crate::graph::QueryDefinition::new("fn q() { 1 }"));
assert!(matches!(
mock.set_definition(query),
Err(GraphError::Unsupported { .. })
));
assert!(matches!(
mock.remove_definition(DefinitionKind::QUERY, "q"),
Err(GraphError::Unsupported { .. })
));
assert_eq!(mock.definitions().count(), 0);
assert!(mock.definition(DefinitionKind::QUERY, "q").is_none());
}
#[test]
fn traversal_graph_capabilities_are_consistent() {
let graph = TraversalGraph::new();
let caps = GraphStorage::capabilities(&graph);
assert!(caps.atomic && caps.change_capture && caps.writable && !caps.immutable);
assert!(caps.is_consistent());
assert_eq!(
GraphStorage::capabilities(&&graph),
StorageCapabilities::none()
);
let shared = Arc::new(TraversalGraph::new());
assert_eq!(GraphStorage::capabilities(&shared), caps);
let second = shared.clone();
assert_eq!(
GraphStorage::capabilities(&shared),
StorageCapabilities::none()
);
drop(second);
}
#[test]
fn test_default_trait_label_filtering() {
let tg = build_test_graph();
let mock = MockStorage { tg };
let persons: Vec<_> = mock.vertices_by_label("person").collect();
assert_eq!(persons.len(), 2);
let unknown: Vec<_> = mock.vertices_by_label("non_existent").collect();
assert!(unknown.is_empty());
let knows: Vec<_> = mock.edges_by_label("knows").collect();
assert_eq!(knows.len(), 1);
let unknown_edges: Vec<_> = mock.edges_by_label("non_existent").collect();
assert!(unknown_edges.is_empty());
assert!(mock.statistics().is_none());
let stats = GraphStatistics::from_storage(&mock);
assert_eq!(stats.vertex_label_count("person"), 2);
assert_eq!(stats.edge_label_count("knows"), 1);
}
fn assert_send_sync<T: Send + Sync>() {}
#[test]
fn test_send_sync_bounds() {
assert_send_sync::<TraversalGraph>();
assert_send_sync::<Arc<TraversalGraph>>();
}
}