vgi 0.1.2

Build VGI workers in Rust to extend DuckDB with custom catalogs, functions, and tables over Apache Arrow IPC
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
// Copyright 2025, 2026 Query Farm LLC - https://query.farm

//! VGI wire DTOs. Field order and types mirror
//! `vgi-go/vgi/generated/protocol_schemas.go` exactly (the C++ extension
//! reads several result schemas positionally, so order matters).
//!
//! Serialize/deserialize the flat ones with [`crate::wire`]; the catalog
//! item structs (`SchemaInfo`, `FunctionInfo`, …) are IPC-serialized into
//! the `items: list<binary>` result via [`crate::ipc`].

use std::sync::Arc;

use vgi_rpc::{Bytes, DictString, LargeBytes, Result, RpcError, VgiArrow};

/// `map<utf8, utf8>` payload (Python-canonical `keys`/`values` child names).
pub type StrMap = Vec<(String, String)>;
/// `map<utf8, int64>` payload.
pub type IntMap = Vec<(String, i64)>;

/// An optionally-inlined `int64` whose wire field is declared **non-nullable**
/// (the C++ extension's result-schema check requires `int64 not null`) yet may
/// carry a NULL value. The extension reads it via `row[...].as<int64_t>()`,
/// which yields `nullopt` for NULL — its signal for "not inlined, fire the RPC".
/// Matches the vgi-go / vgi-python convention (null in a non-nullable column).
#[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
    }
    // Built nullable (so `arrow`'s StructArray accepts the NULL child), then
    // the serialized item's schema is tightened back to non-nullable by
    // `serialize_items` to satisfy the C++ schema check — matching Go/Python,
    // which emit NULL in a column the schema declares non-nullable.
    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])))
    }
}

// ---------------------------------------------------------------------------
// bind
// ---------------------------------------------------------------------------

/// `BindRequest` — carried IPC-serialized inside the `request` binary column
/// of `bind`, and as the nested `bind_call` struct of `init` / cardinality.
#[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,
    /// Time travel: the `AT (TIMESTAMP|VERSION ...)` clause for this scan,
    /// threaded through from DuckDB's per-reference bind (both `None` when there
    /// is no AT clause). For inline-bound (function-backed) tables the actual
    /// `on_bind` RPC runs once at attach with no AT, so the per-scan AT is
    /// carried on the bind request embedded in each `InitRequest` and read at
    /// init. Additive nullable columns — the C++ always emits them.
    pub at_unit: Option<String>,
    pub at_value: Option<String>,
}

/// `BindResponse` — flat result of `bind`.
#[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>,
}

// ---------------------------------------------------------------------------
// init
// ---------------------------------------------------------------------------

/// `InitRequest` — carried IPC-serialized inside the `request` binary column
/// of `init`. `bind_call` is itself an IPC-serialized [`BindRequest`] (Python
/// serializes nested dataclasses as binary), decoded separately.
#[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>,
}

/// `GlobalInitResponse` — the streaming header for `init`.
#[derive(Debug, Clone, VgiArrow)]
pub struct GlobalInitResponse {
    pub execution_id: Bytes,
    pub max_workers: i64,
    pub opaque_data: Option<Bytes>,
}

// ---------------------------------------------------------------------------
// catalog_attach
// ---------------------------------------------------------------------------

/// `CatalogAttachRequest` — IPC-serialized inside `request` of `catalog_attach`.
#[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>,
}

/// Request for `table_function_cardinality` / `table_function_statistics`
/// (boxes an IPC-serialized `BindRequest`).
#[derive(Debug, Clone, VgiArrow)]
pub struct CardinalityRequest {
    pub bind_call: Bytes,
    pub bind_opaque_data: Option<Bytes>,
}

/// Response for `table_function_cardinality`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CardinalityResponse {
    pub estimate: Option<i64>,
    pub max: Option<i64>,
}

/// `aggregate_window_init` — caches a partition for windowed evaluation.
#[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>,
}

/// `aggregate_window` — evaluate one output row over its sub-frames.
#[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>,
}

/// `aggregate_window_batch` — evaluate `count` consecutive output rows.
#[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>,
}

/// `aggregate_window` / `aggregate_window_batch` result.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowResponse {
    pub result_batch: Bytes,
}

