use std::fs::File;
use std::path::PathBuf;
use anyhow::{Context, Result};
use arrow::datatypes::Schema;
use arrow::ipc::writer::FileWriter;
use super::{StructArrayBuilder, TableWriter};
pub struct ArrowTableWriter<Builder: Default + StructArrayBuilder> {
path: PathBuf,
file_writer: FileWriter<File>,
builder: Builder,
pub flush_threshold: usize,
}
impl<Builder: Default + StructArrayBuilder> TableWriter for ArrowTableWriter<Builder> {
type Schema = Schema;
type CloseResult = ();
type Config = Option<usize>;
fn new(mut path: PathBuf, schema: Self::Schema, config: Option<usize>) -> Result<Self> {
path.set_extension("arrow");
let file =
File::create(&path).with_context(|| format!("Could not create {}", path.display()))?;
let file_writer = FileWriter::try_new(file, &schema).with_context(|| {
format!(
"Could not create writer for {} with schema {}",
path.display(),
schema
)
})?;
Ok(ArrowTableWriter {
path,
file_writer,
flush_threshold: config.unwrap_or(1024 * 1024), builder: Builder::default(),
})
}
fn flush(&mut self) -> Result<()> {
let mut tmp = Builder::default();
std::mem::swap(&mut tmp, &mut self.builder);
let struct_array = tmp.finish()?;
self.file_writer
.write(&struct_array.into())
.with_context(|| format!("Could not write to {}", self.path.display()))
}
fn close(mut self) -> Result<()> {
self.flush()?;
self.file_writer
.finish()
.with_context(|| format!("Could not close {}", self.path.display()))
}
}
impl<Builder: Default + StructArrayBuilder> ArrowTableWriter<Builder> {
pub fn builder(&mut self) -> Result<&mut Builder> {
if self.builder.len() >= self.flush_threshold {
self.flush()?;
}
Ok(&mut self.builder)
}
}
impl<Builder: Default + StructArrayBuilder> Drop for ArrowTableWriter<Builder> {
fn drop(&mut self) {
self.flush().unwrap();
self.file_writer
.finish()
.with_context(|| format!("Could not close {}", self.path.display()))
.unwrap();
}
}