use std::{
collections::HashMap, iter::IntoIterator, marker::PhantomData, option::Option, sync::Arc,
};
use arrow_array::{
Array, RecordBatch,
builder::{ArrayBuilder, StructBuilder},
};
use arrow_schema::{DataType, Field, Schema};
pub use crate::error::SchemaError;
#[cfg(feature = "views")]
pub use crate::error::ViewAccessError;
#[cfg(feature = "views")]
impl From<ViewAccessError> for SchemaError {
fn from(err: ViewAccessError) -> Self {
match err {
ViewAccessError::TypeMismatch {
expected, actual, ..
} => SchemaError::TypeMismatch { expected, actual },
_ => SchemaError::invalid(err.to_string()),
}
}
}
pub trait Record {
const LEN: usize;
}
pub trait ColAt<const I: usize>: Record {
type Native;
type ColumnArray: Array;
type ColumnBuilder: ArrayBuilder;
const NULLABLE: bool;
const NAME: &'static str;
fn data_type() -> DataType;
}
pub struct FieldMeta<R> {
pub name: &'static str,
pub nullable: bool,
_phantom: PhantomData<R>,
}
impl<R> FieldMeta<R> {
#[must_use]
pub const fn new(name: &'static str, nullable: bool) -> Self {
Self {
name,
nullable,
_phantom: PhantomData,
}
}
}
pub trait ColumnVisitor {
fn visit<const I: usize, R>(_m: FieldMeta<R>);
}
pub trait ForEachCol: Record {
fn for_each_col<V: ColumnVisitor>();
}
pub trait StructMeta: Record {
fn child_fields() -> Vec<Field>;
fn new_struct_builder(capacity: usize) -> StructBuilder;
}
pub trait SchemaMeta: Record {
fn fields() -> Vec<Field>;
#[must_use]
fn metadata() -> HashMap<String, String> {
HashMap::default()
}
fn schema() -> Arc<Schema> {
let fields: Vec<Arc<Field>> = Self::fields().into_iter().map(Arc::new).collect();
Arc::new(Schema::new_with_metadata(fields, Self::metadata()))
}
}
pub trait BuildRows: Record + Sized {
type Builders: RowBuilder<Self>;
type Arrays: IntoRecordBatch;
fn new_builders(capacity: usize) -> Self::Builders;
}
pub trait RowBuilder<Row> {
type Arrays: IntoRecordBatch;
fn append_row(&mut self, row: Row);
fn append_null_row(&mut self);
fn append_option_row(&mut self, row: Option<Row>);
fn append_rows<I: IntoIterator<Item = Row>>(&mut self, rows: I);
fn append_option_rows<I: IntoIterator<Item = Option<Row>>>(&mut self, rows: I);
fn finish(self) -> Self::Arrays;
}
pub trait IntoRecordBatch {
fn into_record_batch(self) -> RecordBatch;
}
impl IntoRecordBatch for RecordBatch {
fn into_record_batch(self) -> RecordBatch {
self
}
}
pub trait AppendStruct {
fn append_owned_into(self, b: &mut StructBuilder);
fn append_null_into(b: &mut StructBuilder);
}
pub trait AppendStructRef {
fn append_borrowed_into(&self, b: &mut StructBuilder);
}
#[cfg(feature = "views")]
pub trait FromRecordBatch: Record + Sized {
type View<'a>;
type Views<'a>: Iterator<Item = Result<Self::View<'a>, ViewAccessError>>;
fn from_record_batch(batch: &RecordBatch) -> Result<Self::Views<'_>, SchemaError>;
}
#[cfg(feature = "views")]
pub trait ViewResultIteratorExt: Iterator + Sized {
type Item;
fn try_flatten(self) -> Result<Vec<<Self as ViewResultIteratorExt>::Item>, ViewAccessError>
where
Result<Vec<<Self as ViewResultIteratorExt>::Item>, ViewAccessError>:
std::iter::FromIterator<<Self as Iterator>::Item>,
{
self.collect()
}
}
#[cfg(feature = "views")]
impl<I, T> ViewResultIteratorExt for I
where
I: Iterator<Item = Result<T, ViewAccessError>>,
{
type Item = T;
}
#[cfg(feature = "views")]
pub trait StructView: Record + Sized {
type View<'a>;
fn view_at(
array: &arrow_array::StructArray,
index: usize,
) -> Result<Self::View<'_>, ViewAccessError>;
fn is_null_at(array: &arrow_array::StructArray, index: usize) -> bool;
}