use std::path::{Path, PathBuf};
use arrow_array::RecordBatch;
use crate::{
error::{GraphArError, Result},
io,
metadata::{PropertyGroup, VertexInfo},
};
pub struct VertexReader {
info: VertexInfo,
base_dir: PathBuf,
vertex_count: u64,
}
impl VertexReader {
pub fn new(info: VertexInfo, base_dir: impl AsRef<Path>, vertex_count: u64) -> Self {
Self {
info,
base_dir: base_dir.as_ref().to_path_buf(),
vertex_count,
}
}
pub fn vertex_info(&self) -> &VertexInfo {
&self.info
}
pub fn chunk_count(&self) -> u64 {
self.info.chunk_count(self.vertex_count)
}
pub fn read_property_group(&self, group: &PropertyGroup) -> Result<Vec<RecordBatch>> {
let mut all = Vec::new();
for chunk_idx in 0..self.chunk_count() {
let mut batches = self.read_property_group_chunk(group, chunk_idx)?;
all.append(&mut batches);
}
Ok(all)
}
pub fn read_property_group_chunk(
&self,
group: &PropertyGroup,
chunk_index: u64,
) -> Result<Vec<RecordBatch>> {
let rel = self.info.chunk_path(group, chunk_index);
let full = self.base_dir.join(&rel);
if !full.exists() {
return Err(GraphArError::ChunkOutOfRange(
chunk_index,
self.chunk_count(),
));
}
io::read_chunk(&full, &group.file_type)
}
pub fn read_merged(&self) -> Result<RecordBatch> {
let groups = self.info.property_groups.clone();
self.read_merged_groups(&groups)
}
pub fn read_merged_groups(&self, groups: &[PropertyGroup]) -> Result<RecordBatch> {
let per_group = match groups
.iter()
.map(|g| self.read_property_group(g))
.collect::<Result<Vec<_>>>()
{
Ok(v) => v,
Err(e) => {
crate::functional_status(
"graphar/vertex_reader",
"read_merged",
false,
"property-group chunk read failed",
);
return Err(e);
}
};
let merged = crate::merge::merge_property_groups(&per_group);
crate::functional_status(
"graphar/vertex_reader",
"read_merged",
merged.is_ok(),
&format!("{} groups over {} chunks", groups.len(), self.chunk_count()),
);
merged
}
pub fn read_by_property(&self, property_name: &str) -> Result<Vec<RecordBatch>> {
let group = self
.info
.find_property_group(property_name)
.ok_or_else(|| GraphArError::PropertyNotFound(property_name.to_string()))?
.clone();
self.read_property_group(&group)
}
}
pub struct VertexChunkIter<'a> {
reader: &'a VertexReader,
group: &'a PropertyGroup,
current: u64,
total: u64,
}
impl<'a> VertexChunkIter<'a> {
pub fn new(reader: &'a VertexReader, group: &'a PropertyGroup) -> Self {
let total = reader.chunk_count();
Self {
reader,
group,
current: 0,
total,
}
}
}
impl Iterator for VertexChunkIter<'_> {
type Item = Result<Vec<RecordBatch>>;
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.total {
return None;
}
let idx = self.current;
self.current += 1;
Some(self.reader.read_property_group_chunk(self.group, idx))
}
}