use std::collections::HashMap;
use std::sync::Arc;
pub mod cow;
pub mod interner;
#[cfg(feature = "mmap")]
pub mod mmap;
#[cfg(feature = "mmap")]
pub mod cow_mmap;
#[cfg(feature = "full-text")]
pub mod text;
#[cfg(all(feature = "reactive", not(target_arch = "wasm32")))]
pub mod events;
pub use cow::{BatchContext, BatchError, Graph, GraphMutWrapper, GraphSnapshot, GraphState};
pub use interner::StringInterner;
#[cfg(feature = "mmap")]
pub use mmap::MmapGraph;
#[cfg(feature = "mmap")]
pub use cow_mmap::{
BatchError as CowMmapBatchError, CowMmapBatchContext, CowMmapGraph, CowMmapSnapshot,
};
#[cfg(feature = "mmap")]
pub type PersistentGraph = CowMmapGraph;
#[cfg(feature = "mmap")]
pub type PersistentSnapshot = CowMmapSnapshot;
use crate::error::StorageError;
use crate::value::{EdgeId, Value, VertexId};
#[derive(Clone, Debug)]
pub struct Vertex {
pub id: VertexId,
pub label: String,
pub properties: HashMap<String, Value>,
}
#[derive(Clone, Debug)]
pub struct Edge {
pub id: EdgeId,
pub label: String,
pub src: VertexId,
pub dst: VertexId,
pub properties: HashMap<String, Value>,
}
pub trait GraphStorage: Send + Sync {
fn get_vertex(&self, id: VertexId) -> Option<Vertex>;
fn vertex_count(&self) -> u64;
fn get_edge(&self, id: EdgeId) -> Option<Edge>;
fn edge_count(&self) -> u64;
fn out_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = Edge> + '_>;
fn in_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = Edge> + '_>;
fn vertices_with_label(&self, label: &str) -> Box<dyn Iterator<Item = Vertex> + '_>;
fn edges_with_label(&self, label: &str) -> Box<dyn Iterator<Item = Edge> + '_>;
fn all_vertices(&self) -> Box<dyn Iterator<Item = Vertex> + '_>;
fn all_edges(&self) -> Box<dyn Iterator<Item = Edge> + '_>;
fn interner(&self) -> &StringInterner;
fn supports_indexes(&self) -> bool {
false
}
fn vertices_by_property(
&self,
label: Option<&str>,
property: &str,
value: &Value,
) -> Box<dyn Iterator<Item = Vertex> + '_> {
let label_owned = label.map(|s| s.to_string());
let property_owned = property.to_string();
let value_clone = value.clone();
Box::new(self.all_vertices().filter(move |v| {
if let Some(ref l) = label_owned {
if &v.label != l {
return false;
}
}
v.properties.get(&property_owned) == Some(&value_clone)
}))
}
fn edges_by_property(
&self,
label: Option<&str>,
property: &str,
value: &Value,
) -> Box<dyn Iterator<Item = Edge> + '_> {
let label_owned = label.map(|s| s.to_string());
let property_owned = property.to_string();
let value_clone = value.clone();
Box::new(self.all_edges().filter(move |e| {
if let Some(ref l) = label_owned {
if &e.label != l {
return false;
}
}
e.properties.get(&property_owned) == Some(&value_clone)
}))
}
fn vertices_by_property_range(
&self,
label: Option<&str>,
property: &str,
start: std::ops::Bound<&Value>,
end: std::ops::Bound<&Value>,
) -> Box<dyn Iterator<Item = Vertex> + '_> {
use std::ops::Bound;
let label_owned = label.map(|s| s.to_string());
let property_owned = property.to_string();
let start_clone = match start {
Bound::Included(v) => Bound::Included(v.clone()),
Bound::Excluded(v) => Bound::Excluded(v.clone()),
Bound::Unbounded => Bound::Unbounded,
};
let end_clone = match end {
Bound::Included(v) => Bound::Included(v.clone()),
Bound::Excluded(v) => Bound::Excluded(v.clone()),
Bound::Unbounded => Bound::Unbounded,
};
Box::new(self.all_vertices().filter(move |v| {
if let Some(ref l) = label_owned {
if &v.label != l {
return false;
}
}
if let Some(prop_value) = v.properties.get(&property_owned) {
let prop_cmp = prop_value.to_comparable();
let in_start = match &start_clone {
Bound::Included(s) => prop_cmp >= s.to_comparable(),
Bound::Excluded(s) => prop_cmp > s.to_comparable(),
Bound::Unbounded => true,
};
let in_end = match &end_clone {
Bound::Included(e) => prop_cmp <= e.to_comparable(),
Bound::Excluded(e) => prop_cmp < e.to_comparable(),
Bound::Unbounded => true,
};
in_start && in_end
} else {
false
}
}))
}
}
pub trait GraphStorageMut: GraphStorage {
fn add_vertex(&mut self, label: &str, properties: HashMap<String, Value>) -> VertexId;
fn add_edge(
&mut self,
src: VertexId,
dst: VertexId,
label: &str,
properties: HashMap<String, Value>,
) -> Result<EdgeId, StorageError>;
fn set_vertex_property(
&mut self,
id: VertexId,
key: &str,
value: Value,
) -> Result<(), StorageError>;
fn set_edge_property(
&mut self,
id: EdgeId,
key: &str,
value: Value,
) -> Result<(), StorageError>;
fn remove_vertex(&mut self, id: VertexId) -> Result<(), StorageError>;
fn remove_edge(&mut self, id: EdgeId) -> Result<(), StorageError>;
}
impl<T: GraphStorage + ?Sized> GraphStorage for Arc<T> {
fn get_vertex(&self, id: VertexId) -> Option<Vertex> {
(**self).get_vertex(id)
}
fn get_edge(&self, id: EdgeId) -> Option<Edge> {
(**self).get_edge(id)
}
fn vertex_count(&self) -> u64 {
(**self).vertex_count()
}
fn edge_count(&self) -> u64 {
(**self).edge_count()
}
fn all_vertices(&self) -> Box<dyn Iterator<Item = Vertex> + '_> {
(**self).all_vertices()
}
fn all_edges(&self) -> Box<dyn Iterator<Item = Edge> + '_> {
(**self).all_edges()
}
fn out_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = Edge> + '_> {
(**self).out_edges(vertex)
}
fn in_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = Edge> + '_> {
(**self).in_edges(vertex)
}
fn vertices_with_label(&self, label: &str) -> Box<dyn Iterator<Item = Vertex> + '_> {
(**self).vertices_with_label(label)
}
fn edges_with_label(&self, label: &str) -> Box<dyn Iterator<Item = Edge> + '_> {
(**self).edges_with_label(label)
}
fn interner(&self) -> &StringInterner {
(**self).interner()
}
fn vertices_by_property(
&self,
label: Option<&str>,
property: &str,
value: &Value,
) -> Box<dyn Iterator<Item = Vertex> + '_> {
(**self).vertices_by_property(label, property, value)
}
fn edges_by_property(
&self,
label: Option<&str>,
property: &str,
value: &Value,
) -> Box<dyn Iterator<Item = Edge> + '_> {
(**self).edges_by_property(label, property, value)
}
fn vertices_by_property_range(
&self,
label: Option<&str>,
property: &str,
start: std::ops::Bound<&Value>,
end: std::ops::Bound<&Value>,
) -> Box<dyn Iterator<Item = Vertex> + '_> {
(**self).vertices_by_property_range(label, property, start, end)
}
}
pub trait StreamableStorage: GraphStorage + 'static {
fn stream_all_vertices(&self) -> Box<dyn Iterator<Item = VertexId> + Send> {
let ids: Vec<_> = self.all_vertices().map(|v| v.id).collect();
Box::new(ids.into_iter())
}
fn stream_all_edges(&self) -> Box<dyn Iterator<Item = EdgeId> + Send> {
let ids: Vec<_> = self.all_edges().map(|e| e.id).collect();
Box::new(ids.into_iter())
}
fn stream_vertices_with_label(&self, label: &str) -> Box<dyn Iterator<Item = VertexId> + Send> {
let ids: Vec<_> = self.vertices_with_label(label).map(|v| v.id).collect();
Box::new(ids.into_iter())
}
fn stream_edges_with_label(&self, label: &str) -> Box<dyn Iterator<Item = EdgeId> + Send> {
let ids: Vec<_> = self.edges_with_label(label).map(|e| e.id).collect();
Box::new(ids.into_iter())
}
fn stream_out_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = EdgeId> + Send> {
let ids: Vec<_> = self.out_edges(vertex).map(|e| e.id).collect();
Box::new(ids.into_iter())
}
fn stream_in_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = EdgeId> + Send> {
let ids: Vec<_> = self.in_edges(vertex).map(|e| e.id).collect();
Box::new(ids.into_iter())
}
fn stream_out_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
let label_ids_owned: Vec<u32> = label_ids.to_vec();
let interner = self.interner().clone();
let neighbors: Vec<_> = self
.out_edges(vertex)
.filter(move |e| {
if label_ids_owned.is_empty() {
true
} else {
label_ids_owned
.iter()
.any(|&lid| interner.lookup(&e.label) == Some(lid))
}
})
.map(|e| e.dst)
.collect();
Box::new(neighbors.into_iter())
}
fn stream_in_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
let label_ids_owned: Vec<u32> = label_ids.to_vec();
let interner = self.interner().clone();
let neighbors: Vec<_> = self
.in_edges(vertex)
.filter(move |e| {
if label_ids_owned.is_empty() {
true
} else {
label_ids_owned
.iter()
.any(|&lid| interner.lookup(&e.label) == Some(lid))
}
})
.map(|e| e.src)
.collect();
Box::new(neighbors.into_iter())
}
fn stream_both_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
let out_iter = self.stream_out_neighbors(vertex, label_ids);
let in_iter = self.stream_in_neighbors(vertex, label_ids);
Box::new(out_iter.chain(in_iter))
}
}
impl<T: StreamableStorage + ?Sized> StreamableStorage for Arc<T> {
fn stream_all_vertices(&self) -> Box<dyn Iterator<Item = VertexId> + Send> {
(**self).stream_all_vertices()
}
fn stream_all_edges(&self) -> Box<dyn Iterator<Item = EdgeId> + Send> {
(**self).stream_all_edges()
}
fn stream_vertices_with_label(&self, label: &str) -> Box<dyn Iterator<Item = VertexId> + Send> {
(**self).stream_vertices_with_label(label)
}
fn stream_edges_with_label(&self, label: &str) -> Box<dyn Iterator<Item = EdgeId> + Send> {
(**self).stream_edges_with_label(label)
}
fn stream_out_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = EdgeId> + Send> {
(**self).stream_out_edges(vertex)
}
fn stream_in_edges(&self, vertex: VertexId) -> Box<dyn Iterator<Item = EdgeId> + Send> {
(**self).stream_in_edges(vertex)
}
fn stream_out_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
(**self).stream_out_neighbors(vertex, label_ids)
}
fn stream_in_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
(**self).stream_in_neighbors(vertex, label_ids)
}
fn stream_both_neighbors(
&self,
vertex: VertexId,
label_ids: &[u32],
) -> Box<dyn Iterator<Item = VertexId> + Send> {
(**self).stream_both_neighbors(vertex, label_ids)
}
}