use arrow_array::{RecordBatch, RecordBatchIterator, RecordBatchReader};
use arrow_schema::SchemaRef;
use crate::Error;
pub use crate::scandal::api::{SortColumn, WriteLayout, WriteProperties};
pub trait IntoArrowStream {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error>;
fn into_write_input(self) -> Result<WriteInput, Error>
where
Self: Sized,
{
let reader = self.into_arrow_stream()?;
WriteInput::new(
reader.schema(),
vec![reader],
WriteProperties {
ordering: Vec::new(),
},
)
}
}
pub struct WriteInput {
pub(crate) schema: SchemaRef,
pub(crate) partitions: Vec<Box<dyn RecordBatchReader + Send>>,
pub(crate) properties: WriteProperties,
}
impl WriteInput {
pub fn new(
schema: SchemaRef,
partitions: Vec<Box<dyn RecordBatchReader + Send>>,
properties: WriteProperties,
) -> Result<Self, Error> {
if partitions
.iter()
.any(|partition| partition.schema() != schema)
{
return Err(Error::invalid(
"write partitions must have the declared schema",
));
}
Ok(Self {
schema,
partitions,
properties,
})
}
pub fn schema(&self) -> SchemaRef {
self.schema.clone()
}
}
impl IntoArrowStream for WriteInput {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
Ok(Box::new(RecordBatchIterator::new(
self.partitions.into_iter().flatten(),
self.schema,
)))
}
fn into_write_input(self) -> Result<WriteInput, Error> {
Ok(self)
}
}
impl IntoArrowStream for RecordBatch {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
let schema = self.schema();
Ok(Box::new(RecordBatchIterator::new([Ok(self)], schema)))
}
}
impl IntoArrowStream for Vec<RecordBatch> {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
let schema = self
.first()
.ok_or_else(|| Error::invalid("an empty input needs an explicit schema"))?
.schema();
(schema, self).into_arrow_stream()
}
}
impl IntoArrowStream for (SchemaRef, Vec<RecordBatch>) {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
Ok(Box::new(RecordBatchIterator::new(
self.1.into_iter().map(Ok),
self.0,
)))
}
}
impl IntoArrowStream for Box<dyn RecordBatchReader + Send> {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
Ok(self)
}
}
impl<R: RecordBatchReader + Send + 'static> IntoArrowStream for Box<R> {
fn into_arrow_stream(self) -> Result<Box<dyn RecordBatchReader + Send>, Error> {
Ok(self)
}
}