use crate::parquet_reader::{ParquetReaderError, ParquetStreamReader, read_parquet, stream_parquet};
use akar_catalog::CatalogColumn;
use akar_common::file_system::VirtualFileSystemRegistry;
use akar_common::types::Value;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IceDiskRelTableLayout {
Flat,
Csr,
}
pub struct IceDiskRelTable {
pub name: String,
pub layout: IceDiskRelTableLayout,
pub indices_file_path: PathBuf,
pub indptr_file_path: Option<PathBuf>,
}
pub struct IceDiskRelTableScanState {
pub stream: ParquetStreamReader,
pub current_batch: Vec<Vec<Value>>,
pub current_row: usize,
}
impl IceDiskRelTable {
pub fn new(name: String, base_path: &Path, layout: IceDiskRelTableLayout) -> Self {
let indices_path = match layout {
IceDiskRelTableLayout::Flat => base_path.join(format!("{}.flat.parquet", name)),
IceDiskRelTableLayout::Csr => base_path.join(format!("{}.indices.parquet", name)),
};
let indptr_path = match layout {
IceDiskRelTableLayout::Flat => None,
IceDiskRelTableLayout::Csr => Some(base_path.join(format!("{}.indptr.parquet", name))),
};
Self {
name,
layout,
indices_file_path: indices_path,
indptr_file_path: indptr_path,
}
}
pub fn scan_indices(
&self,
vfs: &VirtualFileSystemRegistry,
columns: &[CatalogColumn],
) -> Result<IceDiskRelTableScanState, ParquetReaderError> {
let stream = stream_parquet(self.indices_file_path.to_str().unwrap(), vfs, columns)?;
Ok(IceDiskRelTableScanState {
stream,
current_batch: Vec::new(),
current_row: 0,
})
}
pub fn scan_indptr(
&self,
vfs: &VirtualFileSystemRegistry,
columns: &[CatalogColumn],
) -> Result<Vec<Vec<Value>>, ParquetReaderError> {
if let Some(path) = &self.indptr_file_path {
read_parquet(path.to_str().unwrap(), vfs, columns)
} else {
Ok(vec![])
}
}
}
impl IceDiskRelTableScanState {
pub fn next_row(&mut self) -> Option<&Vec<Value>> {
if self.current_row >= self.current_batch.len() {
match self.stream.next() {
Some(Ok(batch)) => {
self.current_batch = batch;
self.current_row = 0;
}
Some(Err(_)) | None => {
self.current_batch = Vec::new();
self.current_row = 0;
return None;
}
}
}
if self.current_row < self.current_batch.len() {
let row = &self.current_batch[self.current_row];
self.current_row += 1;
Some(row)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ice_disk_paths() {
let base = Path::new("/tmp/akar");
let flat_table = IceDiskRelTable::new("knows".into(), base, IceDiskRelTableLayout::Flat);
assert_eq!(flat_table.indices_file_path, base.join("knows.flat.parquet"));
assert!(flat_table.indptr_file_path.is_none());
let csr_table = IceDiskRelTable::new("study_at".into(), base, IceDiskRelTableLayout::Csr);
assert_eq!(csr_table.indices_file_path, base.join("study_at.indices.parquet"));
assert_eq!(csr_table.indptr_file_path, Some(base.join("study_at.indptr.parquet")));
}
}