use arrow::record_batch::RecordBatch;
use arrow::datatypes::{DataType, Field, Schema};
use std::sync::Arc;
use std::path::Path;
use crate::error::{GraphError, Result};
use crate::graph::GraphIndexes;
#[derive(Debug, Clone)]
pub struct ArrowGraph {
pub nodes: RecordBatch,
pub edges: RecordBatch,
pub indexes: GraphIndexes,
}
impl ArrowGraph {
pub fn new(nodes: RecordBatch, edges: RecordBatch) -> Result<Self> {
let indexes = GraphIndexes::build(&nodes, &edges)?;
Ok(ArrowGraph {
nodes,
edges,
indexes,
})
}
pub fn from_edges(edges: RecordBatch) -> Result<Self> {
let nodes_schema = Arc::new(Schema::new(vec![
Field::new("id", DataType::Utf8, false),
]));
let empty_nodes = RecordBatch::new_empty(nodes_schema);
Self::new(empty_nodes, edges)
}
pub async fn from_files<P: AsRef<Path>>(
_nodes_path: P,
_edges_path: P,
) -> Result<Self> {
todo!("Implement loading from files - will read Arrow/Parquet files")
}
pub fn from_tables(
nodes: RecordBatch,
edges: RecordBatch,
) -> Result<Self> {
Self::new(nodes, edges)
}
pub async fn sql(&self, _query: &str) -> Result<RecordBatch> {
todo!("Implement SQL execution using DataFusion with graph functions")
}
pub fn node_count(&self) -> usize {
self.indexes.node_count
}
pub fn edge_count(&self) -> usize {
self.indexes.edge_count
}
pub fn density(&self) -> f64 {
let n = self.node_count() as f64;
let m = self.edge_count() as f64;
if n <= 1.0 {
0.0
} else {
m / (n * (n - 1.0))
}
}
pub fn neighbors(&self, node_id: &str) -> Option<&Vec<String>> {
self.indexes.neighbors(node_id)
}
pub fn predecessors(&self, node_id: &str) -> Option<&Vec<String>> {
self.indexes.predecessors(node_id)
}
pub fn has_node(&self, node_id: &str) -> bool {
self.indexes.has_node(node_id)
}
pub fn edge_weight(&self, source: &str, target: &str) -> Option<f64> {
self.indexes.edge_weight(source, target)
}
pub fn node_ids(&self) -> impl Iterator<Item = &String> {
self.indexes.all_nodes()
}
}