Scalar functions
On this page
One row in, one value out — the simplest function shape.
trait ScalarFunction
Section titled “trait ScalarFunction”pub trait ScalarFunction: Send + Sync { fn name(&self) -> &str;
fn metadata(&self) -> FunctionMetadata;
fn argument_specs(&self) -> Vec<ArgSpec>; fn secret_lookups(&self, _params: &BindParams) -> Vec<crate::secrets::SecretLookup> { Vec::new() } fn on_bind(&self, params: &BindParams) -> Result<BindResponse> { if let Some(ty) = self.metadata().return_type { return Ok(BindResponse::result(ty)); } let ty = params .input_schema .as_ref() .and_then(|s| s.fields().first().map(|f| f.data_type().clone())) .unwrap_or(DataType::Int64); Ok(BindResponse::result(ty)) } fn process( &self, params: &ProcessParams, batch: &arrow_array::RecordBatch, ) -> Result<arrow_array::RecordBatch>;
fn cache_control(&self) -> Option<crate::cache_control::CacheControl> { None }}Description
A scalar VGI function: one output row per input row.
A scalar function receives a RecordBatch of its
argument columns and returns a single-column batch (the column is named
result) with the same number of rows. Implement name,
metadata, argument_specs, and
process; on_bind has a sensible default
and is only overridden when the return type is computed from the argument
types. Register the function with
Worker::register_scalar.
Examples
Section titled “Examples”use std::sync::Arc;
use arrow_array::{cast::AsArray, ArrayRef, RecordBatch, StringArray};use arrow_schema::DataType;use vgi::{ArgSpec, FunctionMetadata, ProcessParams, ScalarFunction};use vgi_rpc::{Result, RpcError};
struct UpperCase;
impl ScalarFunction for UpperCase { fn name(&self) -> &str { "upper_case" }
fn metadata(&self) -> FunctionMetadata { FunctionMetadata { description: "Uppercase a string".into(), return_type: Some(DataType::Utf8), ..Default::default() } }
fn argument_specs(&self) -> Vec<ArgSpec> { vec![ArgSpec::column("value", 0, "varchar", "String to uppercase")] }
fn process(&self, params: &ProcessParams, batch: &RecordBatch) -> Result<RecordBatch> { let col = batch.column(0).as_string::<i32>(); let out: ArrayRef = Arc::new( col.iter().map(|v| v.map(str::to_uppercase)).collect::<StringArray>(), ); RecordBatch::try_new(params.output_schema.clone(), vec![out]) .map_err(|e| RpcError::runtime_error(e.to_string())) }}constant ADDABLE
Section titled “constant ADDABLE”pub const ADDABLE: TypeBound = TypeBound { name: "_is_addable_type", pred: is_addable,};Description
_is_addable_type: integer | floating | decimal | temporal.
struct ArgSpec
Section titled “struct ArgSpec”pub struct ArgSpec { pub name: String, pub position: i32, pub arrow_type: String, pub doc: String, pub is_const: bool, pub is_varargs: bool, pub arrow_data_type: Option<DataType>, pub type_bound: Option<TypeBound>, pub choices: Option<Vec<serde_json::Value>>, pub ge: Option<f64>, pub le: Option<f64>, pub gt: Option<f64>, pub lt: Option<f64>, pub pattern: Option<String>, pub default: Option<serde_json::Value>,}Description
Per-argument specification, used to build the function’s wire arg schema
(FunctionInfo.arguments) and validate type bounds at bind time.
Methods
method any_column
Section titled “method any_column”pub fn any_column(name: &str, position: i32, doc: &str) -> SelfA positional, non-const ANY-typed column argument.
method as_const
Section titled “method as_const”pub fn as_const(mut self) -> SelfMark this spec const.
method column
Section titled “method column”pub fn column(name: &str, position: i32, arrow_type: &str, doc: &str) -> SelfA positional, non-const column argument of a concrete VGI type string
(e.g. "int32", "varchar", "binary").
method column_typed
Section titled “method column_typed”pub fn column_typed(name: &str, position: i32, ty: DataType, doc: &str) -> SelfA positional column argument with an explicit Arrow type.
method const_arg
Section titled “method const_arg”pub fn const_arg(name: &str, position: i32, arrow_type: &str, doc: &str) -> SelfA positional const (bind-time scalar) argument of a concrete VGI type.
method const_typed
Section titled “method const_typed”pub fn const_typed(name: &str, position: i32, ty: DataType, doc: &str) -> SelfA positional const argument with an explicit Arrow type.
method varargs
Section titled “method varargs”pub fn varargs(mut self) -> SelfMark this spec variadic (consumes all remaining columns).
method with_bound
Section titled “method with_bound”pub fn with_bound(mut self, bound: TypeBound) -> SelfAttach a type bound.
method with_choices
Section titled “method with_choices”pub fn with_choices<I, V>(mut self, choices: I) -> Selfwhere I: IntoIterator<Item = V>, V: Into<serde_json::Value>,Declare the closed set of allowed values (vgi_choices).
method with_default
Section titled “method with_default”pub fn with_default<V: Into<serde_json::Value>>(mut self, default: V) -> SelfDefault value for the argument (vgi_default).
method with_ge
Section titled “method with_ge”pub fn with_ge(mut self, v: f64) -> SelfInclusive lower bound (value >= v), surfaced in vgi_range.
method with_gt
Section titled “method with_gt”pub fn with_gt(mut self, v: f64) -> SelfExclusive lower bound (value > v), surfaced in vgi_range.
method with_le
Section titled “method with_le”pub fn with_le(mut self, v: f64) -> SelfInclusive upper bound (value <= v), surfaced in vgi_range.
method with_lt
Section titled “method with_lt”pub fn with_lt(mut self, v: f64) -> SelfExclusive upper bound (value < v), surfaced in vgi_range.
method with_pattern
Section titled “method with_pattern”pub fn with_pattern(mut self, pattern: &str) -> SelfRegex the value must match (vgi_pattern).
struct BindParams
Section titled “struct BindParams”pub struct BindParams { pub input_schema: Option<SchemaRef>, pub arguments: crate::arguments::Arguments, pub settings: crate::settings::Settings, pub secrets: crate::secrets::Secrets, pub resolved_secrets_provided: bool, pub auth_principal: Option<String>, pub attach_opaque_data: Option<Vec<u8>>, pub transaction_opaque_data: Option<Vec<u8>>, pub storage: Option<crate::storage::SharedStorage>, pub copy_from: Option<crate::protocol::dtos::CopyFromContext>, pub copy_to: Option<crate::protocol::dtos::CopyToContext>,}Description
Parameters delivered to on_bind.
struct BindResponse
Section titled “struct BindResponse”pub struct BindResponse { pub output_schema: SchemaRef, pub opaque_data: Vec<u8>,}Description
Result of on_bind.
Methods
method result
Section titled “method result”pub fn result(ty: DataType) -> SelfA single result column of ty (the canonical scalar bind result).
struct FunctionMetadata
Section titled “struct FunctionMetadata”pub struct FunctionMetadata { pub description: String, pub stability: Option<String>, pub null_handling: Option<String>, pub categories: Vec<String>, pub examples: Vec<FunctionExample>, pub tags: Vec<(String, String)>, pub return_type: Option<DataType>, pub projection_pushdown: bool, pub filter_pushdown: bool, pub sampling_pushdown: bool, pub auto_apply_filters: bool, pub supports_batch_index: bool, pub partition_kind: Option<String>, pub order_preservation: Option<String>, pub sink_order_dependent: bool, pub source_order_dependent: bool, pub requires_input_batch_index: bool, pub supports_window: bool, pub streaming_partitioned: bool, pub late_materialization: bool, pub required_settings: Vec<String>, pub required_secrets: Vec<crate::secrets::SecretLookup>, pub max_workers: i32, pub input_from_args: bool,}Description
Optimizer- and discovery-facing function metadata (FunctionInfo).
constant MULTIPLIABLE
Section titled “constant MULTIPLIABLE”pub const MULTIPLIABLE: TypeBound = TypeBound { name: "_is_multipliable_type", pred: is_multipliable,};Description
_is_multipliable_type: integer | floating | decimal (no temporal).
struct ProcessParams
Section titled “struct ProcessParams”pub struct ProcessParams { pub output_schema: SchemaRef, pub input_schema: Option<SchemaRef>, pub execution_id: Vec<u8>, pub substream_id: Option<Vec<u8>>, pub init_opaque_data: Vec<u8>, pub arguments: crate::arguments::Arguments, pub settings: crate::settings::Settings, pub secrets: crate::secrets::Secrets, pub auth_principal: Option<String>, pub projection_ids: Option<Vec<i64>>, pub pushdown_filters: Option<Vec<u8>>, pub join_keys: Vec<Vec<u8>>, pub storage: Option<crate::storage::SharedStorage>, pub order_by_column: Option<String>, pub order_by_direction: Option<String>, pub order_by_null_order: Option<String>, pub order_by_limit: Option<i64>, pub tablesample_percentage: Option<f64>, pub tablesample_seed: Option<i64>, pub attach_opaque_data: Option<Vec<u8>>, pub at_unit: Option<String>, pub at_value: Option<String>, pub copy_from: Option<crate::protocol::dtos::CopyFromContext>, pub if_none_match: Option<String>, pub if_modified_since: Option<String>,}Description
Parameters delivered to process.
struct TypeBound
Section titled “struct TypeBound”pub struct TypeBound { pub name: &'static str, pub pred: fn(&DataType) -> bool,}Description
A named type-bound predicate for ANY-typed arguments. Checked at bind:
the input field type must satisfy the predicate or bind errors with the
bound’s name (mirrors Python’s type_bound=<predicate>).
function validate_arg_constraints
Section titled “function validate_arg_constraints”pub fn validate_arg_constraints( specs: &[ArgSpec], args: &crate::arguments::Arguments,) -> Result<()>Description
Enforce a function’s const-argument value constraints at bind time.
Const arguments are bind-time scalars, so their declared choices, numeric
range (ge/le/gt/lt), and pattern constraints are validated once
here — mirroring the Python SDK, so a discovered constraint (surfaced via
vgi_function_arguments()) is actually binding. A violating value returns an
RpcError::value_error; a null const value skips its value constraints, and
column (non-const) arguments are not enforced here (type bounds are
[validate_type_bounds]’s job).
function validate_type_bounds
Section titled “function validate_type_bounds”pub fn validate_type_bounds(specs: &[ArgSpec], input_schema: Option<&SchemaRef>) -> Result<()>Description
Validate each spec’s type bound against the input schema. Errors (value
error) naming the failed bound, matching Python’s SchemaValidationError.