use crate::exec::result::Row;
use crate::storage::Value;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, thiserror::Error)]
pub enum FunctionError {
#[error("Invalid argument count: expected {expected}, got {actual}")]
InvalidArgumentCount { expected: usize, actual: usize },
#[error("Invalid argument type: {message}")]
InvalidArgumentType { message: String },
#[error("Function execution failed: {message}")]
ExecutionError { message: String },
#[error("Unsupported operation: {operation}")]
UnsupportedOperation { operation: String },
}
pub type FunctionResult<T> = Result<T, FunctionError>;
pub struct FunctionContext {
pub rows: Vec<Row>,
pub variables: HashMap<String, Value>,
pub arguments: Vec<Value>,
pub storage_manager: Option<Arc<crate::storage::StorageManager>>,
pub current_graph: Option<Arc<crate::storage::GraphCache>>,
pub graph_name: Option<String>,
}
impl FunctionContext {
pub fn new(rows: Vec<Row>, variables: HashMap<String, Value>, arguments: Vec<Value>) -> Self {
Self {
rows,
variables,
arguments,
storage_manager: None,
current_graph: None,
graph_name: None,
}
}
pub fn with_storage(
rows: Vec<Row>,
variables: HashMap<String, Value>,
arguments: Vec<Value>,
storage_manager: Option<Arc<crate::storage::StorageManager>>,
current_graph: Option<Arc<crate::storage::GraphCache>>,
graph_name: Option<String>,
) -> Self {
Self {
rows,
variables,
arguments,
storage_manager,
current_graph,
graph_name,
}
}
pub fn get_argument(&self, index: usize) -> FunctionResult<&Value> {
self.arguments
.get(index)
.ok_or_else(|| FunctionError::InvalidArgumentCount {
expected: index + 1,
actual: self.arguments.len(),
})
}
pub fn argument_count(&self) -> usize {
self.arguments.len()
}
pub fn validate_argument_count(&self, expected: usize) -> FunctionResult<()> {
if self.argument_count() != expected {
return Err(FunctionError::InvalidArgumentCount {
expected,
actual: self.argument_count(),
});
}
Ok(())
}
}
pub trait Function: Send + Sync + std::fmt::Debug {
#[allow(dead_code)] fn name(&self) -> &str;
#[allow(dead_code)] fn description(&self) -> &str;
#[allow(dead_code)] fn argument_count(&self) -> usize;
fn execute(&self, context: &FunctionContext) -> FunctionResult<Value>;
#[allow(dead_code)] fn return_type(&self) -> &str;
fn graph_context_required(&self) -> bool {
true }
#[allow(dead_code)] fn is_variadic(&self) -> bool {
false }
}