use std::sync::Arc;
use arrow_array::RecordBatch;
use arrow_schema::SchemaRef;
use vgi_rpc::{Result, RpcError};
use crate::arguments::Arguments;
use crate::buffering::{BufferingParams, TableBufferingFunction};
use crate::function::{ArgSpec, BindParams, BindResponse, FunctionMetadata};
use crate::storage::FunctionStorage;
use crate::table_function::TableProducer;
pub struct CopyToWriteContext<'a> {
pub path: &'a str,
pub options: &'a Arguments,
pub storage: &'a Arc<dyn FunctionStorage>,
pub execution_id: &'a [u8],
pub params: &'a BufferingParams,
}
pub struct CopyToCloseContext<'a> {
pub path: &'a str,
pub options: &'a Arguments,
pub storage: &'a Arc<dyn FunctionStorage>,
pub execution_id: &'a [u8],
pub input_schema: Option<&'a SchemaRef>,
pub params: &'a BufferingParams,
}
pub trait CopyToFunction: Send + Sync {
fn format(&self) -> &str;
fn handler_name(&self) -> &str;
fn comment(&self) -> Option<String> {
None
}
fn metadata(&self) -> FunctionMetadata {
FunctionMetadata::default()
}
fn argument_specs(&self) -> Vec<ArgSpec>;
fn secret_lookups(&self, _params: &BindParams) -> Vec<crate::secrets::SecretLookup> {
Vec::new()
}
fn ordered(&self) -> bool {
false
}
fn write(&self, ctx: &CopyToWriteContext, batch: &RecordBatch) -> Result<()>;
fn close(&self, ctx: &CopyToCloseContext) -> Result<i64>;
}
pub struct CopyToBuffering(pub Arc<dyn CopyToFunction>);
impl CopyToBuffering {
fn missing_ctx_error(&self) -> RpcError {
RpcError::value_error(format!(
"{} is a COPY TO format writer; invoke it via \
COPY <source> TO '<path>' (FORMAT {}), not directly.",
self.0.handler_name(),
self.0.format()
))
}
}
impl TableBufferingFunction for CopyToBuffering {
fn name(&self) -> &str {
self.0.handler_name()
}
fn metadata(&self) -> FunctionMetadata {
self.0.metadata()
}
fn argument_specs(&self) -> Vec<ArgSpec> {
self.0.argument_specs()
}
fn secret_lookups(&self, params: &BindParams) -> Vec<crate::secrets::SecretLookup> {
self.0.secret_lookups(params)
}
fn on_bind(&self, _params: &BindParams) -> Result<BindResponse> {
Ok(BindResponse {
output_schema: Arc::new(arrow_schema::Schema::empty()),
opaque_data: Vec::new(),
})
}
fn process(&self, params: &BufferingParams, batch: &RecordBatch) -> Result<Vec<u8>> {
let ct = params
.copy_to
.as_ref()
.ok_or_else(|| self.missing_ctx_error())?;
let ctx = CopyToWriteContext {
path: &ct.file_path,
options: ¶ms.arguments,
storage: ¶ms.storage,
execution_id: ¶ms.execution_id,
params,
};
self.0.write(&ctx, batch)?;
Ok(params.execution_id.clone())
}
fn combine(&self, params: &BufferingParams, _state_ids: &[Vec<u8>]) -> Result<Vec<Vec<u8>>> {
let ct = params
.copy_to
.as_ref()
.ok_or_else(|| self.missing_ctx_error())?;
let ctx = CopyToCloseContext {
path: &ct.file_path,
options: ¶ms.arguments,
storage: ¶ms.storage,
execution_id: ¶ms.execution_id,
input_schema: params.input_schema.as_ref(),
params,
};
self.0.close(&ctx)?;
Ok(Vec::new())
}
fn finalize_producer(
&self,
_params: &BufferingParams,
_finalize_state_id: Vec<u8>,
) -> Result<Box<dyn TableProducer>> {
Err(RpcError::value_error(
"COPY TO writer has no finalize/source phase",
))
}
}