mod builtin;
mod custom;
mod table;
mod udf;
#[cfg(test)]
mod tests;
pub use udf::DynamicUdfInfo;
use super::{BuiltinFunction, CustomFunction, TableFunction};
use crate::executor::expression::evaluation_context::graph_storage::GraphStorageRef;
use crate::executor::expression::{ExpressionError, ExpressionErrorType};
use linkrs_core::DataType;
use linkrs_core::Value;
use std::collections::HashMap;
use std::sync::Arc;
use udf::LoadedExtension;
#[derive(Debug, Clone)]
pub struct RegistryEntry {
pub function: BuiltinFunction,
pub return_type: DataType,
}
#[derive(Debug)]
pub struct FunctionRegistry {
builtin_functions: HashMap<String, RegistryEntry>,
custom_functions: HashMap<String, CustomFunction>,
table_functions: HashMap<String, Box<dyn TableFunction>>,
dynamic_libraries: HashMap<String, LoadedExtension>,
}
impl Default for FunctionRegistry {
fn default() -> Self {
Self::new()
}
}
impl FunctionRegistry {
pub fn new() -> Self {
let mut registry = Self {
builtin_functions: HashMap::new(),
custom_functions: HashMap::new(),
table_functions: HashMap::new(),
dynamic_libraries: HashMap::new(),
};
registry.register_all_builtin_functions();
registry.register_builtin_table_functions();
registry
}
fn resolve_entry(&self, name: &str) -> Option<&RegistryEntry> {
let upper = name.to_uppercase();
self.builtin_functions.get(&upper)
}
pub fn contains(&self, name: &str) -> bool {
let upper_name = name.to_uppercase();
self.builtin_functions.contains_key(&upper_name)
|| self.custom_functions.contains_key(&upper_name)
}
pub fn function_names(&self) -> Vec<&str> {
let mut names: Vec<&str> = self.builtin_functions.keys().map(|s| s.as_str()).collect();
names.extend(self.custom_functions.keys().map(|s| s.as_str()));
names
}
pub fn execute(&self, name: &str, args: &[Value]) -> Result<Value, ExpressionError> {
let upper_name = name.to_uppercase();
if let Some(entry) = self.builtin_functions.get(&upper_name) {
return entry.function.execute(args);
}
if let Some(func) = self.custom_functions.get(&upper_name) {
return func.execute(args);
}
Err(ExpressionError::new(
ExpressionErrorType::UndefinedFunction,
format!("Undefined function: {}", name),
))
}
pub fn execute_with_storage(
&self,
name: &str,
args: &[Value],
storage: &GraphStorageRef,
) -> Result<Value, ExpressionError> {
let upper_name = name.to_uppercase();
if let Some(entry) = self.builtin_functions.get(&upper_name) {
return entry.function.execute_with_storage(args, storage);
}
if let Some(func) = self.custom_functions.get(&upper_name) {
return func.execute(args);
}
Err(ExpressionError::new(
ExpressionErrorType::UndefinedFunction,
format!("Undefined function: {}", name),
))
}
}
pub fn global_registry() -> Arc<FunctionRegistry> {
use std::sync::OnceLock;
static REGISTRY: OnceLock<Arc<FunctionRegistry>> = OnceLock::new();
REGISTRY
.get_or_init(|| Arc::new(FunctionRegistry::new()))
.clone()
}
pub fn global_registry_ref() -> &'static FunctionRegistry {
use std::sync::OnceLock;
static REGISTRY: OnceLock<FunctionRegistry> = OnceLock::new();
REGISTRY.get_or_init(FunctionRegistry::new)
}