use std::collections::HashMap;
use compact_str::CompactString;
use crate::error::{TraverserError, TraverserResult};
use crate::graph::storage::{stored_edge_id, stored_vertex_id};
use crate::graph::{GraphStorage, TraversalGraph};
use crate::value::{ElementProperty, PropertyMap};
pub(crate) fn copy_edges_into<S, T>(
source: &S,
edges: impl IntoIterator<Item = S::EdgeId>,
target: &mut T,
copy_schema: bool,
) -> TraverserResult<()>
where
S: GraphStorage,
T: GraphStorage,
{
let mut vertices: HashMap<S::VertexId, T::VertexId> = HashMap::new();
for edge in edges {
let edge_id = stored_edge_id(source, edge)?;
if target.get_edge_by_id(edge_id).is_some() {
continue;
}
let (from, to) = source.edge_endpoints(edge).ok_or_else(|| {
Box::new(TraverserError::QueryExecution {
query: "subgraph".to_string(),
reason: format!("edge '{edge_id}' has no endpoints"),
})
})?;
let from = ensure_vertex(source, target, &mut vertices, from)?;
let to = ensure_vertex(source, target, &mut vertices, to)?;
target.add_edge(
Some(CompactString::new(edge_id)),
source.edge_label(edge).map(CompactString::new),
from,
to,
source
.edge_properties(edge)
.map(crate::value::logical_element)
.unwrap_or_default(),
)?;
}
if copy_schema
&& target.get_schema().is_none()
&& let Some(schema) = source.get_schema()
{
target.set_schema(schema)?;
}
Ok(())
}
fn ensure_vertex<S, T>(
source: &S,
target: &mut T,
copied: &mut HashMap<S::VertexId, T::VertexId>,
vertex: S::VertexId,
) -> TraverserResult<T::VertexId>
where
S: GraphStorage,
T: GraphStorage,
{
if let Some(existing) = copied.get(&vertex) {
return Ok(*existing);
}
let id = stored_vertex_id(source, vertex)?;
let handle = match target.get_vertex_by_id(id) {
Some(existing) => existing,
None => target.add_vertex(
Some(CompactString::new(id)),
source.vertex_labels(vertex).to_vec(),
source
.vertex_properties(vertex)
.map(crate::value::logical_element)
.unwrap_or_default(),
)?,
};
copied.insert(vertex, handle);
Ok(handle)
}
pub(crate) fn graph_to_property(graph: &crate::graph::Graph) -> TraverserResult<ElementProperty> {
let graph = graph.read();
let graph: &TraversalGraph = &graph;
graph_listing(graph, None)
}
pub(crate) fn graph_listing<S: GraphStorage>(
graph: &S,
keep: Option<usize>,
) -> TraverserResult<ElementProperty> {
use crate::value::TraverserValue;
let keep = keep.unwrap_or(usize::MAX);
let mut vertices = Vec::with_capacity(graph.vertex_count().min(keep));
for vertex in graph.vertices().take(keep) {
vertices.push(TraverserValue::<S>::Vertex(vertex).into_node_property(graph)?);
}
let mut edges = Vec::with_capacity(graph.edge_count().min(keep));
for edge in graph.edges().take(keep) {
edges.push(TraverserValue::<S>::Edge(edge).into_node_property(graph)?);
}
let mut map = PropertyMap::default();
map.insert(
CompactString::new("vertices"),
ElementProperty::Array(vertices),
);
map.insert(CompactString::new("edges"), ElementProperty::Array(edges));
Ok(ElementProperty::Object(Box::new(map)))
}