use std::sync::{Arc, RwLock};
use crate::{
graph::{LogicalGraph, LogicalSnapshot},
schema::Schema,
store::traits::GraphStore,
types::{
element::Property,
gvalue::Primitive,
keys::{
AdjacentEdgeCursor, AdjacentEdgesOptions, BatchScenario, CanonicalEdgeKey, CanonicalKey, DegreeDirection,
LabelId, VertexKey,
},
prop_key::PropKey,
Direction, EdgeKey, StoreError,
},
};
pub trait GraphCtx {
#[allow(dead_code)]
fn get_vertex(&mut self, key: VertexKey) -> Result<Option<VertexKey>, StoreError>;
fn get_vertices(&mut self, keys: &[VertexKey]) -> Result<Vec<VertexKey>, StoreError>;
fn get_edge(&mut self, key: &EdgeKey) -> Result<Option<EdgeKey>, StoreError>;
fn get_edges(&mut self, keys: &[EdgeKey]) -> Result<Vec<EdgeKey>, StoreError>;
fn get_adjacent_edges(
&mut self,
vertex_key: VertexKey,
direction: Direction,
opts: AdjacentEdgesOptions<'_>,
limit: Option<u32>,
) -> Result<(Vec<EdgeKey>, Option<AdjacentEdgeCursor>), StoreError>;
fn scan_vertices(
&mut self,
label: Option<LabelId>,
start_from: Option<VertexKey>,
limit: u32,
) -> Result<(Vec<VertexKey>, Option<VertexKey>), StoreError>;
fn scan_edges(
&mut self,
label: Option<LabelId>,
start_from: Option<CanonicalEdgeKey>,
limit: u32,
) -> Result<(Vec<EdgeKey>, Option<CanonicalEdgeKey>), StoreError>;
fn get_property(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Property>, StoreError>;
fn get_value(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Primitive>, StoreError>;
fn add_vertex(&mut self, id: VertexKey, label_id: LabelId) -> Result<VertexKey, StoreError>;
fn add_edge(&mut self, cek: &EdgeKey) -> Result<EdgeKey, StoreError>;
fn set_property(&mut self, prop: &Property) -> Result<(), StoreError>;
fn drop_property(&mut self, prop: &Property) -> Result<(), StoreError>;
fn drop_vertex(&mut self, vertex: VertexKey) -> Result<(), StoreError>;
fn drop_edge(&mut self, edge: &EdgeKey) -> Result<(), StoreError>;
#[allow(clippy::type_complexity)]
fn get_all_props(&mut self, key: &CanonicalKey)
-> Result<Option<(LabelId, Vec<(PropKey, Primitive)>)>, StoreError>;
fn batch_size(&self, scenario: BatchScenario) -> u32;
fn get_degree(&mut self, key: VertexKey, direction: DegreeDirection) -> Result<u64, StoreError>;
fn schema(&self) -> Arc<RwLock<Schema>>;
}
#[cfg(test)]
pub struct NoopCtx;
#[cfg(test)]
impl GraphCtx for NoopCtx {
fn get_vertex(&mut self, _key: VertexKey) -> Result<Option<VertexKey>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_vertex".to_string()))
}
fn get_vertices(&mut self, _keys: &[VertexKey]) -> Result<Vec<VertexKey>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_vertices".to_string()))
}
fn get_edge(&mut self, _key: &EdgeKey) -> Result<Option<EdgeKey>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_edge".to_string()))
}
fn get_edges(&mut self, _keys: &[EdgeKey]) -> Result<Vec<EdgeKey>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_edges".to_string()))
}
fn get_adjacent_edges(
&mut self,
_vertex_key: VertexKey,
_direction: Direction,
_opts: AdjacentEdgesOptions<'_>,
_limit: Option<u32>,
) -> Result<(Vec<EdgeKey>, Option<AdjacentEdgeCursor>), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_adjacent_edges".to_string()))
}
fn scan_vertices(
&mut self,
_label: Option<LabelId>,
_start_from: Option<VertexKey>,
_limit: u32,
) -> Result<(Vec<VertexKey>, Option<VertexKey>), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support scan_vertices".to_string()))
}
fn scan_edges(
&mut self,
_label: Option<LabelId>,
_start_from: Option<CanonicalEdgeKey>,
_limit: u32,
) -> Result<(Vec<EdgeKey>, Option<CanonicalEdgeKey>), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support scan_edges".to_string()))
}
fn get_property(&mut self, _key: &CanonicalKey, _prop_key_id: u16) -> Result<Option<Property>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_property".to_string()))
}
fn get_value(&mut self, _key: &CanonicalKey, _prop_key_id: u16) -> Result<Option<Primitive>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_value".to_string()))
}
fn add_vertex(&mut self, _id: VertexKey, _label_id: LabelId) -> Result<VertexKey, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support add_vertex".to_string()))
}
fn add_edge(&mut self, _cek: &EdgeKey) -> Result<EdgeKey, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support add_edge".to_string()))
}
fn set_property(&mut self, _prop: &Property) -> Result<(), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support set_property".to_string()))
}
fn drop_property(&mut self, _prop: &Property) -> Result<(), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support drop_property".to_string()))
}
fn drop_vertex(&mut self, _vk: VertexKey) -> Result<(), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support drop_vertex".to_string()))
}
fn drop_edge(&mut self, _ek: &EdgeKey) -> Result<(), StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support drop_edge".to_string()))
}
#[allow(clippy::type_complexity)]
fn get_all_props(
&mut self,
_key: &CanonicalKey,
) -> Result<Option<(LabelId, Vec<(PropKey, Primitive)>)>, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_all_props".to_string()))
}
fn batch_size(&self, _scenario: BatchScenario) -> u32 {
1000
}
fn get_degree(&mut self, _key: VertexKey, _direction: DegreeDirection) -> Result<u64, StoreError> {
Err(StoreError::UnsupportedOperation("NoopCtx does not support get_degree".to_string()))
}
fn schema(&self) -> Arc<RwLock<Schema>> {
Arc::new(RwLock::new(Schema::new()))
}
}
impl<S: GraphStore> GraphCtx for LogicalGraph<S> {
fn get_vertex(&mut self, key: VertexKey) -> Result<Option<VertexKey>, StoreError> {
self.get_vertex(key)
}
fn get_vertices(&mut self, keys: &[VertexKey]) -> Result<Vec<VertexKey>, StoreError> {
self.get_vertices(keys)
}
fn get_edge(&mut self, key: &EdgeKey) -> Result<Option<EdgeKey>, StoreError> {
self.get_edge(key)
}
fn get_edges(&mut self, keys: &[EdgeKey]) -> Result<Vec<EdgeKey>, StoreError> {
self.get_edges(keys)
}
fn get_adjacent_edges(
&mut self,
vertex_key: VertexKey,
direction: Direction,
opts: AdjacentEdgesOptions<'_>,
limit: Option<u32>,
) -> Result<(Vec<EdgeKey>, Option<AdjacentEdgeCursor>), StoreError> {
self.get_adjacent_edges(vertex_key, direction, opts, limit)
}
fn scan_vertices(
&mut self,
label: Option<LabelId>,
start_from: Option<VertexKey>,
limit: u32,
) -> Result<(Vec<VertexKey>, Option<VertexKey>), StoreError> {
self.scan_vertices(label, start_from, limit)
}
fn scan_edges(
&mut self,
label: Option<LabelId>,
start_from: Option<CanonicalEdgeKey>,
limit: u32,
) -> Result<(Vec<EdgeKey>, Option<CanonicalEdgeKey>), StoreError> {
self.scan_edges(label, start_from, limit)
}
fn get_property(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Property>, StoreError> {
self.get_property(key, prop_key_id)
}
fn get_value(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Primitive>, StoreError> {
self.get_value(key, prop_key_id)
}
fn add_vertex(&mut self, id: VertexKey, label_id: LabelId) -> Result<VertexKey, StoreError> {
self.add_vertex(id, label_id)
}
fn add_edge(&mut self, ek: &EdgeKey) -> Result<EdgeKey, StoreError> {
self.add_edge(ek)
}
fn set_property(&mut self, prop: &Property) -> Result<(), StoreError> {
self.set_property(prop)
}
fn drop_property(&mut self, prop: &Property) -> Result<(), StoreError> {
self.drop_property(prop)
}
fn drop_vertex(&mut self, vertex: VertexKey) -> Result<(), StoreError> {
self.drop_element(&CanonicalKey::Vertex(vertex))
}
fn drop_edge(&mut self, edge: &EdgeKey) -> Result<(), StoreError> {
self.drop_element(&CanonicalKey::Edge(edge.canonical_edge_key()))
}
#[allow(clippy::type_complexity)]
fn get_all_props(
&mut self,
key: &CanonicalKey,
) -> Result<Option<(LabelId, Vec<(PropKey, Primitive)>)>, StoreError> {
self.get_all_props(key)
}
fn batch_size(&self, scenario: BatchScenario) -> u32 {
match scenario {
BatchScenario::ScanVertices => self.scan_config.scan_vertices_batch_size,
BatchScenario::ScanEdges => self.scan_config.scan_edges_batch_size,
BatchScenario::GetAdjacentEdges => self.scan_config.get_adjacent_edges_batch_size,
}
}
fn get_degree(&mut self, key: VertexKey, _direction: DegreeDirection) -> Result<u64, StoreError> {
self.get_degree(key, _direction)
}
fn schema(&self) -> Arc<RwLock<Schema>> {
Arc::clone(&self.schema)
}
}
impl<S: GraphStore> GraphCtx for LogicalSnapshot<S> {
fn get_vertex(&mut self, key: VertexKey) -> Result<Option<VertexKey>, StoreError> {
self.get_vertex(key)
}
fn get_vertices(&mut self, keys: &[VertexKey]) -> Result<Vec<VertexKey>, StoreError> {
self.get_vertices(keys)
}
fn get_edge(&mut self, key: &EdgeKey) -> Result<Option<EdgeKey>, StoreError> {
self.get_edge(key)
}
fn get_edges(&mut self, keys: &[EdgeKey]) -> Result<Vec<EdgeKey>, StoreError> {
self.get_edges(keys)
}
fn get_adjacent_edges(
&mut self,
vertex_key: VertexKey,
direction: Direction,
opts: AdjacentEdgesOptions<'_>,
limit: Option<u32>,
) -> Result<(Vec<EdgeKey>, Option<AdjacentEdgeCursor>), StoreError> {
self.get_adjacent_edges(vertex_key, direction, opts, limit)
}
fn scan_vertices(
&mut self,
label: Option<LabelId>,
start_from: Option<VertexKey>,
limit: u32,
) -> Result<(Vec<VertexKey>, Option<VertexKey>), StoreError> {
self.scan_vertices(label, start_from, limit)
}
fn scan_edges(
&mut self,
label: Option<LabelId>,
start_from: Option<CanonicalEdgeKey>,
limit: u32,
) -> Result<(Vec<EdgeKey>, Option<CanonicalEdgeKey>), StoreError> {
self.scan_edges(label, start_from, limit)
}
fn get_property(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Property>, StoreError> {
self.get_property(key, prop_key_id)
}
fn get_value(&mut self, key: &CanonicalKey, prop_key_id: u16) -> Result<Option<Primitive>, StoreError> {
self.get_value(key, prop_key_id)
}
fn add_vertex(&mut self, _id: VertexKey, _label_id: LabelId) -> Result<VertexKey, StoreError> {
Err(StoreError::ReadOnly)
}
fn add_edge(&mut self, _cek: &EdgeKey) -> Result<EdgeKey, StoreError> {
Err(StoreError::ReadOnly)
}
fn set_property(&mut self, _prop: &Property) -> Result<(), StoreError> {
Err(StoreError::ReadOnly)
}
fn drop_property(&mut self, _prop: &Property) -> Result<(), StoreError> {
Err(StoreError::ReadOnly)
}
fn drop_vertex(&mut self, _vertex: VertexKey) -> Result<(), StoreError> {
Err(StoreError::ReadOnly)
}
fn drop_edge(&mut self, _edge: &EdgeKey) -> Result<(), StoreError> {
Err(StoreError::ReadOnly)
}
#[allow(clippy::type_complexity)]
fn get_all_props(
&mut self,
key: &CanonicalKey,
) -> Result<Option<(LabelId, Vec<(PropKey, Primitive)>)>, StoreError> {
self.get_all_props(key)
}
fn batch_size(&self, scenario: BatchScenario) -> u32 {
match scenario {
BatchScenario::ScanVertices => self.scan_config.scan_vertices_batch_size,
BatchScenario::ScanEdges => self.scan_config.scan_edges_batch_size,
BatchScenario::GetAdjacentEdges => self.scan_config.get_adjacent_edges_batch_size,
}
}
fn get_degree(&mut self, key: VertexKey, direction: DegreeDirection) -> Result<u64, StoreError> {
self.get_degree(key, direction)
}
fn schema(&self) -> Arc<RwLock<Schema>> {
Arc::clone(&self.schema)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::keys::AdjacentEdgesOptions;
use crate::types::{element::Property, Direction};
#[test]
fn test_noop_ctx_coverage() {
let mut ctx = NoopCtx;
assert!(ctx.get_vertex(1).is_err());
assert!(ctx.get_vertices(&[1]).is_err());
assert!(ctx
.get_edge(&EdgeKey { primary_id: 1, direction: Direction::OUT, label_id: 2, secondary_id: 3, rank: 0 })
.is_err());
assert!(ctx.get_edges(&[]).is_err());
assert!(ctx
.get_adjacent_edges(
1,
Direction::OUT,
AdjacentEdgesOptions { label: None, dst: None, rank: None, start_from: None },
None
)
.is_err());
assert!(ctx.scan_vertices(None, None, 10).is_err());
assert!(ctx.scan_edges(None, None, 10).is_err());
let canon = CanonicalKey::Vertex(1);
assert!(ctx.get_property(&canon, 10).is_err());
assert!(ctx.get_value(&canon, 10).is_err());
assert!(ctx.add_vertex(1, 2).is_err());
assert!(ctx
.add_edge(&EdgeKey { primary_id: 1, direction: Direction::OUT, label_id: 2, secondary_id: 3, rank: 0 })
.is_err());
let prop = Property { owner: canon, key: 10, value: Primitive::Int32(42) };
assert!(ctx.set_property(&prop).is_err());
assert!(ctx.drop_property(&prop).is_err());
assert!(ctx.drop_vertex(1).is_err());
assert!(ctx
.drop_edge(&EdgeKey { primary_id: 1, direction: Direction::OUT, label_id: 2, secondary_id: 3, rank: 0 })
.is_err());
assert!(ctx.get_all_props(&canon).is_err());
assert_eq!(ctx.batch_size(BatchScenario::ScanVertices), 1000);
assert!(ctx.get_degree(1, crate::types::DegreeDirection::Out).is_err());
let _ = ctx.schema();
}
}