1use anyhow::{anyhow, Result};
2use std::collections::HashMap;
3use std::fmt;
4use std::sync::Arc;
5
6use crate::data::datatable::DataValue;
7
8pub mod astronomy;
9pub mod chemistry;
10pub mod comparison;
11pub mod constants;
12pub mod mathematics;
13pub mod string_methods;
14
15pub use string_methods::MethodFunction;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum FunctionCategory {
21 Constant, Mathematical, Astronomical, Chemical, Date, String, Aggregate, }
29
30impl fmt::Display for FunctionCategory {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 FunctionCategory::Constant => write!(f, "Constant"),
34 FunctionCategory::Mathematical => write!(f, "Mathematical"),
35 FunctionCategory::Astronomical => write!(f, "Astronomical"),
36 FunctionCategory::Chemical => write!(f, "Chemical"),
37 FunctionCategory::Date => write!(f, "Date"),
38 FunctionCategory::String => write!(f, "String"),
39 FunctionCategory::Aggregate => write!(f, "Aggregate"),
40 }
41 }
42}
43
44#[derive(Debug, Clone)]
46pub enum ArgCount {
47 Fixed(usize),
49 Range(usize, usize),
51 Variadic,
53}
54
55impl ArgCount {
56 pub fn is_valid(&self, count: usize) -> bool {
57 match self {
58 ArgCount::Fixed(n) => count == *n,
59 ArgCount::Range(min, max) => count >= *min && count <= *max,
60 ArgCount::Variadic => true,
61 }
62 }
63
64 pub fn description(&self) -> String {
65 match self {
66 ArgCount::Fixed(0) => "no arguments".to_string(),
67 ArgCount::Fixed(1) => "1 argument".to_string(),
68 ArgCount::Fixed(n) => format!("{} arguments", n),
69 ArgCount::Range(min, max) => format!("{} to {} arguments", min, max),
70 ArgCount::Variadic => "any number of arguments".to_string(),
71 }
72 }
73}
74
75#[derive(Debug, Clone)]
77pub struct FunctionSignature {
78 pub name: &'static str,
79 pub category: FunctionCategory,
80 pub arg_count: ArgCount,
81 pub description: &'static str,
82 pub returns: &'static str,
83 pub examples: Vec<&'static str>,
84}
85
86pub trait SqlFunction: Send + Sync {
88 fn signature(&self) -> FunctionSignature;
90
91 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue>;
93
94 fn validate_args(&self, args: &[DataValue]) -> Result<()> {
96 let sig = self.signature();
97 if !sig.arg_count.is_valid(args.len()) {
98 return Err(anyhow!(
99 "{}() expects {}, got {}",
100 sig.name,
101 sig.arg_count.description(),
102 args.len()
103 ));
104 }
105 Ok(())
106 }
107}
108
109pub struct FunctionRegistry {
111 functions: HashMap<String, Box<dyn SqlFunction>>,
112 by_category: HashMap<FunctionCategory, Vec<String>>,
113 methods: HashMap<String, Arc<dyn MethodFunction>>,
114}
115
116impl FunctionRegistry {
117 pub fn new() -> Self {
119 let mut registry = Self {
120 functions: HashMap::new(),
121 by_category: HashMap::new(),
122 methods: HashMap::new(),
123 };
124
125 registry.register_constants();
127 registry.register_astronomical_functions();
128 registry.register_chemical_functions();
129 registry.register_mathematical_functions();
130 registry.register_string_methods();
131 registry.register_comparison_functions();
132
133 registry
134 }
135
136 pub fn register(&mut self, func: Box<dyn SqlFunction>) {
138 let sig = func.signature();
139 let name = sig.name.to_uppercase();
140 let category = sig.category;
141
142 self.functions.insert(name.clone(), func);
144
145 self.by_category
147 .entry(category)
148 .or_insert_with(Vec::new)
149 .push(name);
150 }
151
152 pub fn get(&self, name: &str) -> Option<&dyn SqlFunction> {
154 self.functions.get(&name.to_uppercase()).map(|b| b.as_ref())
155 }
156
157 pub fn contains(&self, name: &str) -> bool {
159 self.functions.contains_key(&name.to_uppercase())
160 }
161
162 pub fn autocomplete(&self, prefix: &str) -> Vec<FunctionSignature> {
164 let prefix_upper = prefix.to_uppercase();
165 self.functions
166 .iter()
167 .filter(|(name, _)| name.starts_with(&prefix_upper))
168 .map(|(_, func)| func.signature())
169 .collect()
170 }
171
172 pub fn get_by_category(&self, category: FunctionCategory) -> Vec<FunctionSignature> {
174 self.by_category
175 .get(&category)
176 .map(|names| {
177 names
178 .iter()
179 .filter_map(|name| self.functions.get(name))
180 .map(|func| func.signature())
181 .collect()
182 })
183 .unwrap_or_default()
184 }
185
186 pub fn all_functions(&self) -> Vec<FunctionSignature> {
188 self.functions
189 .values()
190 .map(|func| func.signature())
191 .collect()
192 }
193
194 pub fn register_method(&mut self, method: Arc<dyn MethodFunction>) {
196 let method_name = method.method_name().to_uppercase();
197 self.methods.insert(method_name, method);
198 }
199
200 pub fn get_method(&self, name: &str) -> Option<Arc<dyn MethodFunction>> {
202 if let Some(method) = self.methods.get(&name.to_uppercase()) {
204 return Some(Arc::clone(method));
205 }
206
207 for method in self.methods.values() {
209 if method.handles_method(name) {
210 return Some(Arc::clone(method));
211 }
212 }
213
214 None
215 }
216
217 pub fn has_method(&self, name: &str) -> bool {
219 self.get_method(name).is_some()
220 }
221
222 pub fn generate_markdown_docs(&self) -> String {
224 use std::fmt::Write;
225 let mut doc = String::new();
226
227 writeln!(&mut doc, "# SQL CLI Function Reference\n").unwrap();
228 writeln!(
229 &mut doc,
230 "This document is auto-generated from the function registry.\n"
231 )
232 .unwrap();
233
234 let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
236 categories.sort_by_key(|c| format!("{:?}", c));
237
238 for category in categories {
239 let functions = self.get_by_category(category);
240 if functions.is_empty() {
241 continue;
242 }
243
244 writeln!(&mut doc, "## {} Functions\n", category).unwrap();
245
246 let mut functions = functions;
248 functions.sort_by_key(|f| f.name);
249
250 for func in functions {
251 writeln!(&mut doc, "### {}()\n", func.name).unwrap();
252 writeln!(&mut doc, "**Description:** {}\n", func.description).unwrap();
253 writeln!(
254 &mut doc,
255 "**Arguments:** {}\n",
256 func.arg_count.description()
257 )
258 .unwrap();
259 writeln!(&mut doc, "**Returns:** {}\n", func.returns).unwrap();
260
261 if !func.examples.is_empty() {
262 writeln!(&mut doc, "**Examples:**").unwrap();
263 writeln!(&mut doc, "```sql").unwrap();
264 for example in &func.examples {
265 writeln!(&mut doc, "{}", example).unwrap();
266 }
267 writeln!(&mut doc, "```\n").unwrap();
268 }
269 }
270 }
271
272 doc
273 }
274
275 pub fn generate_function_help(&self, name: &str) -> Option<String> {
277 self.get(name).map(|func| {
278 let sig = func.signature();
279 let mut help = String::new();
280 use std::fmt::Write;
281
282 writeln!(&mut help, "Function: {}()", sig.name).unwrap();
283 writeln!(&mut help, "Category: {}", sig.category).unwrap();
284 writeln!(&mut help, "Description: {}", sig.description).unwrap();
285 writeln!(&mut help, "Arguments: {}", sig.arg_count.description()).unwrap();
286 writeln!(&mut help, "Returns: {}", sig.returns).unwrap();
287
288 if !sig.examples.is_empty() {
289 writeln!(&mut help, "\nExamples:").unwrap();
290 for example in &sig.examples {
291 writeln!(&mut help, " {}", example).unwrap();
292 }
293 }
294
295 help
296 })
297 }
298
299 pub fn list_functions(&self) -> String {
301 use std::fmt::Write;
302 let mut list = String::new();
303
304 writeln!(&mut list, "Available SQL Functions:\n").unwrap();
305
306 let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
307 categories.sort_by_key(|c| format!("{:?}", c));
308
309 for category in categories {
310 let functions = self.get_by_category(category);
311 if functions.is_empty() {
312 continue;
313 }
314
315 writeln!(&mut list, "{} Functions:", category).unwrap();
316
317 let mut functions = functions;
318 functions.sort_by_key(|f| f.name);
319
320 for func in functions {
321 writeln!(
322 &mut list,
323 " {:20} - {}",
324 format!("{}()", func.name),
325 func.description
326 )
327 .unwrap();
328 }
329 writeln!(&mut list).unwrap();
330 }
331
332 list
333 }
334
335 fn register_constants(&mut self) {
337 use constants::*;
338
339 self.register(Box::new(PiFunction));
340 self.register(Box::new(EFunction));
341 self.register(Box::new(MeFunction)); self.register(Box::new(MassElectronFunction)); }
344
345 fn register_astronomical_functions(&mut self) {
347 use astronomy::*;
348
349 self.register(Box::new(MassEarthFunction));
350 self.register(Box::new(MassSunFunction));
351 self.register(Box::new(MassMoonFunction));
352 self.register(Box::new(AuFunction)); self.register(Box::new(LightYearFunction));
354 self.register(Box::new(ParsecFunction));
355
356 self.register(Box::new(MassMercuryFunction));
358 self.register(Box::new(MassVenusFunction));
359 self.register(Box::new(MassMarsFunction));
360 self.register(Box::new(MassJupiterFunction));
361 self.register(Box::new(MassSaturnFunction));
362 self.register(Box::new(MassUranusFunction));
363 self.register(Box::new(MassNeptuneFunction));
364
365 self.register(Box::new(RadiusSunFunction));
367 self.register(Box::new(RadiusEarthFunction));
368 self.register(Box::new(RadiusMoonFunction));
369 self.register(Box::new(RadiusMercuryFunction));
370 self.register(Box::new(RadiusVenusFunction));
371 self.register(Box::new(RadiusMarsFunction));
372 self.register(Box::new(RadiusJupiterFunction));
373 self.register(Box::new(RadiusSaturnFunction));
374 self.register(Box::new(RadiusUranusFunction));
375 self.register(Box::new(RadiusNeptuneFunction));
376 }
377
378 fn register_chemical_functions(&mut self) {
380 use chemistry::*;
381
382 self.register(Box::new(AvogadroFunction));
383 self.register(Box::new(AtomicMassFunction));
384 self.register(Box::new(AtomicNumberFunction));
385 }
386
387 fn register_string_methods(&mut self) {
389 string_methods::register_string_methods(self);
390 }
391
392 fn register_comparison_functions(&mut self) {
394 comparison::register_comparison_functions(self);
395 }
396
397 fn register_mathematical_functions(&mut self) {
399 use mathematics::*;
400
401 self.register(Box::new(PrimeFunction));
402 self.register(Box::new(IsPrimeFunction));
403 self.register(Box::new(PrimeCountFunction));
404 self.register(Box::new(NextPrimeFunction));
405 self.register(Box::new(PrevPrimeFunction));
406 }
407}
408
409impl Default for FunctionRegistry {
410 fn default() -> Self {
411 Self::new()
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418
419 #[test]
420 fn test_registry_creation() {
421 let registry = FunctionRegistry::new();
422
423 assert!(registry.contains("PI"));
425 assert!(registry.contains("MASS_EARTH"));
426 assert!(registry.contains("ME"));
427 }
428
429 #[test]
430 fn test_case_insensitive_lookup() {
431 let registry = FunctionRegistry::new();
432
433 assert!(registry.get("pi").is_some());
434 assert!(registry.get("PI").is_some());
435 assert!(registry.get("Pi").is_some());
436 }
437
438 #[test]
439 fn test_autocomplete() {
440 let registry = FunctionRegistry::new();
441
442 let mass_functions = registry.autocomplete("MASS");
443 assert!(!mass_functions.is_empty());
444
445 let names: Vec<&str> = mass_functions.iter().map(|sig| sig.name).collect();
447 assert!(names.contains(&"MASS_EARTH"));
448 assert!(names.contains(&"MASS_SUN"));
449 }
450}