use crate::{
DuckColumns, DuckDynamicIterator, DuckDynamicRow, DuckDynamicTable, DuckOptionResult,
DuckResult, DuckResultSchema, panic_to_duck_error, vec_option_to_ref,
};
use quack_rs::data_chunk::DataChunk;
use quack_rs::prelude::{
BindInfo, LogicalType,
TableFunctionBuilder,
};
use quack_rs::vector::vector_size;
use std::panic::{AssertUnwindSafe, catch_unwind};
pub fn config_bind_params<A: DuckBindArgs>(builder: TableFunctionBuilder) -> TableFunctionBuilder {
let mut builder = builder;
for (name, ty) in A::bind_param_logical() {
if let Some(name) = name {
builder = builder.named_param_logical(&name, ty);
} else {
builder = builder.param_logical(ty)
}
}
builder
}
pub type DuckFullIterator<T> = Box<dyn Iterator<Item=DuckOptionResult<T>> + Send>;
pub type DuckFullIteratorResult<T> = DuckResult<DuckFullIterator<T>>;
pub trait TableFunctionAdapter: Sized + 'static {
fn table_function_builder() -> DuckResult<TableFunctionBuilder> {
let mut builder = TableFunctionBuilder::new(Self::NAME);
builder = Self::config_params(builder);
builder
.with_state(Self::with_state)
.scan(Self::scan)
.build()
}
fn config_params(builder: TableFunctionBuilder) -> TableFunctionBuilder {
config_bind_params::<Self::Args>(builder)
}
fn with_state(
bind: &BindInfo,
) -> DuckFullIteratorResult<Self::Output> {
catch_unwind(|| {
let args: Self::Args = Self::read_args(bind)?;
Self::config_result_columns(bind, &args);
let x: DuckFullIterator<Self::Output> =
Box::new(Self::init_data_iterator(args)?);
Ok(x)
})
.map_err(panic_to_duck_error)? }
fn config_result_columns(bind: &BindInfo, _args: &Self::Args) {
for (name, ty) in Self::Output::named_column_types() {
bind.add_result_column_with_type(&name, &ty);
}
}
fn read_args(bind: &BindInfo) -> DuckResult<Self::Args> {
Self::Args::read_bind_args(bind)
}
fn scan(
state: &mut DuckFullIterator<Self::Output>,
chunk: &DataChunk,
) -> DuckResult<()> {
catch_unwind(AssertUnwindSafe(|| {
let size = vector_size();
let mut output_vec: Vec<Option<Self::Output>> = Vec::with_capacity(size as usize);
let mut count = size;
for i in 0..size {
let option = state.next();
if let Some(value) = option {
output_vec.push(value?);
} else if option.is_none() {
count = i;
break;
}
}
Self::Output::write_columns_batch(chunk, &vec_option_to_ref(&output_vec));
unsafe { chunk.set_size(count as usize) };
Ok(())
}))
.map_err(panic_to_duck_error)? }
const NAME: &'static str;
type Args: DuckBindArgs;
type Output: DuckColumns;
fn init_data_iterator(
args: Self::Args,
) -> DuckFullIteratorResult<Self::Output>;
}
pub trait DuckBindArgs: Sized {
fn read_bind_args(bind: &BindInfo) -> DuckResult<Self>;
fn bind_param_logical() -> Vec<(Option<String>, LogicalType)>;
}
pub struct DuckDynamicState {
pub schema: DuckResultSchema,
pub rows: DuckDynamicIterator,
}
pub trait DynamicTableFunctionAdapter: Sized + 'static {
fn table_function_builder() -> DuckResult<TableFunctionBuilder> {
let mut builder = TableFunctionBuilder::new(Self::NAME);
builder = config_bind_params::<Self::Args>(builder);
builder
.with_state(Self::with_state)
.scan(Self::scan)
.build()
}
fn config_params(builder: TableFunctionBuilder) -> TableFunctionBuilder {
config_bind_params::<Self::Args>(builder)
}
fn with_state(bind: &BindInfo) -> DuckResult<DuckDynamicState> {
catch_unwind(|| {
let args: Self::Args = Self::read_args(bind)?;
let (schema, rows) = Self::bind(args)?.into_parts();
schema.declare(bind);
Ok(DuckDynamicState { schema, rows })
})
.map_err(panic_to_duck_error)? }
fn read_args(bind: &BindInfo) -> DuckResult<Self::Args> {
Self::Args::read_bind_args(bind)
}
fn scan(state: &mut DuckDynamicState, chunk: &DataChunk) -> DuckResult<()> {
catch_unwind(AssertUnwindSafe(|| {
let size = vector_size();
let mut rows: Vec<Option<DuckDynamicRow>> = Vec::with_capacity(size as usize);
let mut count = size;
for i in 0..size {
match state.rows.next() {
Some(value) => rows.push(value?),
None => {
count = i;
break;
}
}
}
DuckDynamicRow::write_batch(chunk, &state.schema, &vec_option_to_ref(&rows))?;
unsafe { chunk.set_size(count as usize) };
Ok(())
}))
.map_err(panic_to_duck_error)? }
const NAME: &'static str;
type Args: DuckBindArgs;
fn bind(args: Self::Args) -> DuckResult<DuckDynamicTable>;
}