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 base_conversion;
10pub mod case_convert;
11pub mod chemistry;
12pub mod comparison;
13pub mod constants;
14pub mod convert;
15pub mod date_time;
16pub mod financial;
17pub mod format;
18pub mod format_number;
19pub mod geometry;
20pub mod group_num;
21pub mod hash;
22pub mod integer_limits;
23pub mod math;
24pub mod mathematics;
25pub mod number_words;
26pub mod particle_charges;
27pub mod physics;
28pub mod random;
29pub mod roman;
30pub mod solar_system;
31pub mod statistics;
32pub mod string_fun;
33pub mod string_methods;
34pub mod string_utils;
35pub mod text_processing;
36pub mod trigonometry;
37pub mod type_checking;
38
39pub use string_methods::MethodFunction;
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum FunctionCategory {
45 Constant, Mathematical, Statistical, Astronomical, Chemical, Date, String, Aggregate, Conversion, }
55
56impl fmt::Display for FunctionCategory {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 match self {
59 FunctionCategory::Constant => write!(f, "Constant"),
60 FunctionCategory::Mathematical => write!(f, "Mathematical"),
61 FunctionCategory::Statistical => write!(f, "Statistical"),
62 FunctionCategory::Astronomical => write!(f, "Astronomical"),
63 FunctionCategory::Chemical => write!(f, "Chemical"),
64 FunctionCategory::Date => write!(f, "Date"),
65 FunctionCategory::String => write!(f, "String"),
66 FunctionCategory::Aggregate => write!(f, "Aggregate"),
67 FunctionCategory::Conversion => write!(f, "Conversion"),
68 }
69 }
70}
71
72#[derive(Debug, Clone)]
74pub enum ArgCount {
75 Fixed(usize),
77 Range(usize, usize),
79 Variadic,
81}
82
83impl ArgCount {
84 #[must_use]
85 pub fn is_valid(&self, count: usize) -> bool {
86 match self {
87 ArgCount::Fixed(n) => count == *n,
88 ArgCount::Range(min, max) => count >= *min && count <= *max,
89 ArgCount::Variadic => true,
90 }
91 }
92
93 #[must_use]
94 pub fn description(&self) -> String {
95 match self {
96 ArgCount::Fixed(0) => "no arguments".to_string(),
97 ArgCount::Fixed(1) => "1 argument".to_string(),
98 ArgCount::Fixed(n) => format!("{n} arguments"),
99 ArgCount::Range(min, max) => format!("{min} to {max} arguments"),
100 ArgCount::Variadic => "any number of arguments".to_string(),
101 }
102 }
103}
104
105#[derive(Debug, Clone)]
107pub struct FunctionSignature {
108 pub name: &'static str,
109 pub category: FunctionCategory,
110 pub arg_count: ArgCount,
111 pub description: &'static str,
112 pub returns: &'static str,
113 pub examples: Vec<&'static str>,
114}
115
116pub trait SqlFunction: Send + Sync {
118 fn signature(&self) -> FunctionSignature;
120
121 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue>;
123
124 fn validate_args(&self, args: &[DataValue]) -> Result<()> {
126 let sig = self.signature();
127 if !sig.arg_count.is_valid(args.len()) {
128 return Err(anyhow!(
129 "{}() expects {}, got {}",
130 sig.name,
131 sig.arg_count.description(),
132 args.len()
133 ));
134 }
135 Ok(())
136 }
137}
138
139pub struct FunctionRegistry {
141 functions: HashMap<String, Box<dyn SqlFunction>>,
142 by_category: HashMap<FunctionCategory, Vec<String>>,
143 methods: HashMap<String, Arc<dyn MethodFunction>>,
144}
145
146impl FunctionRegistry {
147 #[must_use]
149 pub fn new() -> Self {
150 let mut registry = Self {
151 functions: HashMap::new(),
152 by_category: HashMap::new(),
153 methods: HashMap::new(),
154 };
155
156 registry.register_constants();
158 registry.register_astronomical_functions();
159 registry.register_chemical_functions();
160 registry.register_mathematical_functions();
161 registry.register_statistical_functions();
162 registry.register_geometry_functions();
163 registry.register_physics_functions();
164 registry.register_date_time_functions();
165 registry.register_string_methods();
166 registry.register_financial_functions();
167 registry.register_conversion_functions();
168 registry.register_hash_functions();
169 registry.register_comparison_functions();
170 registry.register_aggregate_functions();
171 registry.register_random_functions();
172 registry.register_format_functions();
173 registry.register_type_checking_functions();
174
175 registry
176 }
177
178 pub fn register(&mut self, func: Box<dyn SqlFunction>) {
180 let sig = func.signature();
181 let name = sig.name.to_uppercase();
182 let category = sig.category;
183
184 self.functions.insert(name.clone(), func);
186
187 self.by_category.entry(category).or_default().push(name);
189 }
190
191 #[must_use]
193 pub fn get(&self, name: &str) -> Option<&dyn SqlFunction> {
194 self.functions
195 .get(&name.to_uppercase())
196 .map(std::convert::AsRef::as_ref)
197 }
198
199 #[must_use]
201 pub fn contains(&self, name: &str) -> bool {
202 self.functions.contains_key(&name.to_uppercase())
203 }
204
205 #[must_use]
207 pub fn autocomplete(&self, prefix: &str) -> Vec<FunctionSignature> {
208 let prefix_upper = prefix.to_uppercase();
209 self.functions
210 .iter()
211 .filter(|(name, _)| name.starts_with(&prefix_upper))
212 .map(|(_, func)| func.signature())
213 .collect()
214 }
215
216 #[must_use]
218 pub fn get_by_category(&self, category: FunctionCategory) -> Vec<FunctionSignature> {
219 self.by_category
220 .get(&category)
221 .map(|names| {
222 names
223 .iter()
224 .filter_map(|name| self.functions.get(name))
225 .map(|func| func.signature())
226 .collect()
227 })
228 .unwrap_or_default()
229 }
230
231 #[must_use]
233 pub fn all_functions(&self) -> Vec<FunctionSignature> {
234 self.functions
235 .values()
236 .map(|func| func.signature())
237 .collect()
238 }
239
240 pub fn register_method(&mut self, method: Arc<dyn MethodFunction>) {
242 let method_name = method.method_name().to_uppercase();
243 self.methods.insert(method_name, method);
244 }
245
246 #[must_use]
248 pub fn get_method(&self, name: &str) -> Option<Arc<dyn MethodFunction>> {
249 if let Some(method) = self.methods.get(&name.to_uppercase()) {
251 return Some(Arc::clone(method));
252 }
253
254 for method in self.methods.values() {
256 if method.handles_method(name) {
257 return Some(Arc::clone(method));
258 }
259 }
260
261 None
262 }
263
264 #[must_use]
266 pub fn has_method(&self, name: &str) -> bool {
267 self.get_method(name).is_some()
268 }
269
270 #[must_use]
272 pub fn generate_markdown_docs(&self) -> String {
273 use std::fmt::Write;
274 let mut doc = String::new();
275
276 writeln!(&mut doc, "# SQL CLI Function Reference\n").unwrap();
277 writeln!(
278 &mut doc,
279 "This document is auto-generated from the function registry.\n"
280 )
281 .unwrap();
282
283 let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
285 categories.sort_by_key(|c| format!("{c:?}"));
286
287 for category in categories {
288 let functions = self.get_by_category(category);
289 if functions.is_empty() {
290 continue;
291 }
292
293 writeln!(&mut doc, "## {category} Functions\n").unwrap();
294
295 let mut functions = functions;
297 functions.sort_by_key(|f| f.name);
298
299 for func in functions {
300 writeln!(&mut doc, "### {}()\n", func.name).unwrap();
301 writeln!(&mut doc, "**Description:** {}\n", func.description).unwrap();
302 writeln!(
303 &mut doc,
304 "**Arguments:** {}\n",
305 func.arg_count.description()
306 )
307 .unwrap();
308 writeln!(&mut doc, "**Returns:** {}\n", func.returns).unwrap();
309
310 if !func.examples.is_empty() {
311 writeln!(&mut doc, "**Examples:**").unwrap();
312 writeln!(&mut doc, "```sql").unwrap();
313 for example in &func.examples {
314 writeln!(&mut doc, "{example}").unwrap();
315 }
316 writeln!(&mut doc, "```\n").unwrap();
317 }
318 }
319 }
320
321 doc
322 }
323
324 #[must_use]
326 pub fn generate_function_help(&self, name: &str) -> Option<String> {
327 self.get(name).map(|func| {
328 let sig = func.signature();
329 let mut help = String::new();
330 use std::fmt::Write;
331
332 writeln!(&mut help, "Function: {}()", sig.name).unwrap();
333 writeln!(&mut help, "Category: {}", sig.category).unwrap();
334 writeln!(&mut help, "Description: {}", sig.description).unwrap();
335 writeln!(&mut help, "Arguments: {}", sig.arg_count.description()).unwrap();
336 writeln!(&mut help, "Returns: {}", sig.returns).unwrap();
337
338 if !sig.examples.is_empty() {
339 writeln!(&mut help, "\nExamples:").unwrap();
340 for example in &sig.examples {
341 writeln!(&mut help, " {example}").unwrap();
342 }
343 }
344
345 help
346 })
347 }
348
349 #[must_use]
351 pub fn list_functions(&self) -> String {
352 use std::fmt::Write;
353 let mut list = String::new();
354
355 writeln!(&mut list, "Available SQL Functions:\n").unwrap();
356
357 let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
358 categories.sort_by_key(|c| format!("{c:?}"));
359
360 for category in categories {
361 let functions = self.get_by_category(category);
362 if functions.is_empty() {
363 continue;
364 }
365
366 writeln!(&mut list, "{category} Functions:").unwrap();
367
368 let mut functions = functions;
369 functions.sort_by_key(|f| f.name);
370
371 for func in functions {
372 writeln!(
373 &mut list,
374 " {:20} - {}",
375 format!("{}()", func.name),
376 func.description
377 )
378 .unwrap();
379 }
380 writeln!(&mut list).unwrap();
381 }
382
383 list
384 }
385
386 fn register_constants(&mut self) {
388 use constants::{
389 EFunction, HbarFunction, MassElectronFunction, MeFunction, PhiFunction, PiFunction,
390 TauFunction,
391 };
392
393 self.register(Box::new(PiFunction));
394 self.register(Box::new(EFunction));
395 self.register(Box::new(MeFunction)); self.register(Box::new(MassElectronFunction)); self.register(Box::new(TauFunction));
398 self.register(Box::new(PhiFunction));
399 self.register(Box::new(HbarFunction));
400 }
401
402 fn register_astronomical_functions(&mut self) {
404 use astronomy::{
405 AuFunction, DistJupiterFunction, DistMarsFunction, DistMercuryFunction,
406 DistNeptuneFunction, DistSaturnFunction, DistUranusFunction, DistVenusFunction,
407 LightYearFunction, MassEarthFunction, MassJupiterFunction, MassMarsFunction,
408 MassMercuryFunction, MassMoonFunction, MassNeptuneFunction, MassSaturnFunction,
409 MassSunFunction, MassUranusFunction, MassVenusFunction, ParsecFunction,
410 RadiusEarthFunction, RadiusJupiterFunction, RadiusMarsFunction, RadiusMercuryFunction,
411 RadiusMoonFunction, RadiusNeptuneFunction, RadiusSaturnFunction, RadiusSunFunction,
412 RadiusUranusFunction, RadiusVenusFunction,
413 };
414
415 use solar_system::{
416 DensitySolarBodyFunction, DistanceSolarBodyFunction, EscapeVelocitySolarBodyFunction,
417 GravitySolarBodyFunction, MassSolarBodyFunction, MoonsSolarBodyFunction,
418 OrbitalPeriodSolarBodyFunction, RadiusSolarBodyFunction,
419 RotationPeriodSolarBodyFunction,
420 };
421
422 self.register(Box::new(MassEarthFunction));
423 self.register(Box::new(MassSunFunction));
424 self.register(Box::new(MassMoonFunction));
425 self.register(Box::new(AuFunction)); self.register(Box::new(LightYearFunction));
427 self.register(Box::new(ParsecFunction));
428
429 self.register(Box::new(MassMercuryFunction));
431 self.register(Box::new(MassVenusFunction));
432 self.register(Box::new(MassMarsFunction));
433 self.register(Box::new(MassJupiterFunction));
434 self.register(Box::new(MassSaturnFunction));
435 self.register(Box::new(MassUranusFunction));
436 self.register(Box::new(MassNeptuneFunction));
437
438 self.register(Box::new(RadiusSunFunction));
440 self.register(Box::new(RadiusEarthFunction));
441 self.register(Box::new(RadiusMoonFunction));
442 self.register(Box::new(RadiusMercuryFunction));
443 self.register(Box::new(RadiusVenusFunction));
444 self.register(Box::new(RadiusMarsFunction));
445 self.register(Box::new(RadiusJupiterFunction));
446 self.register(Box::new(RadiusSaturnFunction));
447 self.register(Box::new(RadiusUranusFunction));
448 self.register(Box::new(RadiusNeptuneFunction));
449
450 self.register(Box::new(DistMercuryFunction));
452 self.register(Box::new(DistVenusFunction));
453 self.register(Box::new(DistMarsFunction));
454 self.register(Box::new(DistJupiterFunction));
455 self.register(Box::new(DistSaturnFunction));
456 self.register(Box::new(DistUranusFunction));
457 self.register(Box::new(DistNeptuneFunction));
458
459 self.register(Box::new(MassSolarBodyFunction));
461 self.register(Box::new(RadiusSolarBodyFunction));
462 self.register(Box::new(DistanceSolarBodyFunction));
463 self.register(Box::new(OrbitalPeriodSolarBodyFunction));
464 self.register(Box::new(GravitySolarBodyFunction));
465 self.register(Box::new(DensitySolarBodyFunction));
466 self.register(Box::new(EscapeVelocitySolarBodyFunction));
467 self.register(Box::new(RotationPeriodSolarBodyFunction));
468 self.register(Box::new(MoonsSolarBodyFunction));
469 }
470
471 fn register_chemical_functions(&mut self) {
473 use chemistry::{
474 AtomicMassFunction, AtomicNumberFunction, AvogadroFunction, MoleculeFormulaFunction,
475 NeutronsFunction,
476 };
477
478 self.register(Box::new(AvogadroFunction));
479 self.register(Box::new(AtomicMassFunction));
480 self.register(Box::new(AtomicNumberFunction));
481 self.register(Box::new(NeutronsFunction));
482 self.register(Box::new(MoleculeFormulaFunction));
483 }
484
485 fn register_string_methods(&mut self) {
487 use case_convert::{
488 ToCamelCaseFunction, ToConstantCaseFunction, ToKebabCaseFunction, ToPascalCaseFunction,
489 ToSnakeCaseFunction,
490 };
491 use number_words::{ToOrdinal, ToOrdinalWords, ToWords};
492 use string_fun::{
493 InitCapFunction, MorseCodeFunction, PigLatinFunction, ProperFunction, ReverseFunction,
494 Rot13Function, ScrambleFunction, SoundexFunction,
495 };
496 use string_utils::{LPadFunction, RPadFunction, RepeatFunction};
497 use text_processing::{CleanText, ExtractWords, StripPunctuation, Tokenize, WordCount};
498
499 string_methods::register_string_methods(self);
500
501 self.register(Box::new(RepeatFunction));
503 self.register(Box::new(LPadFunction));
504 self.register(Box::new(RPadFunction));
505
506 self.register(Box::new(ToSnakeCaseFunction));
508 self.register(Box::new(ToCamelCaseFunction));
509 self.register(Box::new(ToPascalCaseFunction));
510 self.register(Box::new(ToKebabCaseFunction));
511 self.register(Box::new(ToConstantCaseFunction));
512
513 self.register(Box::new(ReverseFunction));
515 self.register(Box::new(InitCapFunction));
516 self.register(Box::new(ProperFunction));
517 self.register(Box::new(Rot13Function));
518 self.register(Box::new(SoundexFunction));
519 self.register(Box::new(PigLatinFunction));
520 self.register(Box::new(MorseCodeFunction));
521 self.register(Box::new(ScrambleFunction));
522
523 self.register(Box::new(ToWords));
525 self.register(Box::new(ToOrdinal));
526 self.register(Box::new(ToOrdinalWords));
527
528 self.register(Box::new(StripPunctuation));
530 self.register(Box::new(Tokenize));
531 self.register(Box::new(CleanText));
532 self.register(Box::new(ExtractWords));
533 self.register(Box::new(WordCount));
534 }
535
536 fn register_geometry_functions(&mut self) {
538 use geometry::{
539 CircleAreaFunction, CircleCircumferenceFunction, Distance2DFunction,
540 PythagorasFunction, SphereSurfaceAreaFunction, SphereVolumeFunction,
541 TriangleAreaFunction,
542 };
543
544 self.register(Box::new(PythagorasFunction));
545 self.register(Box::new(CircleAreaFunction));
546 self.register(Box::new(CircleCircumferenceFunction));
547 self.register(Box::new(SphereVolumeFunction));
548 self.register(Box::new(SphereSurfaceAreaFunction));
549 self.register(Box::new(TriangleAreaFunction));
550 self.register(Box::new(Distance2DFunction));
551 }
552
553 fn register_hash_functions(&mut self) {
555 use hash::{Md5Function, Sha1Function, Sha256Function, Sha512Function};
556
557 self.register(Box::new(Md5Function));
558 self.register(Box::new(Sha1Function));
559 self.register(Box::new(Sha256Function));
560 self.register(Box::new(Sha512Function));
561 }
562
563 fn register_comparison_functions(&mut self) {
565 comparison::register_comparison_functions(self);
566 }
567
568 fn register_mathematical_functions(&mut self) {
570 use base_conversion::{
571 FromBase, FromBinary, FromHex, FromOctal, ToBase, ToBinary, ToHex, ToOctal,
572 };
573 use integer_limits::{
574 ByteMax, ByteMin, CharMax, CharMin, Int16Max, Int16Min, Int32Max, Int32Min, Int64Max,
575 Int64Min, Int8Max, Int8Min, IntMax, IntMin, LongMax, LongMin, ShortMax, ShortMin,
576 Uint16Max, Uint32Max, Uint8Max,
577 };
578 use mathematics::{
579 IsPrimeFunction, NextPrimeFunction, NthPrimeFunction, PrevPrimeFunction,
580 PrimeCountFunction, PrimeFunction, PrimePiFunction,
581 };
582 use trigonometry::{
583 AcosFunction, AsinFunction, Atan2Function, AtanFunction, CosFunction, CoshFunction,
584 CotFunction, SinFunction, SinhFunction, TanFunction, TanhFunction,
585 };
586
587 self.register(Box::new(PrimeFunction));
589 self.register(Box::new(NthPrimeFunction)); self.register(Box::new(IsPrimeFunction));
591 self.register(Box::new(PrimeCountFunction));
592 self.register(Box::new(PrimePiFunction)); self.register(Box::new(NextPrimeFunction));
594 self.register(Box::new(PrevPrimeFunction));
595
596 self.register(Box::new(SinFunction));
598 self.register(Box::new(CosFunction));
599 self.register(Box::new(TanFunction));
600 self.register(Box::new(CotFunction));
601 self.register(Box::new(AsinFunction));
602 self.register(Box::new(AcosFunction));
603 self.register(Box::new(AtanFunction));
604 self.register(Box::new(Atan2Function));
605
606 self.register(Box::new(SinhFunction));
608 self.register(Box::new(CoshFunction));
609 self.register(Box::new(TanhFunction));
610
611 self.register(Box::new(ToBase));
613 self.register(Box::new(FromBase));
614 self.register(Box::new(ToBinary));
615 self.register(Box::new(FromBinary));
616 self.register(Box::new(ToHex));
617 self.register(Box::new(FromHex));
618 self.register(Box::new(ToOctal));
619 self.register(Box::new(FromOctal));
620
621 self.register(Box::new(Int8Min));
623 self.register(Box::new(Int8Max));
624 self.register(Box::new(Uint8Max));
625 self.register(Box::new(Int16Min));
626 self.register(Box::new(Int16Max));
627 self.register(Box::new(Uint16Max));
628 self.register(Box::new(Int32Min));
629 self.register(Box::new(Int32Max));
630 self.register(Box::new(Uint32Max));
631 self.register(Box::new(Int64Min));
632 self.register(Box::new(Int64Max));
633
634 self.register(Box::new(ByteMin));
636 self.register(Box::new(ByteMax));
637 self.register(Box::new(CharMin));
638 self.register(Box::new(CharMax));
639 self.register(Box::new(ShortMin));
640 self.register(Box::new(ShortMax));
641 self.register(Box::new(IntMin));
642 self.register(Box::new(IntMax));
643 self.register(Box::new(LongMin));
644 self.register(Box::new(LongMax));
645
646 math::register_math_functions(self);
648 }
649
650 fn register_physics_functions(&mut self) {
652 physics::register_physics_functions(self);
653
654 use particle_charges::{
656 ChargeDownQuarkFunction, ChargeElectronFunction, ChargeMuonFunction,
657 ChargeNeutronFunction, ChargePositronFunction, ChargeProtonFunction, ChargeTauFunction,
658 ChargeUpQuarkFunction,
659 };
660
661 self.register(Box::new(ChargeElectronFunction));
662 self.register(Box::new(ChargeProtonFunction));
663 self.register(Box::new(ChargeNeutronFunction));
664 self.register(Box::new(ChargeUpQuarkFunction));
665 self.register(Box::new(ChargeDownQuarkFunction));
666 self.register(Box::new(ChargePositronFunction));
667 self.register(Box::new(ChargeMuonFunction));
668 self.register(Box::new(ChargeTauFunction));
669 }
670
671 fn register_date_time_functions(&mut self) {
673 date_time::register_date_time_functions(self);
674 }
675
676 fn register_financial_functions(&mut self) {
678 financial::register_financial_functions(self);
679 }
680
681 fn register_conversion_functions(&mut self) {
683 use convert::ConvertFunction;
684 use roman::{FromRoman, ToRoman};
685
686 self.register(Box::new(ConvertFunction));
687 self.register(Box::new(ToRoman));
688 self.register(Box::new(FromRoman));
689 }
690
691 fn register_statistical_functions(&mut self) {
693 use statistics::{
694 CorrelationFunction, KurtosisFunction, MedianFunction, ModeFunction,
695 PercentileFunction, SkewFunction, VarPopFunction, VarSampFunction, VarianceFunction,
696 };
697
698 self.register(Box::new(MedianFunction));
699 self.register(Box::new(PercentileFunction));
700 self.register(Box::new(ModeFunction));
701 self.register(Box::new(VarianceFunction));
702 self.register(Box::new(VarSampFunction));
703 self.register(Box::new(VarPopFunction));
704 self.register(Box::new(CorrelationFunction));
705 self.register(Box::new(SkewFunction));
706 self.register(Box::new(KurtosisFunction));
707 }
708
709 fn register_aggregate_functions(&mut self) {
711 use group_num::GroupNumFunction;
712
713 self.register(Box::new(GroupNumFunction::new()));
716 }
717
718 fn register_random_functions(&mut self) {
720 use random::{RandIntFunction, RandRangeFunction, RandomFunction};
721
722 self.register(Box::new(RandomFunction));
723 self.register(Box::new(RandIntFunction));
724 self.register(Box::new(RandRangeFunction));
725 }
726
727 fn register_format_functions(&mut self) {
729 use format::{
730 CenterFunction, FormatDateFunction, FormatNumberFunction, LPadFunction, RPadFunction,
731 };
732 use format_number::{FormatCurrencyFunction, RenderNumberFunction};
733
734 self.register(Box::new(FormatNumberFunction));
735 self.register(Box::new(FormatDateFunction));
736 self.register(Box::new(LPadFunction));
737 self.register(Box::new(RPadFunction));
738 self.register(Box::new(CenterFunction));
739 self.register(Box::new(RenderNumberFunction));
740 self.register(Box::new(FormatCurrencyFunction));
741 }
742
743 fn register_type_checking_functions(&mut self) {
745 use type_checking::{
746 IsBoolFunction, IsDateFunction, IsFloatFunction, IsIntegerFunction, IsNotNullFunction,
747 IsNullFunction, IsNumericFunction,
748 };
749
750 self.register(Box::new(IsDateFunction));
751 self.register(Box::new(IsBoolFunction));
752 self.register(Box::new(IsNumericFunction));
753 self.register(Box::new(IsIntegerFunction));
754 self.register(Box::new(IsFloatFunction));
755 self.register(Box::new(IsNullFunction));
756 self.register(Box::new(IsNotNullFunction));
757 }
758}
759
760impl Default for FunctionRegistry {
761 fn default() -> Self {
762 Self::new()
763 }
764}
765
766#[cfg(test)]
767mod tests {
768 use super::*;
769
770 #[test]
771 fn test_registry_creation() {
772 let registry = FunctionRegistry::new();
773
774 assert!(registry.contains("PI"));
776 assert!(registry.contains("MASS_EARTH"));
777 assert!(registry.contains("ME"));
778 }
779
780 #[test]
781 fn test_case_insensitive_lookup() {
782 let registry = FunctionRegistry::new();
783
784 assert!(registry.get("pi").is_some());
785 assert!(registry.get("PI").is_some());
786 assert!(registry.get("Pi").is_some());
787 }
788
789 #[test]
790 fn test_autocomplete() {
791 let registry = FunctionRegistry::new();
792
793 let mass_functions = registry.autocomplete("MASS");
794 assert!(!mass_functions.is_empty());
795
796 let names: Vec<&str> = mass_functions.iter().map(|sig| sig.name).collect();
798 assert!(names.contains(&"MASS_EARTH"));
799 assert!(names.contains(&"MASS_SUN"));
800 }
801}