use std::sync::Arc;
use crate::error::{GraphError, TraverserResult};
use crate::graph::compression::CompressionStats;
use crate::graph::definition::{Definition, DefinitionKind};
use crate::graph::hooks::Mark;
use crate::graph::schema::{GraphSchema, SchemaDiff, SchemaPatch, SchemaValidation};
use crate::graph::{
Graph, GraphStatistics, GraphStorage, MemoryStats, StorageCapabilities, Transactional,
};
use crate::traversal::GraphTraversalSource;
#[cfg(feature = "io")]
use crate::error::IOError;
#[cfg(feature = "io")]
use crate::io::ImportReport;
#[cfg(feature = "persist")]
use crate::persist::{PersistError, SnapshotInfo};
#[cfg(feature = "script")]
use crate::script::plan::{ScriptPlan, Terminal, TerminalOutput, UnitBody, UnitKind, UnitResult};
#[cfg(feature = "io")]
type PresetOptions =
std::collections::HashMap<compact_str::CompactString, crate::value::ElementProperty>;
mod sealed {
pub trait Sealed {}
}
pub trait AnyGraph: Send + Sync + 'static + sealed::Sealed {
fn as_any(&self) -> &dyn std::any::Any;
fn into_any_arc(self: Arc<Self>) -> Arc<dyn std::any::Any + Send + Sync>;
fn storage_type_name(&self) -> &'static str;
fn capabilities(&self) -> StorageCapabilities;
fn last_commit_seq(&self) -> u64;
fn statistics(&self) -> Option<GraphStatistics>;
fn memory_usage(&self) -> Option<MemoryStats>;
#[doc(hidden)]
fn listing(&self, keep: Option<usize>) -> TraverserResult<crate::value::ElementProperty>;
fn get_schema(&self) -> Option<GraphSchema>;
fn set_schema(&self, schema: GraphSchema) -> TraverserResult<()>;
fn patch_schema(&self, patch: &SchemaPatch) -> TraverserResult<GraphSchema>;
fn validate_schema(&self, schema: &GraphSchema) -> TraverserResult<SchemaValidation>;
fn validate_schema_patch(&self, patch: &SchemaPatch) -> TraverserResult<SchemaValidation>;
fn infer_schema(&self) -> TraverserResult<GraphSchema>;
fn diff_schema(&self, schema: &GraphSchema) -> TraverserResult<SchemaDiff>;
fn definitions(&self, kind: Option<DefinitionKind>) -> Vec<Definition>;
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<Definition>;
fn set_definitions(&self, definitions: Vec<Definition>) -> TraverserResult<()>;
fn remove_definition(&self, kind: DefinitionKind, name: &str) -> TraverserResult<bool>;
fn move_query(&self, name: &str, folder: Option<&str>) -> TraverserResult<()>;
fn describe_query(&self, name: &str, description: Option<&str>) -> TraverserResult<()>;
fn recompress(&self, name: &str) -> TraverserResult<()>;
fn compression_stats(&self, name: &str) -> Option<CompressionStats>;
fn mark(&self, name: &str) -> Result<Mark, GraphError>;
#[cfg(feature = "io")]
fn import_graphml(
&self,
reader: &mut dyn std::io::BufRead,
presets: Option<&PresetOptions>,
) -> Result<(), IOError>;
#[cfg(feature = "io")]
fn import_graphson(
&self,
reader: &mut dyn std::io::BufRead,
presets: Option<&PresetOptions>,
) -> Result<ImportReport, IOError>;
#[cfg(feature = "io")]
fn export_graphml(
&self,
writer: &mut dyn std::io::Write,
beautify: bool,
) -> Result<(), IOError>;
#[cfg(feature = "io")]
fn export_graphson(&self, writer: &mut dyn std::io::Write) -> Result<(), IOError>;
#[cfg(feature = "persist")]
fn write_snapshot(&self, writer: &mut dyn std::io::Write)
-> Result<SnapshotInfo, PersistError>;
#[cfg(feature = "script")]
#[doc(hidden)]
fn run_plan(&self, plan: &ScriptPlan<'_>, terminal: Terminal) -> TerminalOutput;
#[cfg(feature = "script")]
#[doc(hidden)]
fn run_unit(
&self,
kind: UnitKind,
body: &mut dyn FnMut(&Arc<dyn AnyGraph>) -> UnitBody,
) -> UnitResult;
}
impl<S> sealed::Sealed for Graph<S> where S: GraphStorage + Default + Send + Sync + 'static {}
impl<S> AnyGraph for Graph<S>
where
S: GraphStorage + Default + Send + Sync + 'static,
{
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn into_any_arc(self: Arc<Self>) -> Arc<dyn std::any::Any + Send + Sync> {
self
}
fn storage_type_name(&self) -> &'static str {
std::any::type_name::<S>()
}
fn capabilities(&self) -> StorageCapabilities {
self.read().capabilities()
}
fn last_commit_seq(&self) -> u64 {
self.read().last_commit_seq()
}
fn statistics(&self) -> Option<GraphStatistics> {
self.read().statistics().cloned()
}
fn memory_usage(&self) -> Option<MemoryStats> {
self.read().memory_usage()
}
fn listing(&self, keep: Option<usize>) -> TraverserResult<crate::value::ElementProperty> {
crate::graph::subgraph::graph_listing(&*self.read(), keep)
}
fn get_schema(&self) -> Option<GraphSchema> {
self.read().get_schema()
}
fn set_schema(&self, schema: GraphSchema) -> TraverserResult<()> {
GraphTraversalSource::new(&mut *self.write()).set_schema(schema)
}
fn patch_schema(&self, patch: &SchemaPatch) -> TraverserResult<GraphSchema> {
GraphTraversalSource::new(&mut *self.write()).patch_schema(patch)
}
fn validate_schema(&self, schema: &GraphSchema) -> TraverserResult<SchemaValidation> {
GraphTraversalSource::new(&*self.read()).validate_schema(schema)
}
fn validate_schema_patch(&self, patch: &SchemaPatch) -> TraverserResult<SchemaValidation> {
GraphTraversalSource::new(&*self.read()).validate_schema_patch(patch)
}
fn infer_schema(&self) -> TraverserResult<GraphSchema> {
GraphTraversalSource::new(&*self.read()).infer_schema()
}
fn diff_schema(&self, schema: &GraphSchema) -> TraverserResult<SchemaDiff> {
GraphTraversalSource::new(&*self.read()).diff_schema(schema)
}
fn definitions(&self, kind: Option<DefinitionKind>) -> Vec<Definition> {
self.read()
.definitions()
.filter(|definition| kind.is_none_or(|kind| definition.kind() == kind))
.cloned()
.collect()
}
fn definition(&self, kind: DefinitionKind, name: &str) -> Option<Definition> {
self.read().definition(kind, name).cloned()
}
fn set_definitions(&self, definitions: Vec<Definition>) -> TraverserResult<()> {
self.write().transaction(|unit| {
for definition in definitions {
GraphTraversalSource::new(&mut *unit).set_definition(definition)?;
}
Ok(())
})
}
fn remove_definition(&self, kind: DefinitionKind, name: &str) -> TraverserResult<bool> {
GraphTraversalSource::new(&mut *self.write()).remove_definition(kind, name)
}
fn move_query(&self, name: &str, folder: Option<&str>) -> TraverserResult<()> {
GraphTraversalSource::new(&mut *self.write()).move_query(name, folder)
}
fn describe_query(&self, name: &str, description: Option<&str>) -> TraverserResult<()> {
GraphTraversalSource::new(&mut *self.write()).describe_query(name, description)
}
fn recompress(&self, name: &str) -> TraverserResult<()> {
GraphTraversalSource::new(&mut *self.write()).recompress(name)
}
fn compression_stats(&self, name: &str) -> Option<CompressionStats> {
self.read().compression_stats(name)
}
fn mark(&self, name: &str) -> Result<Mark, GraphError> {
self.write().mark(name)
}
#[cfg(feature = "io")]
fn import_graphml(
&self,
reader: &mut dyn std::io::BufRead,
presets: Option<&PresetOptions>,
) -> Result<(), IOError> {
crate::io::GraphMLImport {}.import_reader_with(
&mut *self.write(),
quick_xml::Reader::from_reader(reader),
presets,
)
}
#[cfg(feature = "io")]
fn import_graphson(
&self,
reader: &mut dyn std::io::BufRead,
presets: Option<&PresetOptions>,
) -> Result<ImportReport, IOError> {
crate::io::GraphSONImport::new().import_reader_with(&mut *self.write(), reader, presets)
}
#[cfg(feature = "io")]
fn export_graphml(
&self,
writer: &mut dyn std::io::Write,
beautify: bool,
) -> Result<(), IOError> {
crate::io::GraphMLExport::new()
.with_beautify(beautify)
.export_writer(&*self.read(), writer)
}
#[cfg(feature = "io")]
fn export_graphson(&self, writer: &mut dyn std::io::Write) -> Result<(), IOError> {
crate::io::GraphSONExport::new().export_writer(&*self.read(), writer)
}
#[cfg(feature = "persist")]
fn write_snapshot(
&self,
writer: &mut dyn std::io::Write,
) -> Result<SnapshotInfo, PersistError> {
if let Some(write) = self.snapshot_writer() {
return write(&*self.read(), writer);
}
match self.as_any().downcast_ref::<Graph<crate::TraversalGraph>>() {
Some(graph) => graph.read().write_snapshot(writer),
None => Err(PersistError::Graph(GraphError::unsupported("snapshots"))),
}
}
#[cfg(feature = "script")]
fn run_plan(&self, plan: &ScriptPlan<'_>, terminal: Terminal) -> TerminalOutput {
crate::script::plan::run_plan_on(self, plan, terminal)
}
#[cfg(feature = "script")]
fn run_unit(
&self,
kind: UnitKind,
body: &mut dyn FnMut(&Arc<dyn AnyGraph>) -> UnitBody,
) -> UnitResult {
crate::script::plan::run_unit_on(self, kind, body)
}
}
pub trait IntoAnyGraph {
fn into_any_graph(self) -> Arc<dyn AnyGraph>;
}
impl<S> IntoAnyGraph for Arc<Graph<S>>
where
S: GraphStorage + Default + Send + Sync + 'static,
{
fn into_any_graph(self) -> Arc<dyn AnyGraph> {
self
}
}
impl IntoAnyGraph for Arc<dyn AnyGraph> {
fn into_any_graph(self) -> Arc<dyn AnyGraph> {
self
}
}
#[cfg(test)]
mod tests;