use std::sync::Arc;
use vgi_rpc::{Bytes, DictString, LargeBytes, Result, RpcError, VgiArrow};
pub type StrMap = Vec<(String, String)>;
pub type IntMap = Vec<(String, i64)>;
#[derive(Debug, Clone, Copy, Default)]
pub struct InlineI64(pub Option<i64>);
impl From<Option<i64>> for InlineI64 {
fn from(v: Option<i64>) -> Self {
InlineI64(v)
}
}
impl VgiArrow for InlineI64 {
fn arrow_data_type() -> arrow_schema::DataType {
arrow_schema::DataType::Int64
}
fn nullable() -> bool {
true
}
fn describe_name() -> String {
"int".into()
}
fn read(arr: &dyn arrow_array::Array, idx: usize) -> Result<Self> {
if arr.is_null(idx) {
return Ok(InlineI64(None));
}
if let Some(a) = arr.as_any().downcast_ref::<arrow_array::Int64Array>() {
return Ok(InlineI64(Some(a.value(idx))));
}
if let Some(a) = arr.as_any().downcast_ref::<arrow_array::Int32Array>() {
return Ok(InlineI64(Some(a.value(idx) as i64)));
}
Err(RpcError::type_error("expected Int64/Int32 array"))
}
fn build_singleton(value: Self) -> Result<arrow_array::ArrayRef> {
Ok(Arc::new(arrow_array::Int64Array::from(vec![value.0])))
}
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CopyFromContext {
pub format: String,
pub file_path: String,
pub expected_schema: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CopyToContext {
pub format: String,
pub file_path: String,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct BindRequest {
pub function_name: String,
pub arguments: Bytes,
pub function_type: DictString,
pub input_schema: Option<Bytes>,
pub settings: Option<Bytes>,
pub secrets: Option<Bytes>,
pub attach_opaque_data: Option<Bytes>,
pub transaction_opaque_data: Option<Bytes>,
pub resolved_secrets_provided: bool,
pub at_unit: Option<String>,
pub at_value: Option<String>,
}
pub fn read_copy_from(batch: &arrow_array::RecordBatch) -> Result<Option<CopyFromContext>> {
use arrow_array::Array;
match batch.column_by_name("copy_from") {
Some(col) if !col.is_empty() && !col.is_null(0) => {
Ok(Some(<CopyFromContext as VgiArrow>::read(col.as_ref(), 0)?))
}
_ => Ok(None),
}
}
pub fn read_copy_to(batch: &arrow_array::RecordBatch) -> Result<Option<CopyToContext>> {
use arrow_array::Array;
match batch.column_by_name("copy_to") {
Some(col) if !col.is_empty() && !col.is_null(0) => {
Ok(Some(<CopyToContext as VgiArrow>::read(col.as_ref(), 0)?))
}
_ => Ok(None),
}
}
#[derive(Debug, Clone, VgiArrow)]
pub struct BindResponse {
pub output_schema: Bytes,
pub opaque_data: Bytes,
pub lookup_secret_types: Vec<String>,
pub lookup_scopes: Vec<String>,
pub lookup_names: Vec<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct InitRequest {
pub bind_call: Bytes,
pub output_schema: Bytes,
pub bind_opaque_data: Option<Bytes>,
pub projection_ids: Option<Vec<i64>>,
pub pushdown_filters: Option<LargeBytes>,
pub join_keys: Option<Vec<LargeBytes>>,
pub phase: Option<DictString>,
pub execution_id: Option<Bytes>,
pub init_opaque_data: Option<Bytes>,
pub order_by_column_name: Option<String>,
pub order_by_direction: Option<DictString>,
pub order_by_null_order: Option<DictString>,
pub order_by_limit: Option<i64>,
pub tablesample_percentage: Option<f64>,
pub tablesample_seed: Option<i64>,
pub finalize_state_id: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct GlobalInitResponse {
pub execution_id: Bytes,
pub max_workers: i64,
pub opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogAttachRequest {
pub name: String,
pub options: Option<Bytes>,
pub data_version_spec: Option<String>,
pub implementation_version: Option<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CardinalityRequest {
pub bind_call: Bytes,
pub bind_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CardinalityResponse {
pub estimate: Option<i64>,
pub max: Option<i64>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowInitRequest {
pub function_name: String,
pub execution_id: Bytes,
pub partition_id: i64,
pub row_count: i64,
pub partition_batch: Bytes,
pub output_schema: Bytes,
pub filter_mask: Option<Bytes>,
pub frame_stats: Option<Bytes>,
pub all_valid: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowRequest {
pub function_name: String,
pub execution_id: Bytes,
pub partition_id: i64,
pub rid: i64,
pub frame_starts: Vec<i64>,
pub frame_ends: Vec<i64>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowBatchRequest {
pub function_name: String,
pub execution_id: Bytes,
pub partition_id: i64,
pub row_idx: i64,
pub count: i64,
pub frames_per_row: Vec<i64>,
pub frame_starts: Vec<i64>,
pub frame_ends: Vec<i64>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowResponse {
pub result_batch: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowDestructorRequest {
pub function_name: String,
pub execution_id: Bytes,
pub partition_id: i64,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct DynamicToStringRequest {
pub bind_call: Bytes,
pub bind_opaque_data: Option<Bytes>,
pub global_execution_id: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct DynamicToStringResponse {
pub keys: Vec<String>,
pub values: Vec<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingOpenRequest {
pub function_name: String,
pub arguments: Bytes,
pub input_schema: Bytes,
pub partition_key_count: i64,
pub order_key_count: i64,
pub output_schema: Bytes,
pub settings: Option<Bytes>,
pub secrets: Option<Bytes>,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingOpenResponse {
pub execution_id: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingChunkRequest {
pub function_name: String,
pub execution_id: Bytes,
pub input_batch: Bytes,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingChunkResponse {
pub result_batch: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingCloseRequest {
pub function_name: String,
pub execution_id: Bytes,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanBranch {
pub function_name: String,
pub arguments: Bytes,
pub branch_filter: Option<String>,
pub writable: bool,
pub source_catalog: Option<String>,
pub source_schema: Option<String>,
pub source_table: Option<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanBranchesResult {
pub branches: Vec<Bytes>,
pub required_extensions: Vec<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct SecretTypeWire {
pub name: String,
pub description: String,
pub parameters_schema: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AttachCatalogInfo {
pub alias: String,
pub target: String,
pub db_type: String,
pub options: StrMap,
pub hidden: bool,
pub required: bool,
pub secret_ref: String,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogAttachResult {
pub attach_opaque_data: Bytes,
pub supports_transactions: bool,
pub supports_time_travel: bool,
pub catalog_version_frozen: bool,
pub catalog_version: i64,
pub attach_opaque_data_required: bool,
pub default_schema: String,
pub settings: Vec<Bytes>,
pub secret_types: Vec<Bytes>,
pub attach_catalogs: Vec<Bytes>,
pub comment: Option<String>,
pub tags: StrMap,
pub supports_column_statistics: bool,
pub resolved_data_version: Option<String>,
pub resolved_implementation_version: Option<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionBeginParams {
pub attach_opaque_data: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionBeginResult {
pub transaction_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionEndParams {
pub attach_opaque_data: Bytes,
pub transaction_opaque_data: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogDetachParams {
pub attach_opaque_data: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogVersionParams {
pub attach_opaque_data: Bytes,
pub transaction_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogVersionResult {
pub version: i64,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogSchemasParams {
pub attach_opaque_data: Bytes,
pub transaction_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogSchemaNameParams {
pub attach_opaque_data: Bytes,
pub name: String,
pub transaction_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogSchemaContentsFunctionsParams {
pub attach_opaque_data: Bytes,
pub name: String,
#[allow(non_snake_case)]
pub r#type: DictString,
pub transaction_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct ItemsResult {
pub items: Vec<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct SchemaInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub attach_opaque_data: Bytes,
pub name: String,
pub estimated_object_count: Option<IntMap>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct FunctionExample {
pub sql: String,
pub description: String,
pub expected_output: Option<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct RequiredSecret {
pub secret_type: String,
pub scope: Option<String>,
pub secret_name: Option<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub name: String,
pub schema_name: String,
pub columns: Bytes,
pub not_null_constraints: Vec<i32>,
pub unique_constraints: Vec<Vec<i32>>,
pub check_constraints: Vec<String>,
pub primary_key_constraints: Vec<Vec<i32>>,
pub foreign_key_constraints: Vec<Bytes>,
pub supports_insert: bool,
pub supports_update: bool,
pub supports_delete: bool,
pub supports_returning: bool,
pub supports_column_statistics: bool,
pub scan_function: Bytes,
pub insert_function: Bytes,
pub update_function: Bytes,
pub delete_function: Bytes,
pub cardinality_estimate: InlineI64,
pub cardinality_max: InlineI64,
pub column_statistics: Bytes,
pub bind_result: Bytes,
pub required_filters: Vec<Vec<String>>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct ViewInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub name: String,
pub schema_name: String,
pub definition: String,
pub column_comments: StrMap,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct MacroInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub name: String,
pub schema_name: String,
pub macro_type: DictString,
pub parameters: Vec<String>,
pub parameter_default_values: Bytes,
pub definition: String,
pub arguments_schema: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanFunctionResult {
pub function_name: String,
pub arguments: Bytes,
pub required_extensions: Vec<String>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct FunctionInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub name: String,
pub schema_name: String,
pub function_type: DictString,
pub arguments: Bytes,
pub output_schema: Bytes,
pub stability: Option<DictString>,
pub null_handling: Option<DictString>,
pub description: String,
pub examples: Vec<FunctionExample>,
pub categories: Vec<String>,
pub projection_pushdown: Option<bool>,
pub filter_pushdown: Option<bool>,
pub sampling_pushdown: Option<bool>,
pub late_materialization: Option<bool>,
pub supported_expression_filters: Vec<String>,
pub order_preservation: Option<DictString>,
pub max_workers: i32,
pub supports_batch_index: bool,
pub partition_kind: DictString,
pub order_dependent: DictString,
pub distinct_dependent: DictString,
pub supports_window: bool,
pub streaming_partitioned: bool,
pub has_finalize: bool,
pub source_order_dependent: bool,
pub sink_order_dependent: bool,
pub requires_input_batch_index: bool,
pub required_settings: Vec<String>,
pub required_secrets: Vec<RequiredSecret>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct CopyFromFormatInfo {
pub comment: Option<String>,
pub tags: StrMap,
pub format_name: String,
pub handler: String,
pub options: Bytes,
pub direction: String,
pub description: String,
pub ordered: bool,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableCardinality {
pub estimate: Option<i64>,
pub max: Option<i64>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingProcessRequest {
pub function_name: String,
pub execution_id: Bytes,
pub input_batch: Bytes,
pub attach_opaque_data: Option<Bytes>,
pub transaction_id: Option<Bytes>,
pub batch_index: Option<i64>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingProcessResponse {
pub state_id: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingCombineRequest {
pub function_name: String,
pub execution_id: Bytes,
pub state_ids: Vec<Bytes>,
pub attach_opaque_data: Option<Bytes>,
pub transaction_id: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingCombineResponse {
pub finalize_state_ids: Vec<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingDestructorRequest {
pub function_name: String,
pub execution_id: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateBindRequest {
pub function_name: String,
pub arguments: Bytes,
pub input_schema: Option<Bytes>,
pub settings: Option<Bytes>,
pub secrets: Option<Bytes>,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateBindResponse {
pub output_schema: Bytes,
pub execution_id: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateUpdateRequest {
pub function_name: String,
pub execution_id: Bytes,
pub input_batch: Bytes,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateCombineRequest {
pub function_name: String,
pub execution_id: Bytes,
pub merge_batch: Bytes,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateFinalizeRequest {
pub function_name: String,
pub execution_id: Bytes,
pub group_ids_batch: Bytes,
pub output_schema: Bytes,
pub attach_opaque_data: Option<Bytes>,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateFinalizeResponse {
pub result_batch: Bytes,
}
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateDestructorRequest {
pub function_name: String,
pub execution_id: Bytes,
}
#[cfg(test)]
mod federation_tests {
use super::*;
#[test]
fn scan_branch_catalog_table_roundtrips() {
let b = ScanBranch {
function_name: String::new(),
arguments: Bytes::from(Vec::<u8>::new()),
branch_filter: Some("id < 100".to_string()),
writable: false,
source_catalog: Some("acme_lake".to_string()),
source_schema: Some("main".to_string()),
source_table: Some("events".to_string()),
};
let batch = crate::wire::to_batch(b).unwrap();
let back: ScanBranch = crate::wire::from_batch(&batch).unwrap();
assert_eq!(back.function_name, "");
assert_eq!(back.branch_filter.as_deref(), Some("id < 100"));
assert_eq!(back.source_catalog.as_deref(), Some("acme_lake"));
assert_eq!(back.source_schema.as_deref(), Some("main"));
assert_eq!(back.source_table.as_deref(), Some("events"));
}
#[test]
fn attach_catalog_info_roundtrips() {
let info = AttachCatalogInfo {
alias: "acme_lake".to_string(),
target: "ducklake:sqlite:/data/meta.sqlite".to_string(),
db_type: String::new(),
options: vec![("DATA_PATH".to_string(), "/data/".to_string())],
hidden: true,
required: true,
secret_ref: "pg".to_string(),
};
let batch = crate::wire::to_batch(info).unwrap();
let back: AttachCatalogInfo = crate::wire::from_batch(&batch).unwrap();
assert_eq!(back.alias, "acme_lake");
assert_eq!(back.target, "ducklake:sqlite:/data/meta.sqlite");
assert_eq!(
back.options,
vec![("DATA_PATH".to_string(), "/data/".to_string())]
);
assert!(back.hidden);
assert!(back.required);
assert_eq!(back.secret_ref, "pg");
}
}