Skip to content
Query.Farm
Talk with Us

Scalar functions

On this page

One row in, one value out — the simplest function shape.

source
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.

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()))
}
}
source
pub const ADDABLE: TypeBound = TypeBound {
name: "_is_addable_type",
pred: is_addable,
};

Description

_is_addable_type: integer | floating | decimal | temporal.

source
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

source
pub fn any_column(name: &str, position: i32, doc: &str) -> Self

A positional, non-const ANY-typed column argument.

source
pub fn as_const(mut self) -> Self

Mark this spec const.

source
pub fn column(name: &str, position: i32, arrow_type: &str, doc: &str) -> Self

A positional, non-const column argument of a concrete VGI type string (e.g. "int32", "varchar", "binary").

source
pub fn column_typed(name: &str, position: i32, ty: DataType, doc: &str) -> Self

A positional column argument with an explicit Arrow type.

source
pub fn const_arg(name: &str, position: i32, arrow_type: &str, doc: &str) -> Self

A positional const (bind-time scalar) argument of a concrete VGI type.

source
pub fn const_typed(name: &str, position: i32, ty: DataType, doc: &str) -> Self

A positional const argument with an explicit Arrow type.

source
pub fn varargs(mut self) -> Self

Mark this spec variadic (consumes all remaining columns).

source
pub fn with_bound(mut self, bound: TypeBound) -> Self

Attach a type bound.

source
pub fn with_choices<I, V>(mut self, choices: I) -> Self
where
I: IntoIterator<Item = V>,
V: Into<serde_json::Value>,

Declare the closed set of allowed values (vgi_choices).

source
pub fn with_default<V: Into<serde_json::Value>>(mut self, default: V) -> Self

Default value for the argument (vgi_default).

source
pub fn with_ge(mut self, v: f64) -> Self

Inclusive lower bound (value >= v), surfaced in vgi_range.

source
pub fn with_gt(mut self, v: f64) -> Self

Exclusive lower bound (value > v), surfaced in vgi_range.

source
pub fn with_le(mut self, v: f64) -> Self

Inclusive upper bound (value <= v), surfaced in vgi_range.

source
pub fn with_lt(mut self, v: f64) -> Self

Exclusive upper bound (value < v), surfaced in vgi_range.

source
pub fn with_pattern(mut self, pattern: &str) -> Self

Regex the value must match (vgi_pattern).

source
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.

source
pub struct BindResponse {
pub output_schema: SchemaRef,
pub opaque_data: Vec<u8>,
}

Description

Result of on_bind.

Methods

source
pub fn result(ty: DataType) -> Self

A single result column of ty (the canonical scalar bind result).

source
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).

source
pub const MULTIPLIABLE: TypeBound = TypeBound {
name: "_is_multipliable_type",
pred: is_multipliable,
};

Description

_is_multipliable_type: integer | floating | decimal (no temporal).

source
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.

source
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>).

source
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).

source
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.