Custom Functions¶
Add user-defined functions (UDFs) to extend GQL.
Rust-only
Custom function registration is currently available only through the Rust API. The Python, Node.js, and WASM bindings do not expose function registration methods.
Registering Functions¶
use grafeo::{GrafeoDB, Value};
let db = GrafeoDB::new_in_memory()?;
// Register a scalar function
db.register_function("double", |args| {
match &args[0] {
Value::Int64(n) => Ok(Value::Int64(n * 2)),
_ => Err("Expected integer".into())
}
})?;
Using Custom Functions¶
Once registered, custom functions can be called from any query language:
Function Types¶
Scalar Functions¶
Return a single value:
db.register_function("uppercase", |args| {
match &args[0] {
Value::String(s) => Ok(Value::String(s.to_uppercase())),
_ => Err("Expected string".into())
}
})?;
Aggregate Functions¶
Aggregate over multiple values:
db.register_aggregate("product", AggregateFunction {
init: || Value::Int64(1),
step: |acc, val| {
match (acc, val) {
(Value::Int64(a), Value::Int64(v)) => Value::Int64(a * v),
_ => acc
}
},
finalize: |acc| acc,
})?;
Table Functions¶
Return multiple rows:
db.register_table_function("generate_series", |args| {
let start = args[0].as_int()?;
let end = args[1].as_int()?;
Ok((start..=end).map(|i| vec![Value::Int64(i)]).collect())
})?;
Function Signatures¶
// Define function with explicit signature
db.register_function_with_signature(
"add",
FunctionSignature {
args: vec![DataType::Int64, DataType::Int64],
returns: DataType::Int64,
},
|args| {
let a = args[0].as_int()?;
let b = args[1].as_int()?;
Ok(Value::Int64(a + b))
}
)?;
Best Practices¶
- Validate Input - Check argument types and counts
- Handle Nulls - Decide null handling behavior
- Document - Provide clear function documentation
- Test - Unit test all custom functions
- Performance - Keep functions efficient for use in queries