use super::Value;
use crate::error::Result;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub enum FunctionSignature {
Nullary(fn() -> Value),
Unary(fn(&Value) -> Result<Value>),
Binary(fn(&Value, &Value) -> Result<Value>),
Ternary(fn(&Value, &Value, &Value) -> Result<Value>),
Variadic(fn(&[Value]) -> Result<Value>),
UnaryOptional(fn(&Value, Option<&Value>) -> Result<Value>),
Aggregate(fn(&[Value]) -> Result<Value>),
}
#[derive(Debug, Clone)]
pub struct FunctionInfo {
pub name: String,
pub signature: FunctionSignature,
pub description: String,
pub category: FunctionCategory,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FunctionCategory {
Math,
String,
Conversion,
DateTime,
System,
Conditional,
Aggregate,
}
pub struct FunctionRegistry {
functions: HashMap<String, FunctionInfo>,
}
impl FunctionRegistry {
pub fn new() -> Self {
let mut registry = Self {
functions: HashMap::new(),
};
registry.register_all();
registry
}
pub fn register(&mut self, info: FunctionInfo) {
let name = info.name.to_uppercase();
self.functions.insert(name, info);
}
pub fn get(&self, name: &str) -> Option<&FunctionInfo> {
self.functions.get(&name.to_uppercase())
}
pub fn list(&self) -> Vec<&FunctionInfo> {
self.functions.values().collect()
}
pub fn list_by_category(&self, category: FunctionCategory) -> Vec<&FunctionInfo> {
self.functions
.values()
.filter(|f| f.category == category)
.collect()
}
fn register_all(&mut self) {
self.register(FunctionInfo {
name: "ABS".to_string(),
signature: FunctionSignature::Unary(super::math::abs),
description: "Absolute value".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "CEIL".to_string(),
signature: FunctionSignature::Unary(super::math::ceil),
description: "Round up to nearest integer".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "FLOOR".to_string(),
signature: FunctionSignature::Unary(super::math::floor),
description: "Round down to nearest integer".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "SQRT".to_string(),
signature: FunctionSignature::Unary(super::math::sqrt),
description: "Square root".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "POW".to_string(),
signature: FunctionSignature::Binary(super::math::pow),
description: "Power (x^y)".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "EXP".to_string(),
signature: FunctionSignature::Unary(super::math::exp),
description: "e^x".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "LN".to_string(),
signature: FunctionSignature::Unary(super::math::ln),
description: "Natural logarithm".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "LOG10".to_string(),
signature: FunctionSignature::Unary(super::math::log10),
description: "Base-10 logarithm".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "MOD".to_string(),
signature: FunctionSignature::Binary(super::math::modulo),
description: "Modulo operation".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "SIGN".to_string(),
signature: FunctionSignature::Unary(super::math::sign),
description: "Sign of number (-1, 0, 1)".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "PI".to_string(),
signature: FunctionSignature::Nullary(super::math::pi),
description: "Pi constant".to_string(),
category: FunctionCategory::Math,
});
self.register(FunctionInfo {
name: "CONCAT".to_string(),
signature: FunctionSignature::Variadic(super::string::concat),
description: "Concatenate strings".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "UPPER".to_string(),
signature: FunctionSignature::Unary(super::string::upper),
description: "Convert to uppercase".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "LOWER".to_string(),
signature: FunctionSignature::Unary(super::string::lower),
description: "Convert to lowercase".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "LENGTH".to_string(),
signature: FunctionSignature::Unary(super::string::length),
description: "String length".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "TRIM".to_string(),
signature: FunctionSignature::Unary(super::string::trim),
description: "Remove whitespace".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "REVERSE".to_string(),
signature: FunctionSignature::Unary(super::string::reverse),
description: "Reverse string".to_string(),
category: FunctionCategory::String,
});
self.register(FunctionInfo {
name: "ATOF".to_string(),
signature: FunctionSignature::Unary(super::conversion::atof),
description: "ASCII to float".to_string(),
category: FunctionCategory::Conversion,
});
self.register(FunctionInfo {
name: "ATOI".to_string(),
signature: FunctionSignature::Unary(super::conversion::atoi),
description: "ASCII to integer".to_string(),
category: FunctionCategory::Conversion,
});
self.register(FunctionInfo {
name: "HEX".to_string(),
signature: FunctionSignature::Unary(super::conversion::hex),
description: "Convert to hexadecimal".to_string(),
category: FunctionCategory::Conversion,
});
self.register(FunctionInfo {
name: "BIN".to_string(),
signature: FunctionSignature::Unary(super::conversion::bin),
description: "Convert to binary".to_string(),
category: FunctionCategory::Conversion,
});
self.register(FunctionInfo {
name: "NOW".to_string(),
signature: FunctionSignature::Nullary(super::datetime::now),
description: "Current date and time".to_string(),
category: FunctionCategory::DateTime,
});
self.register(FunctionInfo {
name: "CURDATE".to_string(),
signature: FunctionSignature::Nullary(super::datetime::curdate),
description: "Current date".to_string(),
category: FunctionCategory::DateTime,
});
self.register(FunctionInfo {
name: "CURTIME".to_string(),
signature: FunctionSignature::Nullary(super::datetime::curtime),
description: "Current time".to_string(),
category: FunctionCategory::DateTime,
});
self.register(FunctionInfo {
name: "VERSION".to_string(),
signature: FunctionSignature::Nullary(super::system::version),
description: "DDB version".to_string(),
category: FunctionCategory::System,
});
self.register(FunctionInfo {
name: "UUID".to_string(),
signature: FunctionSignature::Nullary(super::system::uuid),
description: "Generate UUID".to_string(),
category: FunctionCategory::System,
});
self.register(FunctionInfo {
name: "IF".to_string(),
signature: FunctionSignature::Ternary(super::conditional::if_fn),
description: "Conditional expression".to_string(),
category: FunctionCategory::Conditional,
});
self.register(FunctionInfo {
name: "IFNULL".to_string(),
signature: FunctionSignature::Binary(super::conditional::ifnull),
description: "Return alt if NULL".to_string(),
category: FunctionCategory::Conditional,
});
self.register(FunctionInfo {
name: "NULLIF".to_string(),
signature: FunctionSignature::Binary(super::conditional::nullif),
description: "Return NULL if equal".to_string(),
category: FunctionCategory::Conditional,
});
self.register(FunctionInfo {
name: "COALESCE".to_string(),
signature: FunctionSignature::Variadic(super::conditional::coalesce),
description: "First non-NULL value".to_string(),
category: FunctionCategory::Conditional,
});
self.register(FunctionInfo {
name: "MAX".to_string(),
signature: FunctionSignature::Aggregate(super::aggregate::max),
description: "Maximum value".to_string(),
category: FunctionCategory::Aggregate,
});
self.register(FunctionInfo {
name: "MIN".to_string(),
signature: FunctionSignature::Aggregate(super::aggregate::min),
description: "Minimum value".to_string(),
category: FunctionCategory::Aggregate,
});
}
}
impl Default for FunctionRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry() {
let registry = FunctionRegistry::new();
assert!(registry.get("ABS").is_some());
assert!(registry.get("CONCAT").is_some());
assert!(registry.get("NOW").is_some());
assert!(registry.get("nonexistent").is_none());
}
#[test]
fn test_category_filter() {
let registry = FunctionRegistry::new();
let math_funcs = registry.list_by_category(FunctionCategory::Math);
assert!(!math_funcs.is_empty());
}
}