/// `aggregate_window_destructor` — drops a cached partition.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateWindowDestructorRequest {
    pub function_name: String,
    pub execution_id: Bytes,
    pub partition_id: i64,
}

/// `table_function_dynamic_to_string` — post-execution profiling info.
#[derive(Debug, Clone, VgiArrow)]
pub struct DynamicToStringRequest {
    pub bind_call: Bytes,
    pub bind_opaque_data: Option<Bytes>,
    pub global_execution_id: Bytes,
}

/// `table_function_dynamic_to_string` result — ordered key/value pairs
/// surfaced as Extra Info under EXPLAIN ANALYZE.
#[derive(Debug, Clone, VgiArrow)]
pub struct DynamicToStringResponse {
    pub keys: Vec<String>,
    pub values: Vec<String>,
}

/// `aggregate_streaming_open` — start a streaming-partitioned session.
#[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>,
}

/// `aggregate_streaming_open` result — the session token.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingOpenResponse {
    pub execution_id: Bytes,
}

/// `aggregate_streaming_chunk` — process one input chunk in a session.
#[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>,
}

/// `aggregate_streaming_chunk` result — a same-length output batch.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingChunkResponse {
    pub result_batch: Bytes,
}

/// `aggregate_streaming_close` — end a session and free its state.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateStreamingCloseRequest {
    pub function_name: String,
    pub execution_id: Bytes,
    pub attach_opaque_data: Option<Bytes>,
}

/// One physical source backing a (possibly multi-branch) table scan.
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanBranch {
    pub function_name: String,
    pub arguments: Bytes,
    pub branch_filter: Option<String>,
    pub writable: bool,
}

/// Response for `catalog_table_scan_branches_get`. The `branches` list must be
/// non-empty (one entry per physical source; single-source tables return one).
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanBranchesResult {
    pub branches: Vec<Bytes>,
    pub required_extensions: Vec<String>,
}

/// Secret-type registration entry, IPC-serialized into
/// `CatalogAttachResult.secret_types`.
#[derive(Debug, Clone, VgiArrow)]
pub struct SecretTypeWire {
    pub name: String,
    pub description: String,
    pub parameters_schema: Bytes,
}

/// `CatalogAttachResult` — flat result of `catalog_attach`.
#[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 comment: Option<String>,
    pub tags: StrMap,
    pub supports_column_statistics: bool,
    pub resolved_data_version: Option<String>,
    pub resolved_implementation_version: Option<String>,
}

// ---------------------------------------------------------------------------
// catalog transactions / version / detach
// ---------------------------------------------------------------------------

/// Flat params: `catalog_transaction_begin`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionBeginParams {
    pub attach_opaque_data: Bytes,
}

/// Flat result: `catalog_transaction_begin`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionBeginResult {
    pub transaction_opaque_data: Option<Bytes>,
}

/// Flat params: `catalog_transaction_commit` / `_rollback`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogTransactionEndParams {
    pub attach_opaque_data: Bytes,
    pub transaction_opaque_data: Bytes,
}

/// Flat params: `catalog_detach`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogDetachParams {
    pub attach_opaque_data: Bytes,
}

/// Flat params: `catalog_version`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogVersionParams {
    pub attach_opaque_data: Bytes,
    pub transaction_opaque_data: Option<Bytes>,
}

/// Flat result: `catalog_version`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogVersionResult {
    pub version: i64,
}

// ---------------------------------------------------------------------------
// catalog schema discovery
// ---------------------------------------------------------------------------

/// Flat params: `catalog_schemas`.
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogSchemasParams {
    pub attach_opaque_data: Bytes,
    pub transaction_opaque_data: Option<Bytes>,
}

/// Flat params: `catalog_schema_get` and the `catalog_schema_contents_{tables,
/// views,indexes}` family (attach + name + optional tx).
#[derive(Debug, Clone, VgiArrow)]
pub struct CatalogSchemaNameParams {
    pub attach_opaque_data: Bytes,
    pub name: String,
    pub transaction_opaque_data: Option<Bytes>,
}

/// Flat params: `catalog_schema_contents_functions` (and `_macros`).
#[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>,
}

/// Shared flat result for every `catalog_*_get` / `_contents_*` method:
/// `items` is a list of IPC-serialized item structs.
#[derive(Debug, Clone, VgiArrow)]
pub struct ItemsResult {
    pub items: Vec<Bytes>,
}

// ---------------------------------------------------------------------------
// catalog item structs (IPC-serialized into ItemsResult.items)
// ---------------------------------------------------------------------------

/// `SchemaInfo` item.
#[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>,
}

/// One `examples` entry of `FunctionInfo`.
#[derive(Debug, Clone, VgiArrow)]
pub struct FunctionExample {
    pub sql: String,
    pub description: String,
    pub expected_output: Option<String>,
}

/// One `required_secrets` entry of `FunctionInfo`.
#[derive(Debug, Clone, VgiArrow)]
pub struct RequiredSecret {
    pub secret_type: String,
    pub scope: Option<String>,
    pub secret_name: Option<String>,
}

/// `TableInfo` item — describes a catalog table to DuckDB.
#[derive(Debug, Clone, VgiArrow)]
pub struct TableInfo {
    pub comment: Option<String>,
    pub tags: StrMap,
    pub name: String,
    pub schema_name: String,
    /// IPC-serialized Arrow schema of the table columns.
    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,
    /// IPC `ScanFunctionResult`, empty if not inlined.
    pub scan_function: Bytes,
    pub insert_function: Bytes,
    pub update_function: Bytes,
    pub delete_function: Bytes,
    /// Inlined optimizer cardinality. `None` → NULL on the wire, which the C++
    /// reads as "not inlined" → it fires the per-bind `table_function_cardinality`
    /// RPC instead. Emitting a sentinel (e.g. -1) would be read as an inlined
    /// value and wrongly skip the RPC.
    pub cardinality_estimate: InlineI64,
    pub cardinality_max: InlineI64,
    pub column_statistics: Bytes,
    pub bind_result: Bytes,
    /// Field paths the scan requires to be materialized (struct/list pushdown).
    /// Empty = no constraint. Added in the C++ protocol's 24-field TableInfo.
    pub required_field_filter_paths: Vec<String>,
}

/// `ViewInfo` item.
#[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,
}

/// `MacroInfo` item.
#[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,
}

/// `ScanFunctionResult` — names the table function that scans a catalog table.
#[derive(Debug, Clone, VgiArrow)]
pub struct ScanFunctionResult {
    pub function_name: String,
    pub arguments: Bytes,
    pub required_extensions: Vec<String>,
}

/// `FunctionInfo` item — describes a function to DuckDB. Field order matches
/// `FunctionInfoSchema` in the generated Go schemas.
#[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>,
}

// ---------------------------------------------------------------------------
// cardinality / statistics
// ---------------------------------------------------------------------------

/// Flat result: `table_function_cardinality`.
#[derive(Debug, Clone, VgiArrow)]
pub struct TableCardinality {
    pub estimate: Option<i64>,
    pub max: Option<i64>,
}

// ---------------------------------------------------------------------------
// table buffering (boxed in `request: binary`)
// ---------------------------------------------------------------------------

/// `TableBufferingProcessRequest` — sink one batch.
#[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>,
}

/// `TableBufferingProcessResponse`.
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingProcessResponse {
    pub state_id: Bytes,
}

/// `TableBufferingCombineRequest`.
#[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>,
}

/// `TableBufferingCombineResponse`.
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingCombineResponse {
    pub finalize_state_ids: Vec<Bytes>,
}

/// `TableBufferingDestructorRequest`.
#[derive(Debug, Clone, VgiArrow)]
pub struct TableBufferingDestructorRequest {
    pub function_name: String,
    pub execution_id: Bytes,
}

// ---------------------------------------------------------------------------
// aggregate (boxed in `request: binary`)
// ---------------------------------------------------------------------------

/// `AggregateBindRequest`.
#[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>,
}

/// `AggregateBindResponse`.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateBindResponse {
    pub output_schema: Bytes,
    pub execution_id: Bytes,
}

/// `AggregateUpdateRequest`.
#[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>,
}

/// `AggregateCombineRequest`.
#[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>,
}

/// `AggregateFinalizeRequest`.
#[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>,
}

/// `AggregateFinalizeResponse`.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateFinalizeResponse {
    pub result_batch: Bytes,
}

/// `AggregateDestructorRequest`.
#[derive(Debug, Clone, VgiArrow)]
pub struct AggregateDestructorRequest {
    pub function_name: String,
    pub execution_id: Bytes,
}