1pub mod builtin;
7
8pub use inventory;
10
11use dsq_shared::value::{value_from_any_value, Value};
12use dsq_shared::Result;
13use std::collections::HashMap;
14use std::sync::Arc;
15
16use sha2::{Digest, Sha256};
17
18use chrono::{DateTime, NaiveDate, NaiveDateTime, TimeZone, Utc};
19
20pub type BuiltinFunction = Arc<dyn Fn(&[Value]) -> Result<Value> + Send + Sync>;
22
23inventory::collect!(FunctionRegistration);
24
25pub struct FunctionRegistration {
26 pub name: &'static str,
27 pub func: fn(&[Value]) -> Result<Value>,
28}
29
30pub struct BuiltinRegistry {
35 functions: HashMap<String, BuiltinFunction>,
36}
37
38impl std::fmt::Debug for BuiltinRegistry {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(
41 f,
42 "BuiltinRegistry {{ functions: {} functions }}",
43 self.functions.len()
44 )
45 }
46}
47
48impl BuiltinRegistry {
49 pub fn new() -> Self {
51 let mut registry = Self {
52 functions: HashMap::new(),
53 };
54
55 registry.register_standard_functions();
56 registry
57 }
58
59 fn register_standard_functions(&mut self) {
61 for func in inventory::iter::<FunctionRegistration> {
63 self.register(func.name, Arc::new(func.func));
64 }
65 }
66
67 pub fn register(&mut self, name: impl Into<String>, func: BuiltinFunction) {
69 self.functions.insert(name.into(), func);
70 }
71
72 pub fn has_function(&self, name: &str) -> bool {
74 self.functions.contains_key(name)
75 }
76
77 pub fn call_function(&self, name: &str, args: &[Value]) -> Result<Value> {
79 if let Some(func) = self.functions.get(name) {
80 func(args)
81 } else {
82 Err(dsq_shared::error::operation_error(format!(
83 "built-in function '{}'",
84 name
85 )))
86 }
87 }
88
89 pub fn function_count(&self) -> usize {
91 self.functions.len()
92 }
93
94 pub fn get_function(&self, name: &str) -> Option<BuiltinFunction> {
96 self.functions.get(name).cloned()
97 }
98
99 pub fn function_names(&self) -> Vec<String> {
101 self.functions.keys().cloned().collect()
102 }
103}
104
105impl Default for BuiltinRegistry {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111pub(crate) fn extract_timestamp(value: &Value) -> Result<DateTime<Utc>> {
113 match value {
114 Value::Int(i) => Utc
115 .timestamp_opt(*i, 0)
116 .single()
117 .ok_or_else(|| dsq_shared::error::operation_error("Invalid timestamp")),
118 Value::Float(f) => {
119 let secs = f.trunc() as i64;
120 let nanos = (f.fract() * 1_000_000_000.0) as u32;
121 Utc.timestamp_opt(secs, nanos)
122 .single()
123 .ok_or_else(|| dsq_shared::error::operation_error("Invalid timestamp"))
124 }
125 Value::String(s) => {
126 if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
128 Ok(dt.with_timezone(&Utc))
129 } else if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
130 Ok(dt.and_utc())
131 } else if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S") {
132 Ok(dt.and_utc())
133 } else if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
134 let dt = date.and_hms_opt(0, 0, 0).unwrap();
135 Ok(dt.and_utc())
136 } else if let Ok(dt) = NaiveDateTime::parse_from_str(s, "%Y/%m/%d %H:%M:%S") {
137 Ok(dt.and_utc())
138 } else if let Ok(date) = NaiveDate::parse_from_str(s, "%Y/%m/%d") {
139 let dt = date.and_hms_opt(0, 0, 0).unwrap();
140 Ok(dt.and_utc())
141 } else {
142 Err(dsq_shared::error::operation_error(
143 "Unable to parse date/time string",
144 ))
145 }
146 }
147 _ => Err(dsq_shared::error::operation_error(
148 "Unsupported type for date extraction",
149 )),
150 }
151}
152
153inventory::submit! {
156 FunctionRegistration {
157 name: "lstrip",
158 func: builtin_lstrip,
159 }
160}
161
162fn builtin_lstrip(args: &[Value]) -> Result<Value> {
163 if args.len() != 1 {
164 return Err(dsq_shared::error::operation_error(
165 "lstrip() expects 1 argument",
166 ));
167 }
168
169 match &args[0] {
170 Value::String(s) => Ok(Value::String(s.trim_start().to_string())),
171 _ => Err(dsq_shared::error::operation_error(
172 "lstrip() requires string argument",
173 )),
174 }
175}
176
177inventory::submit! {
178 FunctionRegistration {
179 name: "sha256",
180 func: builtin_sha256,
181 }
182}
183
184fn builtin_sha256(args: &[Value]) -> Result<Value> {
185 if args.len() != 1 {
186 return Err(dsq_shared::error::operation_error(
187 "sha256() expects 1 argument",
188 ));
189 }
190
191 match &args[0] {
192 Value::String(s) => {
193 let mut hasher = Sha256::new();
194 hasher.update(s.as_bytes());
195 let result = hasher.finalize();
196 Ok(Value::String(format!("{:x}", result)))
197 }
198 _ => Err(dsq_shared::error::operation_error(
199 "sha256() requires string argument",
200 )),
201 }
202}
203
204pub fn compare_values_for_sorting(a: &Value, b: &Value) -> std::cmp::Ordering {
205 match (a, b) {
206 (Value::Null, Value::Null) => std::cmp::Ordering::Equal,
207 (Value::Null, _) => std::cmp::Ordering::Less,
208 (_, Value::Null) => std::cmp::Ordering::Greater,
209 (Value::Bool(a_val), Value::Bool(b_val)) => a_val.cmp(b_val),
210 (Value::Int(a_val), Value::Int(b_val)) => a_val.cmp(b_val),
211 (Value::Float(a_val), Value::Float(b_val)) => a_val
212 .partial_cmp(b_val)
213 .unwrap_or(std::cmp::Ordering::Equal),
214 (Value::String(a_val), Value::String(b_val)) => a_val.cmp(b_val),
215 (Value::Int(a_val), Value::Float(b_val)) => (*a_val as f64)
216 .partial_cmp(b_val)
217 .unwrap_or(std::cmp::Ordering::Equal),
218 (Value::Float(a_val), Value::Int(b_val)) => a_val
219 .partial_cmp(&(*b_val as f64))
220 .unwrap_or(std::cmp::Ordering::Equal),
221 _ => std::cmp::Ordering::Equal,
222 }
223}
224
225inventory::submit! {
226 FunctionRegistration {
227 name: "dtypes",
228 func: builtin_dtypes,
229 }
230}
231
232fn builtin_dtypes(args: &[Value]) -> Result<Value> {
233 if args.len() != 1 {
234 return Err(dsq_shared::error::operation_error(
235 "dtypes() expects 1 argument",
236 ));
237 }
238
239 match &args[0] {
240 Value::DataFrame(df) => {
241 let mut dtypes_obj = HashMap::new();
242 for col_name in df.get_column_names() {
243 if let Ok(series) = df.column(col_name) {
244 dtypes_obj.insert(
245 col_name.to_string(),
246 Value::String(series.dtype().to_string()),
247 );
248 }
249 }
250 Ok(Value::Object(dtypes_obj))
251 }
252 _ => Err(dsq_shared::error::operation_error(
253 "dtypes() requires DataFrame argument",
254 )),
255 }
256}
257
258inventory::submit! {
259 FunctionRegistration {
260 name: "round",
261 func: builtin_round,
262 }
263}
264
265fn builtin_round(args: &[Value]) -> Result<Value> {
266 if args.is_empty() || args.len() > 2 {
267 return Err(dsq_shared::error::operation_error(
268 "round() expects 1 or 2 arguments",
269 ));
270 }
271
272 let precision = if args.len() == 2 {
273 match &args[1] {
274 Value::Int(i) => *i as usize,
275 _ => {
276 return Err(dsq_shared::error::operation_error(
277 "round() precision must be an integer",
278 ))
279 }
280 }
281 } else {
282 0
283 };
284
285 match &args[0] {
286 Value::Int(i) => {
287 if precision == 0 {
288 Ok(Value::Int(*i))
289 } else {
290 Ok(Value::Float(*i as f64))
291 }
292 }
293 Value::Float(f) => {
294 let multiplier = 10f64.powi(precision as i32);
295 let rounded = (f * multiplier).round() / multiplier;
296 Ok(Value::Float(rounded))
297 }
298 Value::Array(arr) => {
299 let rounded_arr: Result<Vec<Value>> = arr
300 .iter()
301 .map(|v| match v {
302 Value::Int(i) => {
303 if precision == 0 {
304 Ok(Value::Int(*i))
305 } else {
306 Ok(Value::Float(*i as f64))
307 }
308 }
309 Value::Float(f) => {
310 let multiplier = 10f64.powi(precision as i32);
311 let rounded = (f * multiplier).round() / multiplier;
312 Ok(Value::Float(rounded))
313 }
314 _ => Ok(v.clone()),
315 })
316 .collect();
317 Ok(Value::Array(rounded_arr?))
318 }
319 Value::DataFrame(df) => {
320 Ok(Value::DataFrame(df.clone()))
322 }
323 Value::Series(series) => {
324 Ok(Value::Series(series.clone()))
326 }
327 _ => Ok(args[0].clone()),
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use crate::builtin::filter::builtin_filter;
335 use crate::builtin::histogram::builtin_histogram;
336 use crate::builtin::select::builtin_select;
337 use crate::builtin::transliterate::builtin_transliterate;
338 use chrono::Datelike;
339 use dsq_shared::value::Value;
340 use polars::datatypes::PlSmallStr;
341 use polars::prelude::*;
342 use std::collections::HashMap;
343
344 fn create_test_dataframe() -> DataFrame {
345 let names = Series::new(PlSmallStr::from("name"), &["Alice", "Bob", "Charlie"]);
346 let ages = Series::new(PlSmallStr::from("age"), &[25, 30, 35]);
347 let scores = Series::new(PlSmallStr::from("score"), &[85.5, 92.0, 78.3]);
348 DataFrame::new(vec![names.into(), ages.into(), scores.into()]).unwrap()
349 }
350
351 #[test]
352 fn test_extract_timestamp() {
353 let ts = Value::Int(1609459200); let dt = extract_timestamp(&ts).unwrap();
356 assert_eq!(dt.year(), 2021);
357 assert_eq!(dt.month(), 1);
358 assert_eq!(dt.day(), 1);
359
360 let rfc3339 = Value::String("2021-01-01T00:00:00Z".to_string());
362 let dt = extract_timestamp(&rfc3339).unwrap();
363 assert_eq!(dt.year(), 2021);
364
365 let date_str = Value::String("2021-01-01".to_string());
367 let dt = extract_timestamp(&date_str).unwrap();
368 assert_eq!(dt.year(), 2021);
369 assert_eq!(dt.month(), 1);
370 assert_eq!(dt.day(), 1);
371 }
372
373 #[test]
374 fn test_start_of_month() {
375 let registry = BuiltinRegistry::new();
376
377 let ts = Value::Int(1612137600); let result = registry.call_function("start_of_month", &[ts]).unwrap();
380 assert_eq!(result, Value::String("2021-02-01".to_string()));
381
382 let ts = Value::Int(1614556800); let result = registry.call_function("start_of_month", &[ts]).unwrap();
385 assert_eq!(result, Value::String("2021-03-01".to_string()));
386
387 let ts = Value::Int(1613347200); let result = registry.call_function("start_of_month", &[ts]).unwrap();
390 assert_eq!(result, Value::String("2021-02-01".to_string()));
391
392 let date_str = Value::String("2021-06-15".to_string());
394 let result = registry
395 .call_function("start_of_month", &[date_str])
396 .unwrap();
397 assert_eq!(result, Value::String("2021-06-01".to_string()));
398 }
399
400 #[test]
401 fn test_truncate_time_function() {
402 let registry = BuiltinRegistry::new();
403
404 let result = registry
406 .call_function(
407 "truncate_time",
408 &[
409 Value::String("2021-06-15T14:30:45Z".to_string()),
410 Value::String("day".to_string()),
411 ],
412 )
413 .unwrap();
414 assert_eq!(
415 result,
416 Value::String("2021-06-15T00:00:00+00:00".to_string())
417 );
418
419 let result = registry
421 .call_function(
422 "truncate_time",
423 &[
424 Value::String("2021-06-15T14:30:45Z".to_string()),
425 Value::String("hour".to_string()),
426 ],
427 )
428 .unwrap();
429 assert_eq!(
430 result,
431 Value::String("2021-06-15T14:00:00+00:00".to_string())
432 );
433
434 let result = registry
436 .call_function(
437 "truncate_time",
438 &[
439 Value::String("2021-06-15T14:30:45Z".to_string()),
440 Value::String("minute".to_string()),
441 ],
442 )
443 .unwrap();
444 assert_eq!(
445 result,
446 Value::String("2021-06-15T14:30:00+00:00".to_string())
447 );
448
449 let result = registry
451 .call_function(
452 "truncate_time",
453 &[
454 Value::String("2021-06-15T14:30:45Z".to_string()),
455 Value::String("month".to_string()),
456 ],
457 )
458 .unwrap();
459 assert_eq!(
460 result,
461 Value::String("2021-06-01T00:00:00+00:00".to_string())
462 );
463
464 let result = registry
466 .call_function(
467 "truncate_time",
468 &[
469 Value::String("2021-06-15T14:30:45Z".to_string()),
470 Value::String("year".to_string()),
471 ],
472 )
473 .unwrap();
474 assert_eq!(
475 result,
476 Value::String("2021-01-01T00:00:00+00:00".to_string())
477 );
478 }
479
480 #[test]
481 fn test_year_function() {
482 let registry = BuiltinRegistry::new();
483
484 let result = registry
486 .call_function("year", &[Value::Int(1609459200)])
487 .unwrap();
488 assert_eq!(result, Value::Int(2021));
489
490 let result = registry
492 .call_function("year", &[Value::String("2021-06-15".to_string())])
493 .unwrap();
494 assert_eq!(result, Value::Int(2021));
495
496 let result = registry
498 .call_function("year", &[Value::String("2021-06-15T12:30:45Z".to_string())])
499 .unwrap();
500 assert_eq!(result, Value::Int(2021));
501 }
502
503 #[test]
504 fn test_date_diff_function() {
505 let registry = BuiltinRegistry::new();
506
507 let result = registry
509 .call_function(
510 "date_diff",
511 &[
512 Value::String("2023-01-01".to_string()),
513 Value::String("2023-01-05".to_string()),
514 ],
515 )
516 .unwrap();
517 assert_eq!(result, Value::Int(4));
518
519 let result = registry
521 .call_function(
522 "date_diff",
523 &[
524 Value::String("2023-01-01".to_string()),
525 Value::String("2023-01-01".to_string()),
526 ],
527 )
528 .unwrap();
529 assert_eq!(result, Value::Int(0));
530
531 let result = registry
533 .call_function(
534 "date_diff",
535 &[
536 Value::String("2023-01-01T00:00:00Z".to_string()),
537 Value::String("2023-01-05T00:00:00Z".to_string()),
538 ],
539 )
540 .unwrap();
541 assert_eq!(result, Value::Int(4));
542
543 let arr1 = Value::Array(vec![
545 Value::String("2023-01-01".to_string()),
546 Value::String("2023-02-01".to_string()),
547 ]);
548 let arr2 = Value::Array(vec![
549 Value::String("2023-01-05".to_string()),
550 Value::String("2023-02-05".to_string()),
551 ]);
552 let result = registry.call_function("date_diff", &[arr1, arr2]).unwrap();
553 assert_eq!(result, Value::Array(vec![Value::Int(4), Value::Int(4)]));
554 }
555
556 #[test]
557 fn test_gmtime_function() {
558 let registry = BuiltinRegistry::new();
559
560 let result = registry
562 .call_function("gmtime", &[Value::Int(1609459200)])
563 .unwrap();
564 if let Value::Object(obj) = result {
565 assert_eq!(obj.get("year"), Some(&Value::Int(2021)));
566 assert_eq!(obj.get("month"), Some(&Value::Int(1)));
567 assert_eq!(obj.get("day"), Some(&Value::Int(1)));
568 assert_eq!(obj.get("hour"), Some(&Value::Int(0)));
569 assert_eq!(obj.get("minute"), Some(&Value::Int(0)));
570 assert_eq!(obj.get("second"), Some(&Value::Int(0)));
571 assert_eq!(obj.get("weekday"), Some(&Value::Int(5))); assert_eq!(obj.get("yearday"), Some(&Value::Int(1)));
573 } else {
574 panic!("Expected object result");
575 }
576
577 let result = registry
579 .call_function("gmtime", &[Value::String("2021-06-15".to_string())])
580 .unwrap();
581 if let Value::Object(obj) = result {
582 assert_eq!(obj.get("year"), Some(&Value::Int(2021)));
583 assert_eq!(obj.get("month"), Some(&Value::Int(6)));
584 assert_eq!(obj.get("day"), Some(&Value::Int(15)));
585 assert_eq!(obj.get("hour"), Some(&Value::Int(0)));
586 assert_eq!(obj.get("minute"), Some(&Value::Int(0)));
587 assert_eq!(obj.get("second"), Some(&Value::Int(0)));
588 } else {
589 panic!("Expected object result");
590 }
591 }
592
593 #[test]
594 fn test_month_function() {
595 let registry = BuiltinRegistry::new();
596
597 let result = registry
598 .call_function("month", &[Value::String("2021-06-15".to_string())])
599 .unwrap();
600 assert_eq!(result, Value::Int(6));
601 }
602
603 #[test]
604 fn test_day_function() {
605 let registry = BuiltinRegistry::new();
606
607 let result = registry
608 .call_function("day", &[Value::String("2021-06-15".to_string())])
609 .unwrap();
610 assert_eq!(result, Value::Int(15));
611 }
612
613 #[test]
614 fn test_hour_function() {
615 let registry = BuiltinRegistry::new();
616
617 let result = registry
618 .call_function("hour", &[Value::String("2021-06-15T14:30:45Z".to_string())])
619 .unwrap();
620 assert_eq!(result, Value::Int(14));
621 }
622
623 #[test]
624 fn test_minute_function() {
625 let registry = BuiltinRegistry::new();
626
627 let result = registry
628 .call_function(
629 "minute",
630 &[Value::String("2021-06-15T14:30:45Z".to_string())],
631 )
632 .unwrap();
633 assert_eq!(result, Value::Int(30));
634 }
635
636 #[test]
637 fn test_second_function() {
638 let registry = BuiltinRegistry::new();
639
640 let result = registry
641 .call_function(
642 "second",
643 &[Value::String("2021-06-15T14:30:45Z".to_string())],
644 )
645 .unwrap();
646 assert_eq!(result, Value::Int(45));
647 }
648
649 #[test]
650 fn test_tostring_function() {
651 let registry = BuiltinRegistry::new();
652
653 let result = registry
654 .call_function("tostring", &[Value::Int(42)])
655 .unwrap();
656 assert_eq!(result, Value::String("42".to_string()));
657
658 let result = registry
659 .call_function("tostring", &[Value::Float(3.14)])
660 .unwrap();
661 assert_eq!(result, Value::String("3.14".to_string()));
662
663 let result = registry
664 .call_function("tostring", &[Value::Bool(true)])
665 .unwrap();
666 assert_eq!(result, Value::String("true".to_string()));
667 }
668
669 #[test]
670 fn test_snake_case_function() {
671 let registry = BuiltinRegistry::new();
672
673 let result = registry
674 .call_function("snake_case", &[Value::String("CamelCase".to_string())])
675 .unwrap();
676 assert_eq!(result, Value::String("camel_case".to_string()));
677
678 let result = registry
679 .call_function("snake_case", &[Value::String("XMLHttpRequest".to_string())])
680 .unwrap();
681 assert_eq!(result, Value::String("xml_http_request".to_string()));
682 }
683
684 #[test]
685 fn test_lowercase_function() {
686 let registry = BuiltinRegistry::new();
687
688 let result = registry
689 .call_function("lowercase", &[Value::String("HELLO WORLD".to_string())])
690 .unwrap();
691 assert_eq!(result, Value::String("hello world".to_string()));
692
693 let result = registry
694 .call_function("lowercase", &[Value::String("HeLLo WoRlD".to_string())])
695 .unwrap();
696 assert_eq!(result, Value::String("hello world".to_string()));
697 }
698
699 #[test]
700 fn test_camel_case_function() {
701 let registry = BuiltinRegistry::new();
702
703 let result = registry
704 .call_function("camel_case", &[Value::String("snake_case".to_string())])
705 .unwrap();
706 assert_eq!(result, Value::String("snakeCase".to_string()));
707
708 let result = registry
709 .call_function(
710 "camel_case",
711 &[Value::String("xml_http_request".to_string())],
712 )
713 .unwrap();
714 assert_eq!(result, Value::String("xmlHttpRequest".to_string()));
715 }
716
717 #[test]
718 fn test_is_valid_utf8_function() {
719 let registry = BuiltinRegistry::new();
720
721 let result = registry
722 .call_function("is_valid_utf8", &[Value::String("hello world".to_string())])
723 .unwrap();
724 assert_eq!(result, Value::Bool(true));
725
726 let result = registry
727 .call_function("is_valid_utf8", &[Value::String("hello".to_string())])
728 .unwrap();
729 assert_eq!(result, Value::Bool(true));
730 }
731
732 #[test]
733 fn test_to_valid_utf8_function() {
734 let registry = BuiltinRegistry::new();
735
736 let result = registry
737 .call_function("to_valid_utf8", &[Value::String("hello world".to_string())])
738 .unwrap();
739 assert_eq!(result, Value::String("hello world".to_string()));
740
741 let result = registry
742 .call_function("to_valid_utf8", &[Value::String("café".to_string())])
743 .unwrap();
744 assert_eq!(result, Value::String("café".to_string()));
745
746 let arr = vec![
748 Value::String("café".to_string()),
749 Value::String("naïve".to_string()),
750 ];
751 let result = registry
752 .call_function("to_valid_utf8", &[Value::Array(arr)])
753 .unwrap();
754 let expected = vec![
755 Value::String("café".to_string()),
756 Value::String("naïve".to_string()),
757 ];
758 assert_eq!(result, Value::Array(expected));
759 }
760
761 #[test]
762 fn test_tabs_to_spaces_function() {
763 let registry = BuiltinRegistry::new();
764
765 let result = registry
767 .call_function(
768 "tabs_to_spaces",
769 &[Value::String("hello\tworld".to_string())],
770 )
771 .unwrap();
772 assert_eq!(result, Value::String("hello world".to_string()));
773
774 let result = registry
776 .call_function(
777 "tabs_to_spaces",
778 &[Value::String("a\tb\tc".to_string()), Value::Int(2)],
779 )
780 .unwrap();
781 assert_eq!(result, Value::String("a b c".to_string()));
782
783 let result = registry
785 .call_function(
786 "tabs_to_spaces",
787 &[Value::String("\tindented text".to_string())],
788 )
789 .unwrap();
790 assert_eq!(result, Value::String(" indented text".to_string()));
791
792 let result = registry
794 .call_function(
795 "tabs_to_spaces",
796 &[Value::String("Multiple\ttabs\tin\tone\tline".to_string())],
797 )
798 .unwrap();
799 assert_eq!(
800 result,
801 Value::String("Multiple tabs in one line".to_string())
802 );
803 }
804
805 #[test]
806 fn test_abs_function() {
807 let registry = BuiltinRegistry::new();
808
809 let result = registry.call_function("abs", &[Value::Int(-42)]).unwrap();
810 assert_eq!(result, Value::Int(42));
811
812 let result = registry
813 .call_function("abs", &[Value::Float(-3.14)])
814 .unwrap();
815 assert_eq!(result, Value::Float(3.14));
816 }
817
818 #[test]
819 fn test_floor_function() {
820 let registry = BuiltinRegistry::new();
821
822 let result = registry
823 .call_function("floor", &[Value::Float(3.7)])
824 .unwrap();
825 assert_eq!(result, Value::Float(3.0));
826
827 let result = registry
828 .call_function("floor", &[Value::Float(-3.7)])
829 .unwrap();
830 assert_eq!(result, Value::Float(-4.0));
831 }
832
833 #[test]
834 fn test_ceil_function() {
835 let registry = BuiltinRegistry::new();
836
837 let result = registry
838 .call_function("ceil", &[Value::Float(3.1)])
839 .unwrap();
840 assert_eq!(result, Value::Float(4.0));
841
842 let result = registry
843 .call_function("ceil", &[Value::Float(-3.1)])
844 .unwrap();
845 assert_eq!(result, Value::Float(-3.0));
846 }
847
848 #[test]
849 fn test_pow_function() {
850 let registry = BuiltinRegistry::new();
851
852 let result = registry
853 .call_function("pow", &[Value::Int(2), Value::Int(3)])
854 .unwrap();
855 assert_eq!(result, Value::Float(8.0));
856
857 let result = registry
858 .call_function("pow", &[Value::Float(2.0), Value::Float(0.5)])
859 .unwrap();
860 assert_eq!(result, Value::Float(std::f64::consts::SQRT_2));
861 }
862
863 #[test]
864 fn test_log10_function() {
865 let registry = BuiltinRegistry::new();
866
867 let result = registry.call_function("log10", &[Value::Int(10)]).unwrap();
868 assert_eq!(result, Value::Float(1.0));
869
870 let result = registry.call_function("log10", &[Value::Int(100)]).unwrap();
871 assert_eq!(result, Value::Float(2.0));
872
873 let result = registry
874 .call_function("log10", &[Value::Float(1000.0)])
875 .unwrap();
876 assert_eq!(result, Value::Float(3.0));
877
878 let result = registry.call_function("log10", &[Value::Int(0)]);
880 assert!(result.is_err());
881
882 let result = registry.call_function("log10", &[Value::Float(-1.0)]);
883 assert!(result.is_err());
884 }
885
886 #[test]
887 fn test_pi_function() {
888 let registry = BuiltinRegistry::new();
889
890 let result = registry.call_function("pi", &[]).unwrap();
891 assert_eq!(result, Value::Float(std::f64::consts::PI));
892 }
893
894 #[test]
895 fn test_sha512_function() {
896 let registry = BuiltinRegistry::new();
897
898 let result = registry
899 .call_function("sha512", &[Value::String("hello".to_string())])
900 .unwrap();
901 if let Value::String(hash) = result {
902 assert_eq!(hash.len(), 128); assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
904 } else {
905 panic!("Expected string result");
906 }
907 }
908
909 #[test]
910 fn test_sha256_function() {
911 let registry = BuiltinRegistry::new();
912
913 let result = registry
914 .call_function("sha256", &[Value::String("hello".to_string())])
915 .unwrap();
916 if let Value::String(hash) = result {
917 assert_eq!(hash.len(), 64); assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
919 } else {
920 panic!("Expected string result");
921 }
922 }
923
924 #[test]
925 fn test_sha1_function() {
926 let registry = BuiltinRegistry::new();
927
928 let result = registry
929 .call_function("sha1", &[Value::String("hello".to_string())])
930 .unwrap();
931 if let Value::String(hash) = result {
932 assert_eq!(hash.len(), 40); assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
934 } else {
935 panic!("Expected string result");
936 }
937 }
938
939 #[test]
940 fn test_md5_function() {
941 let registry = BuiltinRegistry::new();
942
943 let result = registry
944 .call_function("md5", &[Value::String("hello".to_string())])
945 .unwrap();
946 if let Value::String(hash) = result {
947 assert_eq!(hash.len(), 32); assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
949 } else {
950 panic!("Expected string result");
951 }
952 }
953
954 #[test]
955 fn test_base64_encode_decode() {
956 let registry = BuiltinRegistry::new();
957
958 let original = "hello world";
959 let encoded = registry
960 .call_function("base64_encode", &[Value::String(original.to_string())])
961 .unwrap();
962 if let Value::String(enc_str) = encoded {
963 let decoded = registry
964 .call_function("base64_decode", &[Value::String(enc_str)])
965 .unwrap();
966 assert_eq!(decoded, Value::String(original.to_string()));
967 } else {
968 panic!("Expected string result from base64_encode");
969 }
970 }
971
972 #[test]
973 fn test_base32_encode_decode() {
974 let registry = BuiltinRegistry::new();
975
976 let original = "hello world";
977 let encoded = registry
978 .call_function("base32_encode", &[Value::String(original.to_string())])
979 .unwrap();
980 if let Value::String(enc_str) = encoded {
981 let decoded = registry
982 .call_function("base32_decode", &[Value::String(enc_str)])
983 .unwrap();
984 assert_eq!(decoded, Value::String(original.to_string()));
985 } else {
986 panic!("Expected string result from base32_encode");
987 }
988 }
989
990 #[test]
991 fn test_base58_encode_decode() {
992 let registry = BuiltinRegistry::new();
993
994 let original = "hello world";
995 let encoded = registry
996 .call_function("base58_encode", &[Value::String(original.to_string())])
997 .unwrap();
998 if let Value::String(enc_str) = encoded {
999 let decoded = registry
1000 .call_function("base58_decode", &[Value::String(enc_str)])
1001 .unwrap();
1002 assert_eq!(decoded, Value::String(original.to_string()));
1003 } else {
1004 panic!("Expected string result from base58_encode");
1005 }
1006 }
1007
1008 #[test]
1009 fn test_columns_function() {
1010 let registry = BuiltinRegistry::new();
1011 let df = create_test_dataframe();
1012
1013 let result = registry
1014 .call_function("columns", &[Value::DataFrame(df)])
1015 .unwrap();
1016 if let Value::Array(cols) = result {
1017 assert_eq!(cols.len(), 3);
1018 assert!(cols.contains(&Value::String("name".to_string())));
1019 assert!(cols.contains(&Value::String("age".to_string())));
1020 assert!(cols.contains(&Value::String("score".to_string())));
1021 } else {
1022 panic!("Expected array result");
1023 }
1024 }
1025
1026 #[test]
1027 fn test_shape_function() {
1028 let registry = BuiltinRegistry::new();
1029 let df = create_test_dataframe();
1030
1031 let result = registry
1032 .call_function("shape", &[Value::DataFrame(df)])
1033 .unwrap();
1034 if let Value::Array(shape) = result {
1035 assert_eq!(shape.len(), 2);
1036 assert_eq!(shape[0], Value::Int(3)); assert_eq!(shape[1], Value::Int(3)); } else {
1039 panic!("Expected array result");
1040 }
1041 }
1042
1043 #[test]
1044 fn test_mean_function() {
1045 let registry = BuiltinRegistry::new();
1046 let df = create_test_dataframe();
1047
1048 let result = registry
1049 .call_function("mean", &[Value::DataFrame(df)])
1050 .unwrap();
1051 if let Value::Object(means) = result {
1052 assert!(means.contains_key("age"));
1053 assert!(means.contains_key("score"));
1054 if let Some(Value::Float(age_mean)) = means.get("age") {
1056 assert!((age_mean - 30.0).abs() < 0.001);
1057 } else {
1058 panic!("Expected float for age mean");
1059 }
1060 } else {
1061 panic!("Expected object result");
1062 }
1063 }
1064
1065 #[test]
1066 fn test_median_function() {
1067 let registry = BuiltinRegistry::new();
1068 let df = create_test_dataframe();
1069
1070 let result = registry
1071 .call_function("median", &[Value::DataFrame(df)])
1072 .unwrap();
1073 if let Value::Object(medians) = result {
1074 assert!(medians.contains_key("age"));
1075 assert!(medians.contains_key("score"));
1076 if let Some(Value::Float(age_median)) = medians.get("age") {
1078 assert!((age_median - 30.0).abs() < 0.001);
1079 } else {
1080 panic!("Expected float for age median");
1081 }
1082 } else {
1083 panic!("Expected object result");
1084 }
1085 }
1086
1087 #[test]
1088 fn test_count_function() {
1089 let registry = BuiltinRegistry::new();
1090 let df = create_test_dataframe();
1091
1092 let result = registry
1094 .call_function("count", &[Value::DataFrame(df.clone())])
1095 .unwrap();
1096 assert_eq!(result, Value::Int(3));
1097
1098 let arr = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
1100 let result = registry.call_function("count", &[arr]).unwrap();
1101 assert_eq!(result, Value::Int(3));
1102
1103 let empty_arr = Value::Array(vec![]);
1105 let result = registry.call_function("count", &[empty_arr]).unwrap();
1106 assert_eq!(result, Value::Int(0));
1107
1108 let mut obj = std::collections::HashMap::new();
1110 obj.insert("a".to_string(), Value::Int(1));
1111 obj.insert("b".to_string(), Value::Int(2));
1112 let obj_val = Value::Object(obj);
1113 let result = registry.call_function("count", &[obj_val]).unwrap();
1114 assert_eq!(result, Value::Int(2));
1115
1116 let series = Series::new(PlSmallStr::from("test"), vec![1i64, 2, 3]);
1118 let result = registry
1119 .call_function("count", &[Value::Series(series)])
1120 .unwrap();
1121 assert_eq!(result, Value::Int(3));
1122
1123 let string_val = Value::String("hello".to_string());
1125 let result = registry.call_function("count", &[string_val]).unwrap();
1126 assert_eq!(result, Value::Int(5));
1127
1128 let unicode_string = Value::String("héllo".to_string());
1130 let result = registry.call_function("count", &[unicode_string]).unwrap();
1131 assert_eq!(result, Value::Int(5)); let int_val = Value::Int(42);
1135 let result = registry.call_function("count", &[int_val]).unwrap();
1136 assert_eq!(result, Value::Int(1));
1137
1138 let float_val = Value::Float(3.14);
1139 let result = registry.call_function("count", &[float_val]).unwrap();
1140 assert_eq!(result, Value::Int(1));
1141
1142 let bool_val = Value::Bool(true);
1143 let result = registry.call_function("count", &[bool_val]).unwrap();
1144 assert_eq!(result, Value::Int(1));
1145
1146 let null_val = Value::Null;
1147 let result = registry.call_function("count", &[null_val]).unwrap();
1148 assert_eq!(result, Value::Int(1));
1149 }
1150
1151 #[test]
1152 fn test_url_parse_function() {
1153 let registry = BuiltinRegistry::new();
1154
1155 let result = registry
1156 .call_function(
1157 "url_parse",
1158 &[Value::String(
1159 "https://www.example.com:8080/path?query=value#fragment".to_string(),
1160 )],
1161 )
1162 .unwrap();
1163 if let Value::Object(parsed) = result {
1164 assert_eq!(
1165 parsed.get("scheme"),
1166 Some(&Value::String("https".to_string()))
1167 );
1168 assert_eq!(
1169 parsed.get("host"),
1170 Some(&Value::String("www.example.com".to_string()))
1171 );
1172 assert_eq!(parsed.get("port"), Some(&Value::Int(8080)));
1173 assert_eq!(
1174 parsed.get("path"),
1175 Some(&Value::String("/path".to_string()))
1176 );
1177 assert_eq!(
1178 parsed.get("query"),
1179 Some(&Value::String("query=value".to_string()))
1180 );
1181 assert_eq!(
1182 parsed.get("fragment"),
1183 Some(&Value::String("fragment".to_string()))
1184 );
1185 } else {
1186 panic!("Expected object result");
1187 }
1188 }
1189
1190 #[test]
1191 fn test_url_extract_domain_function() {
1192 let registry = BuiltinRegistry::new();
1193
1194 let result = registry
1195 .call_function(
1196 "url_extract_domain",
1197 &[Value::String("https://www.example.com/path".to_string())],
1198 )
1199 .unwrap();
1200 assert_eq!(result, Value::String("www.example.com".to_string()));
1201 }
1202
1203 #[test]
1204 fn test_range_function() {
1205 let registry = BuiltinRegistry::new();
1206
1207 let result = registry.call_function("range", &[Value::Int(5)]).unwrap();
1208 if let Value::Array(arr) = result {
1209 assert_eq!(arr.len(), 5);
1210 assert_eq!(arr[0], Value::Int(0));
1211 assert_eq!(arr[4], Value::Int(4));
1212 } else {
1213 panic!("Expected array result");
1214 }
1215
1216 let result = registry
1217 .call_function("range", &[Value::Int(1), Value::Int(5)])
1218 .unwrap();
1219 if let Value::Array(arr) = result {
1220 assert_eq!(arr.len(), 4);
1221 assert_eq!(arr[0], Value::Int(1));
1222 assert_eq!(arr[3], Value::Int(4));
1223 } else {
1224 panic!("Expected array result");
1225 }
1226 }
1227
1228 #[test]
1229 fn test_select_function() {
1230 let registry = BuiltinRegistry::new();
1231
1232 let arr = Value::Array(vec![
1233 Value::String("a".to_string()),
1234 Value::String("b".to_string()),
1235 Value::String("c".to_string()),
1236 ]);
1237 let result = registry
1238 .call_function("select", &[arr, Value::Int(0), Value::Int(2)])
1239 .unwrap();
1240 if let Value::Array(selected) = result {
1241 assert_eq!(selected.len(), 2);
1242 assert_eq!(selected[0], Value::String("a".to_string()));
1243 assert_eq!(selected[1], Value::String("c".to_string()));
1244 } else {
1245 panic!("Expected array result");
1246 }
1247 }
1248
1249 #[test]
1250 fn test_del_function() {
1251 let registry = BuiltinRegistry::new();
1252
1253 let mut obj = HashMap::new();
1254 obj.insert("a".to_string(), Value::Int(1));
1255 obj.insert("b".to_string(), Value::Int(2));
1256 obj.insert("c".to_string(), Value::Int(3));
1257
1258 let result = registry
1259 .call_function("del", &[Value::Object(obj), Value::String("b".to_string())])
1260 .unwrap();
1261 if let Value::Object(del_obj) = result {
1262 assert!(!del_obj.contains_key("b"));
1263 assert_eq!(del_obj.get("a"), Some(&Value::Int(1)));
1264 assert_eq!(del_obj.get("c"), Some(&Value::Int(3)));
1265 } else {
1266 panic!("Expected object result");
1267 }
1268 }
1269
1270 #[test]
1271 fn test_fromjson_function() {
1272 let registry = BuiltinRegistry::new();
1273
1274 let json_str = r#"{"name": "Alice", "age": 30, "active": true}"#;
1275 let result = registry
1276 .call_function("fromjson", &[Value::String(json_str.to_string())])
1277 .unwrap();
1278 if let Value::Object(obj) = result {
1279 assert_eq!(obj.get("name"), Some(&Value::String("Alice".to_string())));
1280 assert_eq!(obj.get("age"), Some(&Value::Int(30)));
1281 assert_eq!(obj.get("active"), Some(&Value::Bool(true)));
1282 } else {
1283 panic!("Expected object result");
1284 }
1285 }
1286
1287 #[test]
1288 fn test_group_concat_function() {
1289 let registry = BuiltinRegistry::new();
1290
1291 let arr = Value::Array(vec![
1292 Value::String("a".to_string()),
1293 Value::String("b".to_string()),
1294 Value::String("c".to_string()),
1295 ]);
1296 let result = registry
1297 .call_function("group_concat", std::slice::from_ref(&arr))
1298 .unwrap();
1299 assert_eq!(result, Value::String("a,b,c".to_string()));
1300
1301 let result = registry
1302 .call_function("group_concat", &[arr, Value::String(";".to_string())])
1303 .unwrap();
1304 assert_eq!(result, Value::String("a;b;c".to_string()));
1305 }
1306
1307 #[test]
1308 fn test_registry_has_function() {
1309 let registry = BuiltinRegistry::new();
1310
1311 assert!(registry.has_function("year"));
1312 assert!(registry.has_function("month"));
1313 assert!(registry.has_function("tostring"));
1314 assert!(registry.has_function("abs"));
1315 assert!(registry.has_function("sha512"));
1316 assert!(registry.has_function("has"));
1317 assert!(registry.has_function("rstrip"));
1318 assert!(registry.has_function("url_extract_path"));
1319 assert!(registry.has_function("uppercase"));
1320 assert!(registry.has_function("toupper"));
1321 assert!(registry.has_function("iif"));
1322 assert!(registry.has_function("time_series_range"));
1323 assert!(!registry.has_function("nonexistent"));
1324 }
1325
1326 #[test]
1327 fn test_builtin_has() {
1328 let registry = BuiltinRegistry::new();
1329
1330 let obj = Value::Object(
1331 vec![
1332 ("name".to_string(), Value::String("Alice".to_string())),
1333 ("age".to_string(), Value::Int(30)),
1334 ("city".to_string(), Value::String("New York".to_string())),
1335 ]
1336 .into_iter()
1337 .collect(),
1338 );
1339
1340 let result = registry
1342 .call_function("has", &[obj.clone(), Value::String("city".to_string())])
1343 .unwrap();
1344 assert_eq!(result, Value::Bool(true));
1345
1346 let result = registry
1348 .call_function("has", &[obj.clone(), Value::String("country".to_string())])
1349 .unwrap();
1350 assert_eq!(result, Value::Bool(false));
1351
1352 let result = registry
1354 .call_function(
1355 "has",
1356 &[
1357 Value::String("test".to_string()),
1358 Value::String("key".to_string()),
1359 ],
1360 )
1361 .unwrap();
1362 assert_eq!(result, Value::Bool(false));
1363 }
1364
1365 #[test]
1366 fn test_registry_function_count() {
1367 let registry = BuiltinRegistry::new();
1368
1369 assert!(registry.function_count() > 50);
1371 }
1372
1373 #[test]
1374 fn test_registry_function_names() {
1375 let registry = BuiltinRegistry::new();
1376
1377 let names = registry.function_names();
1378 assert!(names.contains(&"year".to_string()));
1379 assert!(names.contains(&"month".to_string()));
1380 assert!(names.contains(&"tostring".to_string()));
1381 assert!(names.contains(&"strptime".to_string()));
1382 assert!(names.contains(&"now".to_string()));
1383 assert!(names.contains(&"url_extract_port".to_string()));
1384 }
1385
1386 #[test]
1387 fn test_registry_strptime() {
1388 let registry = BuiltinRegistry::new();
1389
1390 let result = registry
1392 .call_function(
1393 "strptime",
1394 &[
1395 Value::String("2021-01-01 00:00:00".to_string()),
1396 Value::String("%Y-%m-%d %H:%M:%S".to_string()),
1397 ],
1398 )
1399 .unwrap();
1400 assert!(matches!(result, Value::Int(_)));
1401 }
1402
1403 #[test]
1404 fn test_builtin_start_of_week() {
1405 let registry = BuiltinRegistry::new();
1406
1407 let result = registry
1409 .call_function("start_of_week", &[Value::String("2023-10-02".to_string())])
1410 .unwrap();
1411 assert_eq!(result, Value::Int(1696204800));
1413
1414 let result = registry
1416 .call_function("start_of_week", &[Value::String("2023-10-03".to_string())])
1417 .unwrap();
1418 assert_eq!(result, Value::Int(1696204800)); let result = registry
1422 .call_function("start_of_week", &[Value::String("2023-10-08".to_string())])
1423 .unwrap();
1424 assert_eq!(result, Value::Int(1696204800)); let result = registry
1428 .call_function(
1429 "start_of_week",
1430 &[
1431 Value::String("2023-10-02".to_string()),
1432 Value::String("sunday".to_string()),
1433 ],
1434 )
1435 .unwrap();
1436 assert_eq!(result, Value::Int(1696118400));
1440
1441 let arr = Value::Array(vec![
1443 Value::String("2023-10-02".to_string()),
1444 Value::String("2023-10-03".to_string()),
1445 ]);
1446 let result = registry.call_function("start_of_week", &[arr]).unwrap();
1447 match result {
1448 Value::Array(res) => {
1449 assert_eq!(res.len(), 2);
1450 assert_eq!(res[0], Value::Int(1696204800));
1451 assert_eq!(res[1], Value::Int(1696204800));
1452 }
1453 _ => panic!("Expected array"),
1454 }
1455 }
1456
1457 #[test]
1458 fn test_builtin_length_with_dataframe() {
1459 let registry = BuiltinRegistry::new();
1460 let df = DataFrame::new(vec![
1461 Series::new(PlSmallStr::from("name"), &["Alice", "Bob", "Charlie"]).into(),
1462 Series::new(PlSmallStr::from("age"), &[25, 30, 35]).into(),
1463 ])
1464 .unwrap();
1465 let df_value = Value::DataFrame(df);
1466
1467 let result = registry.call_function("length", &[df_value]).unwrap();
1468 assert_eq!(result, Value::Int(3));
1469 }
1470
1471 #[test]
1472 fn test_builtin_select_single_arg() {
1473 let result = builtin_select(&[Value::Bool(true)]).unwrap();
1475 assert_eq!(result, Value::Bool(true));
1476
1477 let result = builtin_select(&[Value::Bool(false)]).unwrap();
1479 assert_eq!(result, Value::Null);
1480
1481 let result = builtin_select(&[Value::Null]).unwrap();
1483 assert_eq!(result, Value::Null);
1484
1485 let result = builtin_select(&[Value::String("test".to_string())]).unwrap();
1487 assert_eq!(result, Value::String("test".to_string()));
1488
1489 let result = builtin_select(&[Value::String("".to_string())]).unwrap();
1491 assert_eq!(result, Value::Null);
1492
1493 let result = builtin_select(&[Value::Int(42)]).unwrap();
1495 assert_eq!(result, Value::Int(42));
1496
1497 let result = builtin_select(&[Value::Int(0)]).unwrap();
1499 assert_eq!(result, Value::Null);
1500 }
1501
1502 #[test]
1503 fn test_builtin_select_two_args() {
1504 let result =
1506 builtin_select(&[Value::String("test".to_string()), Value::Bool(true)]).unwrap();
1507 assert_eq!(result, Value::String("test".to_string()));
1508
1509 let result =
1511 builtin_select(&[Value::String("test".to_string()), Value::Bool(false)]).unwrap();
1512 assert_eq!(result, Value::Null);
1513
1514 let result = builtin_select(&[Value::String("test".to_string()), Value::Null]).unwrap();
1516 assert_eq!(result, Value::Null);
1517
1518 let arr = Value::Array(vec![Value::Int(1), Value::Int(2)]);
1520 let result = builtin_select(&[arr, Value::Bool(true)]).unwrap();
1521 assert_eq!(result, Value::Array(vec![Value::Int(1), Value::Int(2)]));
1522 }
1523
1524 #[test]
1525 fn test_builtin_select_array_with_mask() {
1526 let arr = vec![Value::Int(1), Value::Int(2), Value::Int(3)];
1527 let mask = vec![Value::Bool(true), Value::Bool(false), Value::Bool(true)];
1528 let result = builtin_select(&[Value::Array(arr), Value::Array(mask)]).unwrap();
1529 match result {
1530 Value::Array(filtered) => {
1531 assert_eq!(filtered.len(), 2);
1532 assert_eq!(filtered[0], Value::Int(1));
1533 assert_eq!(filtered[1], Value::Int(3));
1534 }
1535 _ => panic!("Expected Array"),
1536 }
1537 }
1538
1539 #[test]
1540 fn test_builtin_select_dataframe_with_series() {
1541 let name = PlSmallStr::from("name");
1542 let age: PlSmallStr = "age".into();
1543 let mask: PlSmallStr = "mask".into();
1544 let df = DataFrame::new(vec![
1545 Series::new(
1546 name,
1547 vec![
1548 "Alice".to_string(),
1549 "Bob".to_string(),
1550 "Charlie".to_string(),
1551 ],
1552 )
1553 .into(),
1554 Series::new(age, vec![25, 30, 35]).into(),
1555 ])
1556 .unwrap();
1557 let mask_series = Series::new(mask, vec![true, false, true]);
1558 let result =
1559 builtin_select(&[Value::DataFrame(df.clone()), Value::Series(mask_series)]).unwrap();
1560 match result {
1561 Value::DataFrame(filtered_df) => {
1562 assert_eq!(filtered_df.height(), 2);
1563 let names = filtered_df.column("name").unwrap();
1564 assert_eq!(names.len(), 2);
1565 if let Ok(AnyValue::String(name1)) = names.get(0) {
1566 assert_eq!(name1, "Alice");
1567 }
1568 if let Ok(AnyValue::String(name2)) = names.get(1) {
1569 assert_eq!(name2, "Charlie");
1570 }
1571 }
1572 _ => panic!("Expected DataFrame"),
1573 }
1574 }
1575
1576 #[test]
1577 fn test_builtin_select_series_with_series() {
1578 let series = Series::new(PlSmallStr::from("values"), vec![1, 2, 3, 4]);
1579 let mask_series = Series::new(PlSmallStr::from("mask"), vec![true, false, true, false]);
1580 let result = builtin_select(&[Value::Series(series), Value::Series(mask_series)]).unwrap();
1581 match result {
1582 Value::Series(filtered_series) => {
1583 assert_eq!(filtered_series.len(), 2);
1584 if let Ok(AnyValue::Int64(val1)) = filtered_series.get(0) {
1585 assert_eq!(val1, 1);
1586 }
1587 if let Ok(AnyValue::Int64(val2)) = filtered_series.get(1) {
1588 assert_eq!(val2, 3);
1589 }
1590 }
1591 _ => panic!("Expected Series"),
1592 }
1593 }
1594
1595 #[test]
1596 fn test_builtin_select_single_arg_extended() {
1597 let mut obj = std::collections::HashMap::new();
1599 obj.insert("key".to_string(), Value::String("value".to_string()));
1600 let result = builtin_select(&[Value::Object(obj.clone())]).unwrap();
1601 assert_eq!(result, Value::Object(obj));
1602
1603 let arr = Value::Array(vec![Value::Int(1), Value::Int(2)]);
1605 let result = builtin_select(std::slice::from_ref(&arr)).unwrap();
1606 assert_eq!(result, arr);
1607
1608 let result = builtin_select(&[Value::Float(std::f64::consts::PI)]).unwrap();
1610 assert_eq!(result, Value::Float(std::f64::consts::PI));
1611
1612 let result = builtin_select(&[Value::Int(-1)]).unwrap();
1614 assert_eq!(result, Value::Int(-1));
1615 }
1616
1617 #[test]
1618 fn test_builtin_select_two_args_extended() {
1619 use polars::prelude::*;
1620 let mut obj = std::collections::HashMap::new();
1622 obj.insert("key".to_string(), Value::String("value".to_string()));
1623 let result = builtin_select(&[Value::Object(obj.clone()), Value::Bool(true)]).unwrap();
1624 assert_eq!(result, Value::Object(obj.clone()));
1625
1626 let result = builtin_select(&[Value::Object(obj), Value::Bool(false)]).unwrap();
1627 assert_eq!(result, Value::Null);
1628
1629 let df = DataFrame::new(vec![
1631 Series::new(PlSmallStr::from("name"), &["Alice"]).into(),
1632 Series::new(PlSmallStr::from("age"), &[25]).into(),
1633 ])
1634 .unwrap();
1635 let result = builtin_select(&[Value::DataFrame(df.clone()), Value::Bool(true)]).unwrap();
1636 if let Value::DataFrame(result_df) = result {
1637 assert_eq!(result_df.height(), df.height());
1638 assert_eq!(result_df.width(), df.width());
1639 } else {
1640 panic!("Expected DataFrame result");
1641 }
1642
1643 let result = builtin_select(&[Value::DataFrame(df), Value::Bool(false)]).unwrap();
1644 assert_eq!(result, Value::Null);
1645
1646 let series = Series::new(PlSmallStr::from("values"), vec![1, 2, 3]);
1648 let result = builtin_select(&[Value::Series(series.clone()), Value::Bool(true)]).unwrap();
1649 if let Value::Series(result_series) = result {
1650 assert_eq!(result_series.name(), series.name());
1651 assert_eq!(result_series.len(), series.len());
1652 } else {
1653 panic!("Expected Series result");
1654 }
1655
1656 let result = builtin_select(&[Value::Series(series), Value::Bool(false)]).unwrap();
1657 assert_eq!(result, Value::Null);
1658 }
1659
1660 #[test]
1661 fn test_builtin_select_mask_errors() {
1662 let arr = Value::Array(vec![Value::Int(1)]);
1664 let mask = Value::Array(vec![Value::Bool(true), Value::Bool(false)]);
1665 let result = builtin_select(&[arr, mask]);
1666 assert!(result.is_err());
1667 assert!(result.unwrap_err().to_string().contains("same length"));
1668
1669 let df = DataFrame::new(vec![Column::new(PlSmallStr::from("a"), vec![1])]).unwrap();
1671 let mask_series = Series::new(PlSmallStr::from("mask"), vec![true, false]);
1672 let result = builtin_select(&[Value::DataFrame(df), Value::Series(mask_series)]);
1673 assert!(result.is_err());
1674 assert!(result.unwrap_err().to_string().contains("same length"));
1675
1676 let series = Series::new(PlSmallStr::from("values"), vec![1]);
1678 let mask_series = Series::new(PlSmallStr::from("mask"), vec![true, false]);
1679 let result = builtin_select(&[Value::Series(series), Value::Series(mask_series)]);
1680 assert!(result.is_err());
1681 assert!(result.unwrap_err().to_string().contains("same length"));
1682
1683 let series = Series::new(PlSmallStr::from("values"), vec![1, 2]);
1685 let mask_series = Series::new(
1686 PlSmallStr::from("mask"),
1687 vec![AnyValue::Int64(1), AnyValue::Int64(0)],
1688 ); let result = builtin_select(&[Value::Series(series), Value::Series(mask_series)]);
1690 assert!(result.is_err());
1691 assert!(result
1692 .unwrap_err()
1693 .to_string()
1694 .contains("must contain booleans"));
1695 }
1696
1697 #[test]
1698 fn test_builtin_select_invalid_args() {
1699 let result = builtin_select(&[]);
1701 assert!(result.is_err());
1702
1703 let result = builtin_select(&[Value::Int(1), Value::Int(2), Value::Int(3)]);
1705 assert!(result.is_err());
1706 }
1707
1708 #[test]
1709 fn test_builtin_filter_array() {
1710 let arr = Value::Array(vec![
1711 Value::Int(1),
1712 Value::Int(2),
1713 Value::Int(1),
1714 Value::Int(3),
1715 ]);
1716 let filter_value = Value::Int(1);
1717 let result = builtin_filter(&[arr, filter_value]).unwrap();
1718 match result {
1719 Value::Array(filtered) => {
1720 assert_eq!(filtered.len(), 2);
1721 assert_eq!(filtered[0], Value::Int(1));
1722 assert_eq!(filtered[1], Value::Int(1));
1723 }
1724 _ => panic!("Expected Array"),
1725 }
1726 }
1727
1728 #[test]
1729 fn test_builtin_filter_dataframe() {
1730 let df = DataFrame::new(vec![
1731 Series::new(PlSmallStr::from("col1"), vec![1, 2, 1, 3]).into(),
1732 Series::new(PlSmallStr::from("col2"), vec!["a", "b", "c", "d"]).into(),
1733 ])
1734 .unwrap();
1735 let df_value = Value::DataFrame(df);
1736 let filter_value = Value::Int(1);
1737 let result = builtin_filter(&[df_value, filter_value]).unwrap();
1738 match result {
1739 Value::DataFrame(filtered_df) => {
1740 assert_eq!(filtered_df.height(), 2);
1741 let col1 = filtered_df.column("col1").unwrap();
1742 if let Ok(AnyValue::Int64(val1)) = col1.get(0) {
1743 assert_eq!(val1, 1);
1744 }
1745 if let Ok(AnyValue::Int64(val2)) = col1.get(1) {
1746 assert_eq!(val2, 1);
1747 }
1748 }
1749 _ => panic!("Expected DataFrame"),
1750 }
1751 }
1752
1753 #[test]
1754 fn test_builtin_filter_series() {
1755 let series = Series::new(
1756 <&str as Into<PlSmallStr>>::into("values"),
1757 vec![1i32, 2, 1, 3],
1758 );
1759 let series_value = Value::Series(series);
1760 let filter_value = Value::Int(1);
1761 let result = builtin_filter(&[series_value, filter_value]).unwrap();
1762 match result {
1763 Value::Series(filtered_series) => {
1764 assert_eq!(filtered_series.len(), 2);
1765 if let Ok(AnyValue::Int64(val1)) = filtered_series.get(0) {
1766 assert_eq!(val1, 1);
1767 }
1768 if let Ok(AnyValue::Int64(val2)) = filtered_series.get(1) {
1769 assert_eq!(val2, 1);
1770 }
1771 }
1772 _ => panic!("Expected Series"),
1773 }
1774 }
1775
1776 #[test]
1777 fn test_builtin_filter_no_matches() {
1778 let arr = Value::Array(vec![Value::Int(1), Value::Int(2)]);
1779 let filter_value = Value::Int(3);
1780 let result = builtin_filter(&[arr, filter_value]).unwrap();
1781 match result {
1782 Value::Array(filtered) => {
1783 assert_eq!(filtered.len(), 0);
1784 }
1785 _ => panic!("Expected Array"),
1786 }
1787 }
1788
1789 #[test]
1790 fn test_builtin_filter_invalid_args() {
1791 let result = builtin_filter(&[Value::Array(vec![])]);
1793 assert!(result.is_err());
1794
1795 let result = builtin_filter(&[Value::Array(vec![]), Value::Int(1), Value::Int(2)]);
1797 assert!(result.is_err());
1798 }
1799
1800 #[test]
1801 fn test_builtin_humanize_number() {
1802 let registry = BuiltinRegistry::new();
1803
1804 let result = registry
1806 .call_function(
1807 "humanize",
1808 &[Value::Int(1234567), Value::String("number".to_string())],
1809 )
1810 .unwrap();
1811 assert_eq!(result, Value::String("1,234,567".to_string()));
1812
1813 let result = registry
1815 .call_function(
1816 "humanize",
1817 &[Value::Int(123456), Value::String("currency".to_string())],
1818 )
1819 .unwrap();
1820 assert_eq!(result, Value::String("$1,234.56".to_string()));
1821
1822 let result = registry
1824 .call_function(
1825 "humanize",
1826 &[Value::Int(1048576), Value::String("bytes".to_string())],
1827 )
1828 .unwrap();
1829 assert_eq!(result, Value::String("1.0 MB".to_string()));
1830
1831 let result = registry
1833 .call_function(
1834 "humanize",
1835 &[Value::Float(0.85), Value::String("percentage".to_string())],
1836 )
1837 .unwrap();
1838 assert_eq!(result, Value::String("85.0%".to_string()));
1839
1840 let result = registry
1842 .call_function(
1843 "humanize",
1844 &[
1845 Value::String("2023-12-25".to_string()),
1846 Value::String("date".to_string()),
1847 ],
1848 )
1849 .unwrap();
1850 assert_eq!(result, Value::String("December 25, 2023".to_string()));
1851 }
1852
1853 #[test]
1854 fn test_builtin_humanize_auto() {
1855 let registry = BuiltinRegistry::new();
1856
1857 let result = registry
1859 .call_function("humanize", &[Value::Int(1234567)])
1860 .unwrap();
1861 assert_eq!(result, Value::String("1,234,567".to_string()));
1862
1863 let result = registry
1865 .call_function("humanize", &[Value::Int(1048576)])
1866 .unwrap();
1867 assert_eq!(result, Value::String("1.0 MB".to_string()));
1868
1869 let result = registry
1871 .call_function("humanize", &[Value::String("2023-12-25".to_string())])
1872 .unwrap();
1873 assert_eq!(result, Value::String("December 25, 2023".to_string()));
1874 }
1875
1876 #[test]
1877 fn test_builtin_humanize_invalid_args() {
1878 let registry = BuiltinRegistry::new();
1879
1880 let result = registry.call_function("humanize", &[]);
1882 assert!(result.is_err());
1883
1884 let result = registry.call_function(
1885 "humanize",
1886 &[
1887 Value::Int(1),
1888 Value::String("number".to_string()),
1889 Value::Int(2),
1890 ],
1891 );
1892 assert!(result.is_err());
1893
1894 let result = registry.call_function(
1896 "humanize",
1897 &[Value::Int(1), Value::String("invalid".to_string())],
1898 );
1899 assert!(result.is_err());
1900 assert!(result.unwrap_err().to_string().contains("unknown format"));
1901 }
1902
1903 #[test]
1904 fn test_builtin_tan() {
1905 let registry = BuiltinRegistry::new();
1906
1907 let result = registry.call_function("tan", &[Value::Int(0)]).unwrap();
1909 if let Value::Float(val) = result {
1910 assert!((val - 0.0).abs() < 1e-10);
1911 } else {
1912 panic!("Expected float result");
1913 }
1914
1915 let pi_over_4 = std::f64::consts::PI / 4.0;
1917 let result = registry
1918 .call_function("tan", &[Value::Float(pi_over_4)])
1919 .unwrap();
1920 if let Value::Float(val) = result {
1921 assert!((val - 1.0).abs() < 1e-10);
1922 } else {
1923 panic!("Expected float result");
1924 }
1925
1926 let pi_over_2 = std::f64::consts::PI / 2.0;
1928 let result = registry
1929 .call_function("tan", &[Value::Float(pi_over_2)])
1930 .unwrap();
1931 if let Value::Float(val) = result {
1932 assert!(val.abs() > 1e10); } else {
1934 panic!("Expected float result");
1935 }
1936
1937 let angle_radians = 30.0_f64.to_radians();
1939 let result = registry
1940 .call_function("tan", &[Value::Float(angle_radians)])
1941 .unwrap();
1942 let expected = angle_radians.tan();
1943 if let Value::Float(val) = result {
1944 assert!((val - expected).abs() < 1e-10);
1945 } else {
1946 panic!("Expected float result");
1947 }
1948
1949 let angle_radians = (45.0_f64).to_radians();
1951 let result = registry
1952 .call_function(
1953 "tan",
1954 &[Value::Array(vec![
1955 Value::Int(0),
1956 Value::Float(angle_radians),
1957 ])],
1958 )
1959 .unwrap();
1960 if let Value::Array(arr) = result {
1961 assert_eq!(arr.len(), 2);
1962 if let Value::Float(val0) = &arr[0] {
1963 assert!((val0 - 0.0).abs() < 1e-10);
1964 } else {
1965 panic!("Expected float in array");
1966 }
1967 if let Value::Float(val1) = &arr[1] {
1968 assert!((val1 - 1.0).abs() < 1e-10);
1969 } else {
1970 panic!("Expected float in array");
1971 }
1972 } else {
1973 panic!("Expected array result");
1974 }
1975 }
1976
1977 #[test]
1978 fn test_builtin_tan_invalid_args() {
1979 let registry = BuiltinRegistry::new();
1980
1981 let result = registry.call_function("tan", &[]);
1983 assert!(result.is_err());
1984 assert!(result
1985 .unwrap_err()
1986 .to_string()
1987 .contains("expects 1 argument"));
1988
1989 let result = registry.call_function("tan", &[Value::Int(1), Value::Int(2)]);
1990 assert!(result.is_err());
1991 assert!(result
1992 .unwrap_err()
1993 .to_string()
1994 .contains("expects 1 argument"));
1995
1996 let result = registry.call_function("tan", &[Value::String("not a number".to_string())]);
1998 assert!(result.is_err());
1999 assert!(result.unwrap_err().to_string().contains("requires numeric"));
2000
2001 let result = registry.call_function(
2003 "tan",
2004 &[Value::Array(vec![
2005 Value::Int(1),
2006 Value::String("invalid".to_string()),
2007 ])],
2008 );
2009 assert!(result.is_err());
2010 assert!(result
2011 .unwrap_err()
2012 .to_string()
2013 .contains("requires numeric values in array"));
2014 }
2015
2016 #[test]
2017 fn test_builtin_quartile_invalid_args() {
2018 let registry = BuiltinRegistry::new();
2019
2020 let result = registry.call_function("quartile", &[]);
2022 assert!(result.is_err());
2023 assert!(result
2024 .unwrap_err()
2025 .to_string()
2026 .contains("expects 1 or 2 arguments"));
2027
2028 let result =
2029 registry.call_function("quartile", &[Value::Int(1), Value::Int(2), Value::Int(3)]);
2030 assert!(result.is_err());
2031 assert!(result
2032 .unwrap_err()
2033 .to_string()
2034 .contains("expects 1 or 2 arguments"));
2035
2036 let result = registry.call_function(
2038 "quartile",
2039 &[Value::Array(vec![Value::Int(1)]), Value::Int(0)],
2040 );
2041 assert!(result.is_err());
2042 assert!(result
2043 .unwrap_err()
2044 .to_string()
2045 .contains("second argument must be 1, 2, or 3"));
2046
2047 let result = registry.call_function(
2048 "quartile",
2049 &[Value::Array(vec![Value::Int(1)]), Value::Int(4)],
2050 );
2051 assert!(result.is_err());
2052 assert!(result
2053 .unwrap_err()
2054 .to_string()
2055 .contains("second argument must be 1, 2, or 3"));
2056
2057 let result = registry.call_function(
2058 "quartile",
2059 &[
2060 Value::Array(vec![Value::Int(1)]),
2061 Value::String("invalid".to_string()),
2062 ],
2063 );
2064 assert!(result.is_err());
2065 assert!(result
2066 .unwrap_err()
2067 .to_string()
2068 .contains("second argument must be 1, 2, or 3"));
2069
2070 let result = registry.call_function("quartile", &[Value::String("not array".to_string())]);
2072 assert!(result.is_err());
2073 assert!(result
2074 .unwrap_err()
2075 .to_string()
2076 .contains("requires array, DataFrame, or Series"));
2077 }
2078
2079 #[test]
2080 fn test_builtin_array_pop_array() {
2081 let registry = BuiltinRegistry::new();
2082
2083 let arr = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
2085 let result = registry.call_function("array_pop", &[arr]).unwrap();
2086 assert_eq!(result, Value::Int(3));
2087
2088 let arr = Value::Array(vec![Value::String("hello".to_string())]);
2090 let result = registry.call_function("array_pop", &[arr]).unwrap();
2091 assert_eq!(result, Value::String("hello".to_string()));
2092
2093 let arr = Value::Array(vec![]);
2095 let result = registry.call_function("array_pop", &[arr]).unwrap();
2096 assert_eq!(result, Value::Null);
2097 }
2098
2099 #[test]
2100 fn test_builtin_array_pop_dataframe() {
2101 let registry = BuiltinRegistry::new();
2102
2103 let df = DataFrame::new(vec![
2105 Series::new(
2106 PlSmallStr::from("name"),
2107 vec![
2108 "Alice".to_string(),
2109 "Bob".to_string(),
2110 "Charlie".to_string(),
2111 ],
2112 )
2113 .into(),
2114 Series::new(PlSmallStr::from("age"), vec![25i64, 30i64, 35i64]).into(),
2115 ])
2116 .unwrap();
2117 let df_value = Value::DataFrame(df);
2118 let result = registry.call_function("array_pop", &[df_value]).unwrap();
2119 match result {
2120 Value::Object(obj) => {
2121 assert_eq!(obj.get("name"), Some(&Value::String("Charlie".to_string())));
2122 assert_eq!(obj.get("age"), Some(&Value::Int(35)));
2123 }
2124 _ => panic!("Expected object result"),
2125 }
2126
2127 let df = DataFrame::new(vec![
2129 Series::new(PlSmallStr::from("id"), vec![42i64]).into(),
2130 Series::new(PlSmallStr::from("value"), vec!["test".to_string()]).into(),
2131 ])
2132 .unwrap();
2133 let df_value = Value::DataFrame(df);
2134 let result = registry.call_function("array_pop", &[df_value]).unwrap();
2135 match result {
2136 Value::Object(obj) => {
2137 assert_eq!(obj.get("id"), Some(&Value::Int(42)));
2138 assert_eq!(obj.get("value"), Some(&Value::String("test".to_string())));
2139 }
2140 _ => panic!("Expected object result"),
2141 }
2142
2143 let df = DataFrame::new(vec![Column::new(
2145 PlSmallStr::from("empty"),
2146 Vec::<String>::new(),
2147 )])
2148 .unwrap();
2149 let df_value = Value::DataFrame(df);
2150 let result = registry.call_function("array_pop", &[df_value]).unwrap();
2151 assert_eq!(result, Value::Null);
2152 }
2153
2154 #[test]
2155 fn test_builtin_array_pop_series() {
2156 let registry = BuiltinRegistry::new();
2157
2158 let list_series = Series::new(
2160 PlSmallStr::from("lists"),
2161 vec![Series::new(PlSmallStr::from(""), vec![1, 2, 3])],
2162 );
2163 let series_value = Value::Series(list_series);
2164 let result = registry
2165 .call_function("array_pop", &[series_value])
2166 .unwrap();
2167 assert_eq!(result, Value::Int(3));
2168
2169 let list_series = Series::new(
2171 "empty_lists".into(),
2172 vec![Series::new(PlSmallStr::from(""), Vec::<i32>::new())],
2173 );
2174 let series_value = Value::Series(list_series);
2175 let result = registry
2176 .call_function("array_pop", &[series_value])
2177 .unwrap();
2178 assert_eq!(result, Value::Null);
2179
2180 let int_series = Series::new(PlSmallStr::from("ints"), vec![1, 2, 3]);
2182 let series_value = Value::Series(int_series);
2183 let result = registry.call_function("array_pop", &[series_value]);
2184 assert!(result.is_err());
2185 assert!(result
2186 .unwrap_err()
2187 .to_string()
2188 .contains("requires an array, DataFrame, or list series"));
2189 }
2190
2191 #[test]
2192 fn test_builtin_array_pop_invalid_args() {
2193 let registry = BuiltinRegistry::new();
2194
2195 let result = registry.call_function("array_pop", &[]);
2197 assert!(result.is_err());
2198 assert!(result
2199 .unwrap_err()
2200 .to_string()
2201 .contains("expects 1 argument"));
2202
2203 let arr = Value::Array(vec![Value::Int(1)]);
2204 let result = registry.call_function("array_pop", &[arr, Value::Int(2)]);
2205 assert!(result.is_err());
2206 assert!(result
2207 .unwrap_err()
2208 .to_string()
2209 .contains("expects 1 argument"));
2210
2211 let result = registry.call_function("array_pop", &[Value::String("not array".to_string())]);
2213 assert!(result.is_err());
2214 assert!(result
2215 .unwrap_err()
2216 .to_string()
2217 .contains("requires an array, DataFrame, or list series"));
2218 }
2219
2220 #[test]
2221 fn test_builtin_mround() {
2222 let result = builtin::mround::builtin_mround(&[Value::Int(17), Value::Int(5)]).unwrap();
2224 assert_eq!(result, Value::Float(15.0));
2225
2226 let result = builtin::mround::builtin_mround(&[Value::Int(18), Value::Int(5)]).unwrap();
2227 assert_eq!(result, Value::Float(20.0));
2228
2229 let result = builtin::mround::builtin_mround(&[Value::Int(15), Value::Int(5)]).unwrap();
2230 assert_eq!(result, Value::Float(15.0));
2231
2232 let result = builtin::mround::builtin_mround(&[Value::Float(17.3), Value::Int(5)]).unwrap();
2234 assert_eq!(result, Value::Float(15.0));
2235
2236 let result = builtin::mround::builtin_mround(&[Value::Float(18.7), Value::Int(5)]).unwrap();
2237 assert_eq!(result, Value::Float(20.0));
2238
2239 let result =
2241 builtin::mround::builtin_mround(&[Value::String("17".to_string()), Value::Int(5)])
2242 .unwrap();
2243 assert_eq!(result, Value::Float(15.0));
2244
2245 let result =
2246 builtin::mround::builtin_mround(&[Value::String("18.5".to_string()), Value::Int(5)])
2247 .unwrap();
2248 assert_eq!(result, Value::Float(20.0));
2249
2250 let result =
2252 builtin::mround::builtin_mround(&[Value::Int(17), Value::String("5".to_string())])
2253 .unwrap();
2254 assert_eq!(result, Value::Float(15.0));
2255
2256 let result = builtin::mround::builtin_mround(&[Value::Int(17), Value::Int(0)]).unwrap();
2258 assert_eq!(result, Value::Float(17.0));
2259
2260 let result = builtin::mround::builtin_mround(&[
2262 Value::String("not a number".to_string()),
2263 Value::Int(5),
2264 ]);
2265 assert!(result.is_err());
2266
2267 let result = builtin::mround::builtin_mround(&[
2269 Value::Int(17),
2270 Value::String("not a number".to_string()),
2271 ]);
2272 assert!(result.is_err());
2273
2274 let result = builtin::mround::builtin_mround(&[Value::Int(17)]);
2276 assert!(result.is_err());
2277
2278 let result =
2279 builtin::mround::builtin_mround(&[Value::Int(17), Value::Int(5), Value::Int(1)]);
2280 assert!(result.is_err());
2281 }
2282
2283 #[test]
2284 #[cfg(feature = "rand")]
2285 fn test_builtin_rand() {
2286 let result = builtin::rand::builtin_rand(&[]).unwrap();
2288 match result {
2289 Value::Float(f) => {
2290 assert!((0.0..1.0).contains(&f));
2291 }
2292 _ => panic!("Expected Float"),
2293 }
2294
2295 let result = builtin::rand::builtin_rand(&[Value::Int(42)]).unwrap();
2297 match result {
2298 Value::Float(f) => {
2299 assert!((0.0..1.0).contains(&f));
2300 }
2301 _ => panic!("Expected Float"),
2302 }
2303
2304 let result = builtin::rand::builtin_rand(&[Value::Int(1), Value::Int(2)]);
2306 assert!(result.is_err());
2307 }
2308
2309 #[test]
2310 fn test_builtin_histogram_array() {
2311 let arr = Value::Array(vec![
2312 Value::Int(1),
2313 Value::Int(2),
2314 Value::Int(3),
2315 Value::Int(4),
2316 Value::Int(5),
2317 Value::Int(6),
2318 Value::Int(7),
2319 Value::Int(8),
2320 Value::Int(9),
2321 Value::Int(10),
2322 ]);
2323 let result = builtin_histogram(&[arr]).unwrap();
2324 match result {
2325 Value::Object(obj) => {
2326 assert!(obj.contains_key("counts"));
2327 assert!(obj.contains_key("bins"));
2328 if let Value::Array(counts) = &obj["counts"] {
2329 assert_eq!(counts.len(), 10);
2330 assert_eq!(counts[0], Value::Int(1)); assert_eq!(counts[9], Value::Int(1)); } else {
2334 panic!("counts should be array");
2335 }
2336 if let Value::Array(bins) = &obj["bins"] {
2337 assert_eq!(bins.len(), 11); assert_eq!(bins[0], Value::Float(1.0));
2339 assert_eq!(bins[10], Value::Float(10.0));
2340 } else {
2341 panic!("bins should be array");
2342 }
2343 }
2344 _ => panic!("Expected Object"),
2345 }
2346 }
2347
2348 #[test]
2349 fn test_builtin_histogram_series() {
2350 let series = Series::new(
2351 PlSmallStr::from("values"),
2352 vec![1i64, 2, 3, 4, 5, 6, 7, 8, 9, 10],
2353 );
2354 let series_value = Value::Series(series);
2355 let result = builtin_histogram(&[series_value]).unwrap();
2356 match result {
2357 Value::Object(obj) => {
2358 assert!(obj.contains_key("counts"));
2359 assert!(obj.contains_key("bins"));
2360 if let Value::Array(counts) = &obj["counts"] {
2361 assert_eq!(counts.len(), 10);
2362 }
2363 }
2364 _ => panic!("Expected Object"),
2365 }
2366 }
2367
2368 #[test]
2369 fn test_builtin_histogram_empty() {
2370 let arr = Value::Array(vec![]);
2371 let result = builtin_histogram(&[arr]).unwrap();
2372 match result {
2373 Value::Object(obj) => {
2374 if let Value::Array(counts) = &obj["counts"] {
2375 assert_eq!(counts.len(), 0);
2376 }
2377 if let Value::Array(bins) = &obj["bins"] {
2378 assert_eq!(bins.len(), 0);
2379 }
2380 }
2381 _ => panic!("Expected Object"),
2382 }
2383 }
2384
2385 #[test]
2386 fn test_builtin_histogram_custom_bins() {
2387 let arr = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
2388 let result = builtin_histogram(&[arr, Value::Int(5)]).unwrap();
2389 match result {
2390 Value::Object(obj) => {
2391 if let Value::Array(counts) = &obj["counts"] {
2392 assert_eq!(counts.len(), 5);
2393 }
2394 if let Value::Array(bins) = &obj["bins"] {
2395 assert_eq!(bins.len(), 6); }
2397 }
2398 _ => panic!("Expected Object"),
2399 }
2400 }
2401
2402 #[test]
2403 fn test_builtin_histogram_invalid_args() {
2404 let result = builtin_histogram(&[]);
2406 assert!(result.is_err());
2407
2408 let arr = Value::Array(vec![Value::Int(1)]);
2410 let result = builtin_histogram(&[arr.clone(), Value::Int(5), Value::Int(6)]);
2411 assert!(result.is_err());
2412
2413 let result = builtin_histogram(&[arr.clone(), Value::Int(0)]);
2415 assert!(result.is_err());
2416
2417 let result = builtin_histogram(&[arr.clone(), Value::String("5".to_string())]);
2419 assert!(result.is_err());
2420
2421 let result = builtin_histogram(&[Value::Int(1)]);
2423 assert!(result.is_err());
2424 }
2425
2426 #[test]
2427 fn test_builtin_transliterate() {
2428 let result = builtin_transliterate(&[
2430 Value::String("Привет".to_string()),
2431 Value::String("cyrillic".to_string()),
2432 Value::String("latin".to_string()),
2433 ])
2434 .unwrap();
2435 assert_eq!(result, Value::String("Privet".to_string()));
2436
2437 let result = builtin_transliterate(&[
2439 Value::String("Москва".to_string()),
2440 Value::String("cyrillic".to_string()),
2441 Value::String("latin".to_string()),
2442 ])
2443 .unwrap();
2444 assert_eq!(result, Value::String("Moskva".to_string()));
2445
2446 let result = builtin_transliterate(&[
2448 Value::String("Александр".to_string()),
2449 Value::String("cyrillic".to_string()),
2450 Value::String("latin".to_string()),
2451 ])
2452 .unwrap();
2453 assert_eq!(result, Value::String("Aleksandr".to_string()));
2454
2455 let result = builtin_transliterate(&[
2457 Value::Array(vec![
2458 Value::String("Привет".to_string()),
2459 Value::String("Москва".to_string()),
2460 Value::Int(123), ]),
2462 Value::String("cyrillic".to_string()),
2463 Value::String("latin".to_string()),
2464 ])
2465 .unwrap();
2466 assert_eq!(
2467 result,
2468 Value::Array(vec![
2469 Value::String("Privet".to_string()),
2470 Value::String("Moskva".to_string()),
2471 Value::Int(123)
2472 ])
2473 );
2474
2475 let text_series = Series::new(PlSmallStr::from("text"), &["Привет", "Москва", "тест"]);
2477 let df = DataFrame::new(vec![text_series.into()]).unwrap();
2478 let result = builtin_transliterate(&[
2479 Value::DataFrame(df),
2480 Value::String("cyrillic".to_string()),
2481 Value::String("latin".to_string()),
2482 ])
2483 .unwrap();
2484 if let Value::DataFrame(result_df) = result {
2485 let text_col = result_df.column("text").unwrap();
2486 let values: Vec<String> = text_col
2487 .str()
2488 .unwrap()
2489 .into_iter()
2490 .map(|s| s.unwrap_or("").to_string())
2491 .collect();
2492 assert_eq!(values, vec!["Privet", "Moskva", "test"]);
2493 } else {
2494 panic!("Expected DataFrame");
2495 }
2496
2497 let result = builtin_transliterate(&[
2499 Value::String("hello".to_string()),
2500 Value::String("latin".to_string()),
2501 Value::String("cyrillic".to_string()),
2502 ]);
2503 assert!(result.is_err());
2504 assert!(result.unwrap_err().to_string().contains("not supported"));
2505
2506 let result = builtin_transliterate(&[Value::String("test".to_string())]);
2508 assert!(result.is_err());
2509
2510 let result = builtin_transliterate(&[
2511 Value::Int(123),
2512 Value::String("cyrillic".to_string()),
2513 Value::String("latin".to_string()),
2514 ]);
2515 assert!(result.is_err());
2516 }
2517
2518 #[test]
2519 fn test_transliterate_registry() {
2520 let registry = BuiltinRegistry::new();
2521 assert!(registry.has_function("transliterate"));
2522 let result = registry
2523 .call_function(
2524 "transliterate",
2525 &[
2526 Value::String("Привет".to_string()),
2527 Value::String("cyrillic".to_string()),
2528 Value::String("latin".to_string()),
2529 ],
2530 )
2531 .unwrap();
2532 assert_eq!(result, Value::String("Privet".to_string()));
2533 }
2534
2535 #[test]
2536 fn test_builtin_length() {
2537 let registry = BuiltinRegistry::new();
2538
2539 let arr = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
2541 let result = registry.call_function("length", &[arr]).unwrap();
2542 assert_eq!(result, Value::Int(3));
2543
2544 let mixed_arr = Value::Array(vec![
2546 Value::Int(1),
2547 Value::String("hello".to_string()),
2548 Value::Bool(true),
2549 ]);
2550 let result = registry.call_function("length", &[mixed_arr]).unwrap();
2551 assert_eq!(result, Value::Int(3));
2552
2553 let empty_arr = Value::Array(vec![]);
2555 let result = registry.call_function("length", &[empty_arr]).unwrap();
2556 assert_eq!(result, Value::Int(0));
2557
2558 let str_val = Value::String("hello".to_string());
2560 let result = registry.call_function("length", &[str_val]).unwrap();
2561 assert_eq!(result, Value::Int(5));
2562
2563 let unicode_str = Value::String("héllo wörld".to_string());
2565 let result = registry.call_function("length", &[unicode_str]).unwrap();
2566 assert_eq!(result, Value::Int(11)); let mut obj = HashMap::new();
2570 obj.insert("a".to_string(), Value::Int(1));
2571 obj.insert("b".to_string(), Value::Int(2));
2572 let obj_val = Value::Object(obj);
2573 let result = registry.call_function("length", &[obj_val]).unwrap();
2574 assert_eq!(result, Value::Int(2));
2575
2576 let df = create_test_dataframe();
2578 let df_val = Value::DataFrame(df);
2579 let result = registry.call_function("length", &[df_val]).unwrap();
2580 assert_eq!(result, Value::Int(3)); let series = Series::new(PlSmallStr::from("test"), &[1, 2, 3, 4]);
2584 let series_val = Value::Series(series);
2585 let result = registry.call_function("length", &[series_val]).unwrap();
2586 assert_eq!(result, Value::Int(4));
2587
2588 let result = registry.call_function("length", &[Value::Null]).unwrap();
2590 assert_eq!(result, Value::Int(0));
2591
2592 let result = registry.call_function("length", &[Value::Int(42)]).unwrap();
2594 assert_eq!(result, Value::Int(1));
2595
2596 let result = registry
2597 .call_function("length", &[Value::Bool(true)])
2598 .unwrap();
2599 assert_eq!(result, Value::Int(1));
2600 }
2601
2602 #[test]
2603 fn test_builtin_keys() {
2604 let registry = BuiltinRegistry::new();
2605
2606 let mut obj = HashMap::new();
2608 obj.insert("b".to_string(), Value::Int(2));
2609 obj.insert("a".to_string(), Value::Int(1));
2610 obj.insert("c".to_string(), Value::Int(3));
2611 let obj_val = Value::Object(obj);
2612 let result = registry.call_function("keys", &[obj_val]).unwrap();
2613 if let Value::Array(keys) = result {
2614 assert_eq!(keys.len(), 3);
2615 assert_eq!(keys[0], Value::String("a".to_string()));
2617 assert_eq!(keys[1], Value::String("b".to_string()));
2618 assert_eq!(keys[2], Value::String("c".to_string()));
2619 } else {
2620 panic!("Expected array of keys");
2621 }
2622
2623 let df = create_test_dataframe();
2625 let df_val = Value::DataFrame(df);
2626 let result = registry.call_function("keys", &[df_val]).unwrap();
2627 if let Value::Array(keys) = result {
2628 assert_eq!(keys.len(), 3);
2629 assert!(keys.contains(&Value::String("name".to_string())));
2630 assert!(keys.contains(&Value::String("age".to_string())));
2631 assert!(keys.contains(&Value::String("score".to_string())));
2632 } else {
2633 panic!("Expected array of column names");
2634 }
2635 }
2636
2637 #[test]
2638 fn test_builtin_values() {
2639 let registry = BuiltinRegistry::new();
2640
2641 let mut obj = HashMap::new();
2643 obj.insert("a".to_string(), Value::Int(1));
2644 obj.insert("b".to_string(), Value::Int(2));
2645 let obj_val = Value::Object(obj);
2646 let result = registry.call_function("values", &[obj_val]).unwrap();
2647 if let Value::Array(values) = result {
2648 assert_eq!(values.len(), 2);
2649 assert!(values.contains(&Value::Int(1)));
2650 assert!(values.contains(&Value::Int(2)));
2651 } else {
2652 panic!("Expected array of values");
2653 }
2654 }
2655
2656 #[test]
2657 fn test_builtin_type() {
2658 let registry = BuiltinRegistry::new();
2659
2660 let result = registry.call_function("type", &[Value::Int(42)]).unwrap();
2662 assert_eq!(result, Value::String("integer".to_string()));
2663
2664 let result = registry
2665 .call_function("type", &[Value::Float(3.14)])
2666 .unwrap();
2667 assert_eq!(result, Value::String("float".to_string()));
2668
2669 let result = registry
2670 .call_function("type", &[Value::String("hello".to_string())])
2671 .unwrap();
2672 assert_eq!(result, Value::String("string".to_string()));
2673
2674 let result = registry
2675 .call_function("type", &[Value::Bool(true)])
2676 .unwrap();
2677 assert_eq!(result, Value::String("boolean".to_string()));
2678
2679 let result = registry.call_function("type", &[Value::Null]).unwrap();
2680 assert_eq!(result, Value::String("null".to_string()));
2681
2682 let arr = Value::Array(vec![Value::Int(1)]);
2683 let result = registry.call_function("type", &[arr]).unwrap();
2684 assert_eq!(result, Value::String("array".to_string()));
2685
2686 let mut obj = HashMap::new();
2687 obj.insert("key".to_string(), Value::Int(1));
2688 let obj_val = Value::Object(obj);
2689 let result = registry.call_function("type", &[obj_val]).unwrap();
2690 assert_eq!(result, Value::String("object".to_string()));
2691 }
2692
2693 #[test]
2694 fn test_builtin_empty() {
2695 let registry = BuiltinRegistry::new();
2696
2697 let empty_arr = Value::Array(vec![]);
2699 let result = registry.call_function("empty", &[empty_arr]).unwrap();
2700 assert_eq!(result, Value::Bool(true));
2701
2702 let arr = Value::Array(vec![Value::Int(1)]);
2704 let result = registry.call_function("empty", &[arr]).unwrap();
2705 assert_eq!(result, Value::Bool(false));
2706
2707 let empty_obj = Value::Object(HashMap::new());
2709 let result = registry.call_function("empty", &[empty_obj]).unwrap();
2710 assert_eq!(result, Value::Bool(true));
2711
2712 let mut obj = HashMap::new();
2714 obj.insert("key".to_string(), Value::Int(1));
2715 let obj_val = Value::Object(obj);
2716 let result = registry.call_function("empty", &[obj_val]).unwrap();
2717 assert_eq!(result, Value::Bool(false));
2718
2719 let empty_str = Value::String("".to_string());
2721 let result = registry.call_function("empty", &[empty_str]).unwrap();
2722 assert_eq!(result, Value::Bool(true));
2723
2724 let str_val = Value::String("hello".to_string());
2726 let result = registry.call_function("empty", &[str_val]).unwrap();
2727 assert_eq!(result, Value::Bool(false));
2728 }
2729
2730 #[test]
2731 fn test_builtin_generate_uuidv4() {
2732 let registry = BuiltinRegistry::new();
2733
2734 let result1 = registry.call_function("generate_uuidv4", &[]).unwrap();
2736 let result2 = registry.call_function("generate_uuidv4", &[]).unwrap();
2737
2738 match (&result1, &result2) {
2739 (Value::String(uuid1), Value::String(uuid2)) => {
2740 assert_ne!(uuid1, uuid2);
2742
2743 assert_eq!(uuid1.len(), 36); assert_eq!(uuid2.len(), 36);
2746
2747 let uuid1_parsed = uuid::Uuid::parse_str(uuid1).unwrap();
2749 let uuid2_parsed = uuid::Uuid::parse_str(uuid2).unwrap();
2750
2751 assert_eq!(uuid1_parsed.get_version_num(), 4);
2752 assert_eq!(uuid2_parsed.get_version_num(), 4);
2753 }
2754 _ => panic!("Expected strings"),
2755 }
2756
2757 let result = registry.call_function("generate_uuidv4", &[Value::Int(1)]);
2759 assert!(result.is_err());
2760 }
2761
2762 #[test]
2763 fn test_builtin_avg_ifs_array() {
2764 let registry = BuiltinRegistry::new();
2765
2766 let values = Value::Array(vec![
2768 Value::Int(10),
2769 Value::Int(20),
2770 Value::Int(30),
2771 Value::Int(40),
2772 ]);
2773 let mask1 = Value::Array(vec![
2774 Value::Bool(true),
2775 Value::Bool(false),
2776 Value::Bool(true),
2777 Value::Bool(false),
2778 ]);
2779 let mask2 = Value::Array(vec![
2780 Value::Bool(true),
2781 Value::Bool(true),
2782 Value::Bool(true),
2783 Value::Bool(false),
2784 ]);
2785 let result = registry
2786 .call_function("avg_ifs", &[values, mask1, mask2])
2787 .unwrap();
2788 assert_eq!(result, Value::Float(20.0)); let values = Value::Array(vec![
2792 Value::Float(1.5),
2793 Value::Float(2.5),
2794 Value::Float(3.5),
2795 ]);
2796 let mask1 = Value::Array(vec![
2797 Value::Bool(true),
2798 Value::Bool(true),
2799 Value::Bool(true),
2800 ]);
2801 let mask2 = Value::Array(vec![
2802 Value::Bool(true),
2803 Value::Bool(false),
2804 Value::Bool(true),
2805 ]);
2806 let result = registry
2807 .call_function("avg_ifs", &[values, mask1, mask2])
2808 .unwrap();
2809 assert_eq!(result, Value::Float(2.5)); let values = Value::Array(vec![Value::Int(10), Value::Int(20)]);
2813 let mask1 = Value::Array(vec![Value::Bool(false), Value::Bool(false)]);
2814 let mask2 = Value::Array(vec![Value::Bool(true), Value::Bool(true)]);
2815 let result = registry
2816 .call_function("avg_ifs", &[values, mask1, mask2])
2817 .unwrap();
2818 assert_eq!(result, Value::Null);
2819
2820 let values = Value::Array(vec![Value::Int(5), Value::Int(15), Value::Int(25)]);
2822 let mask1 = Value::Array(vec![
2823 Value::Bool(true),
2824 Value::Bool(true),
2825 Value::Bool(false),
2826 ]);
2827 let mask2 = Value::Array(vec![
2828 Value::Bool(true),
2829 Value::Bool(false),
2830 Value::Bool(true),
2831 ]);
2832 let result = registry
2833 .call_function("avg_ifs", &[values, mask1, mask2])
2834 .unwrap();
2835 assert_eq!(result, Value::Float(5.0)); }
2837
2838 #[test]
2839 fn test_builtin_avg_ifs_dataframe() {
2840 let registry = BuiltinRegistry::new();
2841
2842 let df = DataFrame::new(vec![
2844 Series::new(PlSmallStr::from("a"), vec![10i64, 20, 30]).into(),
2845 Series::new(PlSmallStr::from("b"), vec![1i64, 2, 3]).into(),
2846 Series::new(PlSmallStr::from("c"), vec![100.0f64, 200.0, 300.0]).into(),
2847 ])
2848 .unwrap();
2849 let df_value = Value::DataFrame(df);
2850
2851 let mask1 = Series::new(PlSmallStr::from("mask1"), vec![true, false, true]);
2853 let mask1_value = Value::Series(mask1);
2854 let mask2 = Series::new(PlSmallStr::from("mask2"), vec![true, true, true]);
2855 let mask2_value = Value::Series(mask2);
2856
2857 let result = registry
2858 .call_function("avg_ifs", &[df_value, mask1_value, mask2_value])
2859 .unwrap();
2860 match result {
2861 Value::Object(obj) => {
2862 assert_eq!(obj.get("a"), Some(&Value::Float(20.0))); assert_eq!(obj.get("b"), Some(&Value::Float(2.0))); assert_eq!(obj.get("c"), Some(&Value::Float(200.0))); }
2867 _ => panic!("Expected object"),
2868 }
2869 }
2870
2871 #[test]
2872 fn test_builtin_avg_ifs_series() {
2873 let registry = BuiltinRegistry::new();
2874
2875 let series = Series::new(PlSmallStr::from("values"), vec![10.0f64, 20.0, 30.0, 40.0]);
2877 let series_value = Value::Series(series);
2878
2879 let mask1 = Series::new(PlSmallStr::from("mask1"), vec![true, false, true, false]);
2880 let mask1_value = Value::Series(mask1);
2881 let mask2 = Series::new(PlSmallStr::from("mask2"), vec![true, true, true, false]);
2882 let mask2_value = Value::Series(mask2);
2883
2884 let result = registry
2885 .call_function("avg_ifs", &[series_value, mask1_value, mask2_value])
2886 .unwrap();
2887 assert_eq!(result, Value::Float(20.0)); let series = Series::new(PlSmallStr::from("values"), vec![10.0f64, 20.0]);
2891 let series_value = Value::Series(series);
2892 let mask1 = Series::new(PlSmallStr::from("mask1"), vec![false, false]);
2893 let mask1_value = Value::Series(mask1);
2894 let mask2 = Series::new(PlSmallStr::from("mask2"), vec![true, true]);
2895 let mask2_value = Value::Series(mask2);
2896
2897 let result = registry
2898 .call_function("avg_ifs", &[series_value, mask1_value, mask2_value])
2899 .unwrap();
2900 assert_eq!(result, Value::Null);
2901 }
2902
2903 #[test]
2904 fn test_builtin_avg_ifs_invalid_args() {
2905 let registry = BuiltinRegistry::new();
2906
2907 let result = registry.call_function("avg_ifs", &[Value::Array(vec![Value::Int(1)])]);
2909 assert!(result.is_err());
2910 assert!(result
2911 .unwrap_err()
2912 .to_string()
2913 .contains("expects at least 3 arguments"));
2914
2915 let values = Value::Array(vec![Value::Int(1), Value::Int(2)]);
2917 let mask1 = Value::Array(vec![Value::Bool(true)]); let mask2 = Value::Array(vec![Value::Bool(true), Value::Bool(false)]);
2919 let result = registry.call_function("avg_ifs", &[values, mask1, mask2]);
2920 assert!(result.is_err());
2921 assert!(result
2922 .unwrap_err()
2923 .to_string()
2924 .contains("all masks must have same length as values"));
2925
2926 let values = Value::Array(vec![Value::Int(1), Value::Int(2)]);
2928 let mask1 = Value::String("not array".to_string());
2929 let mask2 = Value::Array(vec![Value::Bool(true), Value::Bool(false)]);
2930 let result = registry.call_function("avg_ifs", &[values, mask1, mask2]);
2931 assert!(result.is_err());
2932 assert!(result
2933 .unwrap_err()
2934 .to_string()
2935 .contains("all masks must be arrays"));
2936
2937 let result = registry.call_function(
2939 "avg_ifs",
2940 &[
2941 Value::String("not array".to_string()),
2942 Value::Array(vec![Value::Bool(true)]),
2943 Value::Array(vec![Value::Bool(true)]),
2944 ],
2945 );
2946 assert!(result.is_err());
2947 assert!(result
2948 .unwrap_err()
2949 .to_string()
2950 .contains("first argument must be array, DataFrame, or Series"));
2951 }
2952
2953 #[test]
2954 fn test_builtin_count_if_array() {
2955 let registry = BuiltinRegistry::new();
2956
2957 let values = Value::Array(vec![
2959 Value::Int(10),
2960 Value::Int(20),
2961 Value::Int(30),
2962 Value::Int(40),
2963 ]);
2964 let mask = Value::Array(vec![
2965 Value::Bool(true),
2966 Value::Bool(false),
2967 Value::Bool(true),
2968 Value::Bool(false),
2969 ]);
2970 let result = registry.call_function("count_if", &[values, mask]).unwrap();
2971 assert_eq!(result, Value::Int(2)); let values = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
2975 let mask = Value::Array(vec![
2976 Value::Bool(true),
2977 Value::Bool(true),
2978 Value::Bool(true),
2979 ]);
2980 let result = registry.call_function("count_if", &[values, mask]).unwrap();
2981 assert_eq!(result, Value::Int(3));
2982
2983 let values = Value::Array(vec![Value::Int(1), Value::Int(2)]);
2985 let mask = Value::Array(vec![Value::Bool(false), Value::Bool(false)]);
2986 let result = registry.call_function("count_if", &[values, mask]).unwrap();
2987 assert_eq!(result, Value::Int(0));
2988
2989 let values = Value::Array(vec![
2991 Value::Int(1),
2992 Value::Int(0),
2993 Value::String("hello".to_string()),
2994 Value::String("".to_string()),
2995 ]);
2996 let mask = Value::Array(vec![
2997 Value::Int(1),
2998 Value::Int(0),
2999 Value::String("hello".to_string()),
3000 Value::String("".to_string()),
3001 ]);
3002 let result = registry.call_function("count_if", &[values, mask]).unwrap();
3003 assert_eq!(result, Value::Int(2)); let values = Value::Array(vec![]);
3007 let mask = Value::Array(vec![]);
3008 let result = registry.call_function("count_if", &[values, mask]).unwrap();
3009 assert_eq!(result, Value::Int(0));
3010
3011 let values = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
3013 let mask = Value::Array(vec![Value::Bool(true), Value::Null, Value::Bool(false)]);
3014 let result = registry.call_function("count_if", &[values, mask]).unwrap();
3015 assert_eq!(result, Value::Int(1)); }
3017
3018 #[test]
3019 fn test_builtin_count_if_dataframe() {
3020 let registry = BuiltinRegistry::new();
3021
3022 let df = DataFrame::new(vec![
3024 Series::new(PlSmallStr::from("a"), vec![10i64, 20, 30]).into(),
3025 Series::new(PlSmallStr::from("b"), vec![1i64, 2, 3]).into(),
3026 ])
3027 .unwrap();
3028 let df_value = Value::DataFrame(df);
3029
3030 let mask = Series::new(PlSmallStr::from("mask"), vec![true, false, true]);
3032 let mask_value = Value::Series(mask);
3033
3034 let result = registry
3035 .call_function("count_if", &[df_value, mask_value])
3036 .unwrap();
3037 assert_eq!(result, Value::Int(2)); }
3039
3040 #[test]
3041 fn test_builtin_count_if_series() {
3042 let registry = BuiltinRegistry::new();
3043
3044 let series = Series::new(PlSmallStr::from("values"), vec![10.0f64, 20.0, 30.0, 40.0]);
3046 let series_value = Value::Series(series);
3047
3048 let mask = Series::new(PlSmallStr::from("mask"), vec![true, false, true, false]);
3049 let mask_value = Value::Series(mask);
3050
3051 let result = registry
3052 .call_function("count_if", &[series_value, mask_value])
3053 .unwrap();
3054 assert_eq!(result, Value::Int(2)); }
3056
3057 #[test]
3058 fn test_builtin_count_if_invalid_args() {
3059 let registry = BuiltinRegistry::new();
3060
3061 let result = registry.call_function("count_if", &[Value::Array(vec![Value::Int(1)])]);
3063 assert!(result.is_err());
3064 assert!(result
3065 .unwrap_err()
3066 .to_string()
3067 .contains("expects 2 arguments"));
3068
3069 let values = Value::Array(vec![Value::Int(1), Value::Int(2)]);
3071 let mask = Value::Array(vec![Value::Bool(true)]); let result = registry.call_function("count_if", &[values, mask]);
3073 assert!(result.is_err());
3074 assert!(result
3075 .unwrap_err()
3076 .to_string()
3077 .contains("collection and mask arrays must have same length"));
3078
3079 let values = Value::String("not array".to_string());
3081 let mask = Value::Array(vec![Value::Bool(true)]);
3082 let result = registry.call_function("count_if", &[values, mask]);
3083 assert!(result.is_err());
3084 assert!(result
3085 .unwrap_err()
3086 .to_string()
3087 .contains("requires (array, array) or (dataframe/series, series)"));
3088 }
3089
3090 #[test]
3091 fn test_builtin_sort() {
3092 let registry = BuiltinRegistry::new();
3093
3094 let arr = Value::Array(vec![Value::Int(3), Value::Int(1), Value::Int(2)]);
3096 let result = registry.call_function("sort", &[arr]).unwrap();
3097 if let Value::Array(sorted) = result {
3098 assert_eq!(sorted, vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
3099 } else {
3100 panic!("Expected sorted array");
3101 }
3102
3103 let arr = Value::Array(vec![
3105 Value::String("c".to_string()),
3106 Value::String("a".to_string()),
3107 Value::String("b".to_string()),
3108 ]);
3109 let result = registry.call_function("sort", &[arr]).unwrap();
3110 if let Value::Array(sorted) = result {
3111 assert_eq!(
3112 sorted,
3113 vec![
3114 Value::String("a".to_string()),
3115 Value::String("b".to_string()),
3116 Value::String("c".to_string())
3117 ]
3118 );
3119 } else {
3120 panic!("Expected sorted array");
3121 }
3122
3123 let arr = Value::Array(vec![Value::Int(1), Value::String("a".to_string())]);
3125 let result = registry
3126 .call_function("sort", std::slice::from_ref(&arr))
3127 .unwrap();
3128 assert_eq!(result, arr); let result = registry.call_function("sort", &[]);
3132 assert!(result.is_err());
3133 assert!(result
3134 .unwrap_err()
3135 .to_string()
3136 .contains("expects 1 argument"));
3137
3138 let result = registry.call_function("sort", &[Value::Int(1), Value::Int(2)]);
3139 assert!(result.is_err());
3140 assert!(result
3141 .unwrap_err()
3142 .to_string()
3143 .contains("expects 1 argument"));
3144 }
3145
3146 #[test]
3147 fn test_builtin_stdev_s_array() {
3148 let registry = BuiltinRegistry::new();
3149
3150 let arr = Value::Array(vec![
3152 Value::Int(1),
3153 Value::Int(2),
3154 Value::Int(3),
3155 Value::Int(4),
3156 Value::Int(5),
3157 ]);
3158 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3159 match result {
3160 Value::Float(stdev) => {
3161 assert!((stdev - 1.58113883).abs() < 0.0001);
3163 }
3164 _ => panic!("Expected float result"),
3165 }
3166
3167 let arr = Value::Array(vec![
3169 Value::Float(1.0),
3170 Value::Float(2.0),
3171 Value::Float(3.0),
3172 Value::Float(4.0),
3173 Value::Float(5.0),
3174 ]);
3175 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3176 match result {
3177 Value::Float(stdev) => {
3178 assert!((stdev - 1.58113883).abs() < 0.0001);
3179 }
3180 _ => panic!("Expected float result"),
3181 }
3182
3183 let arr = Value::Array(vec![Value::Int(1), Value::Float(2.0), Value::Int(3)]);
3185 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3186 match result {
3187 Value::Float(stdev) => {
3188 assert!((stdev - 1.0).abs() < 0.0001);
3190 }
3191 _ => panic!("Expected float result"),
3192 }
3193
3194 let arr = Value::Array(vec![Value::Int(1)]);
3196 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3197 assert_eq!(result, Value::Null);
3198
3199 let arr = Value::Array(vec![]);
3201 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3202 assert_eq!(result, Value::Null);
3203
3204 let arr = Value::Array(vec![
3206 Value::Int(1),
3207 Value::String("test".to_string()),
3208 Value::Int(3),
3209 ]);
3210 let result = registry.call_function("stdev_s", &[arr]).unwrap();
3211 match result {
3212 Value::Float(stdev) => {
3213 assert!((stdev - std::f64::consts::SQRT_2).abs() < 0.0001);
3215 }
3216 _ => panic!("Expected float result"),
3217 }
3218 }
3219
3220 #[test]
3221 fn test_builtin_stdev_s_invalid_args() {
3222 let registry = BuiltinRegistry::new();
3223
3224 let result = registry.call_function("stdev_s", &[]);
3226 assert!(result.is_err());
3227 assert!(result
3228 .unwrap_err()
3229 .to_string()
3230 .contains("expects 1 argument"));
3231
3232 let result = registry.call_function("stdev_s", &[Value::Int(1), Value::Int(2)]);
3234 assert!(result.is_err());
3235 assert!(result
3236 .unwrap_err()
3237 .to_string()
3238 .contains("expects 1 argument"));
3239
3240 let result = registry.call_function("stdev_s", &[Value::String("test".to_string())]);
3242 assert!(result.is_err());
3243 assert!(result
3244 .unwrap_err()
3245 .to_string()
3246 .contains("requires array, DataFrame, or Series"));
3247 }
3248
3249 #[test]
3250 fn test_builtin_stdev_s_dataframe() {
3251 let registry = BuiltinRegistry::new();
3252
3253 let df = DataFrame::new(vec![
3255 Series::new(PlSmallStr::from("col1"), &[1.0, 2.0, 3.0]).into(),
3256 Series::new(PlSmallStr::from("col2"), &[4.0, 5.0, 6.0]).into(),
3257 ])
3258 .unwrap();
3259 let df_value = Value::DataFrame(df);
3260
3261 let result = registry.call_function("stdev_s", &[df_value]).unwrap();
3262 match result {
3263 Value::Object(obj) => {
3264 assert_eq!(obj.get("col1"), Some(&Value::Float(1.0)));
3266 assert_eq!(obj.get("col2"), Some(&Value::Float(1.0)));
3267 }
3268 _ => panic!("Expected object result"),
3269 }
3270 }
3271
3272 #[test]
3273 fn test_builtin_stdev_s_series() {
3274 let registry = BuiltinRegistry::new();
3275
3276 let series = Series::new(PlSmallStr::from("test"), &[1.0, 2.0, 3.0, 4.0, 5.0]);
3278 let series_value = Value::Series(series);
3279
3280 let result = registry.call_function("stdev_s", &[series_value]).unwrap();
3281 match result {
3283 Value::Float(val) => assert!((val - 1.5811388).abs() < 1e-6),
3284 _ => panic!("Expected Float"),
3285 }
3286 }
3287
3288 #[test]
3289 fn test_builtin_std_array() {
3290 let registry = BuiltinRegistry::new();
3291
3292 let arr = Value::Array(vec![
3294 Value::Int(1),
3295 Value::Int(2),
3296 Value::Int(3),
3297 Value::Int(4),
3298 Value::Int(5),
3299 ]);
3300 let result = registry.call_function("std", &[arr]).unwrap();
3301 match result {
3302 Value::Float(stdev) => {
3303 assert!((stdev - 1.58113883).abs() < 0.0001);
3305 }
3306 _ => panic!("Expected float result"),
3307 }
3308
3309 let arr = Value::Array(vec![
3311 Value::Float(1.0),
3312 Value::Float(2.0),
3313 Value::Float(3.0),
3314 Value::Float(4.0),
3315 Value::Float(5.0),
3316 ]);
3317 let result = registry.call_function("std", &[arr]).unwrap();
3318 match result {
3319 Value::Float(stdev) => {
3320 assert!((stdev - 1.58113883).abs() < 0.0001);
3321 }
3322 _ => panic!("Expected float result"),
3323 }
3324
3325 let arr = Value::Array(vec![Value::Int(1), Value::Float(2.0), Value::Int(3)]);
3327 let result = registry.call_function("std", &[arr]).unwrap();
3328 match result {
3329 Value::Float(stdev) => {
3330 assert!((stdev - 1.0).abs() < 0.0001);
3332 }
3333 _ => panic!("Expected float result"),
3334 }
3335
3336 let arr = Value::Array(vec![Value::Int(1)]);
3338 let result = registry.call_function("std", &[arr]).unwrap();
3339 assert_eq!(result, Value::Null);
3340
3341 let arr = Value::Array(vec![]);
3343 let result = registry.call_function("std", &[arr]).unwrap();
3344 assert_eq!(result, Value::Null);
3345
3346 let arr = Value::Array(vec![
3348 Value::Int(1),
3349 Value::String("test".to_string()),
3350 Value::Int(3),
3351 ]);
3352 let result = registry.call_function("std", &[arr]).unwrap();
3353 match result {
3354 Value::Float(stdev) => {
3355 assert!((stdev - std::f64::consts::SQRT_2).abs() < 0.0001);
3357 }
3358 _ => panic!("Expected float result"),
3359 }
3360 }
3361
3362 #[test]
3363 fn test_builtin_std_invalid_args() {
3364 let registry = BuiltinRegistry::new();
3365
3366 let result = registry.call_function("std", &[]);
3368 assert!(result.is_err());
3369 assert!(result
3370 .unwrap_err()
3371 .to_string()
3372 .contains("expects 1 argument"));
3373
3374 let result = registry.call_function("std", &[Value::Int(1), Value::Int(2)]);
3376 assert!(result.is_err());
3377 assert!(result
3378 .unwrap_err()
3379 .to_string()
3380 .contains("expects 1 argument"));
3381
3382 let result = registry.call_function("std", &[Value::String("test".to_string())]);
3384 assert!(result.is_err());
3385 assert!(result
3386 .unwrap_err()
3387 .to_string()
3388 .contains("requires array, DataFrame, or Series"));
3389 }
3390
3391 #[test]
3392 fn test_builtin_std_dataframe() {
3393 let registry = BuiltinRegistry::new();
3394
3395 let df = DataFrame::new(vec![
3397 Series::new("col1".into(), &[1.0, 2.0, 3.0]).into(),
3398 Series::new("col2".into(), &[4.0, 5.0, 6.0]).into(),
3399 ])
3400 .unwrap();
3401 let df_value = Value::DataFrame(df);
3402
3403 let result = registry.call_function("std", &[df_value]).unwrap();
3404 match result {
3405 Value::Object(obj) => {
3406 assert_eq!(obj.get("col1"), Some(&Value::Null));
3408 assert_eq!(obj.get("col2"), Some(&Value::Null));
3409 }
3410 _ => panic!("Expected object result"),
3411 }
3412 }
3413
3414 #[test]
3415 fn test_builtin_std_series() {
3416 let registry = BuiltinRegistry::new();
3417
3418 let series = Series::new(PlSmallStr::from("test"), &[1.0, 2.0, 3.0, 4.0, 5.0]);
3420 let series_value = Value::Series(series);
3421
3422 let result = registry.call_function("std", &[series_value]).unwrap();
3423 assert_eq!(result, Value::Null);
3425 }
3426
3427 #[test]
3428 fn test_builtin_today() {
3429 let registry = BuiltinRegistry::new();
3430
3431 let result = registry.call_function("today", &[]).unwrap();
3433 match result {
3434 Value::String(date_str) => {
3435 assert_eq!(date_str.len(), 10);
3437 assert!(date_str.chars().nth(4) == Some('-'));
3438 assert!(date_str.chars().nth(7) == Some('-'));
3439 let today = chrono::Utc::now().date_naive();
3441 let expected = today.format("%Y-%m-%d").to_string();
3442 assert_eq!(date_str, expected);
3443 }
3444 _ => panic!("Expected string result"),
3445 }
3446
3447 let result = registry.call_function("today", &[Value::Int(1)]);
3449 assert!(result.is_err());
3450 }
3451
3452 #[test]
3453 fn test_builtin_repeat() {
3454 let registry = BuiltinRegistry::new();
3455
3456 let value = Value::String("hello".to_string());
3458 let count = Value::Int(3);
3459 let result = registry.call_function("repeat", &[value, count]).unwrap();
3460 match result {
3461 Value::Array(arr) => {
3462 assert_eq!(arr.len(), 3);
3463 assert_eq!(arr[0], Value::String("hello".to_string()));
3464 assert_eq!(arr[1], Value::String("hello".to_string()));
3465 assert_eq!(arr[2], Value::String("hello".to_string()));
3466 }
3467 _ => panic!("Expected array"),
3468 }
3469
3470 let value = Value::Int(42);
3472 let count = Value::Int(0);
3473 let result = registry.call_function("repeat", &[value, count]).unwrap();
3474 match result {
3475 Value::Array(arr) => {
3476 assert_eq!(arr.len(), 0);
3477 }
3478 _ => panic!("Expected array"),
3479 }
3480
3481 let value = Value::Bool(true);
3483 let count = Value::Int(1);
3484 let result = registry.call_function("repeat", &[value, count]).unwrap();
3485 match result {
3486 Value::Array(arr) => {
3487 assert_eq!(arr.len(), 1);
3488 assert_eq!(arr[0], Value::Bool(true));
3489 }
3490 _ => panic!("Expected array"),
3491 }
3492
3493 let value = Value::String("test".to_string());
3495 let count = Value::Int(-1);
3496 let result = registry.call_function("repeat", &[value, count]);
3497 assert!(result.is_err());
3498 assert!(result
3499 .unwrap_err()
3500 .to_string()
3501 .contains("non-negative integer"));
3502
3503 let result = registry.call_function("repeat", &[Value::String("test".to_string())]);
3505 assert!(result.is_err());
3506 assert!(result
3507 .unwrap_err()
3508 .to_string()
3509 .contains("expects 2 arguments"));
3510
3511 let result = registry.call_function(
3512 "repeat",
3513 &[
3514 Value::String("test".to_string()),
3515 Value::Int(1),
3516 Value::Int(2),
3517 ],
3518 );
3519 assert!(result.is_err());
3520 assert!(result
3521 .unwrap_err()
3522 .to_string()
3523 .contains("expects 2 arguments"));
3524
3525 let value = Value::String("test".to_string());
3527 let count = Value::String("not a number".to_string());
3528 let result = registry.call_function("repeat", &[value, count]);
3529 assert!(result.is_err());
3530 assert!(result
3531 .unwrap_err()
3532 .to_string()
3533 .contains("non-negative integer"));
3534 }
3535
3536 #[test]
3537 fn test_builtin_avg() {
3538 let registry = BuiltinRegistry::new();
3539
3540 let values = Value::Array(vec![Value::Int(10), Value::Int(20), Value::Int(30)]);
3542 let result = registry.call_function("avg", &[values]).unwrap();
3543 assert_eq!(result, Value::Float(20.0));
3544
3545 let values = Value::Array(vec![
3547 Value::Float(1.5),
3548 Value::Float(2.5),
3549 Value::Float(3.5),
3550 ]);
3551 let result = registry.call_function("avg", &[values]).unwrap();
3552 assert_eq!(result, Value::Float(2.5));
3553
3554 let values = Value::Array(vec![Value::Int(10), Value::Float(20.0), Value::Int(30)]);
3556 let result = registry.call_function("avg", &[values]).unwrap();
3557 assert_eq!(result, Value::Float(20.0));
3558
3559 let values = Value::Array(vec![]);
3561 let result = registry.call_function("avg", &[values]).unwrap();
3562 assert_eq!(result, Value::Null);
3563
3564 let values = Value::Array(vec![
3566 Value::Int(10),
3567 Value::String("ignore".to_string()),
3568 Value::Int(30),
3569 ]);
3570 let result = registry.call_function("avg", &[values]).unwrap();
3571 assert_eq!(result, Value::Float(20.0));
3572
3573 let result = registry.call_function("avg", &[]);
3575 assert!(result.is_err());
3576 assert!(result
3577 .unwrap_err()
3578 .to_string()
3579 .contains("expects 1 argument"));
3580
3581 let result = registry.call_function("avg", &[Value::Array(vec![]), Value::Array(vec![])]);
3583 assert!(result.is_err());
3584 assert!(result
3585 .unwrap_err()
3586 .to_string()
3587 .contains("expects 1 argument"));
3588 }
3589
3590 #[test]
3591 fn test_builtin_correl_arrays() {
3592 let registry = BuiltinRegistry::new();
3593
3594 let arr1 = Value::Array(vec![
3596 Value::Int(1),
3597 Value::Int(2),
3598 Value::Int(3),
3599 Value::Int(4),
3600 ]);
3601 let arr2 = Value::Array(vec![
3602 Value::Int(2),
3603 Value::Int(4),
3604 Value::Int(6),
3605 Value::Int(8),
3606 ]);
3607 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3608 assert_eq!(result, Value::Float(1.0));
3609
3610 let arr1 = Value::Array(vec![
3612 Value::Int(1),
3613 Value::Int(2),
3614 Value::Int(3),
3615 Value::Int(4),
3616 ]);
3617 let arr2 = Value::Array(vec![
3618 Value::Int(8),
3619 Value::Int(6),
3620 Value::Int(4),
3621 Value::Int(2),
3622 ]);
3623 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3624 assert_eq!(result, Value::Float(-1.0));
3625
3626 let arr1 = Value::Array(vec![
3628 Value::Int(1),
3629 Value::Int(1),
3630 Value::Int(1),
3631 Value::Int(1),
3632 ]);
3633 let arr2 = Value::Array(vec![
3634 Value::Int(1),
3635 Value::Int(2),
3636 Value::Int(3),
3637 Value::Int(4),
3638 ]);
3639 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3640 assert_eq!(result, Value::Float(0.0));
3641
3642 let arr1 = Value::Array(vec![
3644 Value::Float(1.0),
3645 Value::Float(2.0),
3646 Value::Float(3.0),
3647 ]);
3648 let arr2 = Value::Array(vec![
3649 Value::Float(1.0),
3650 Value::Float(2.0),
3651 Value::Float(3.0),
3652 ]);
3653 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3654 assert_eq!(result, Value::Float(1.0));
3655 }
3656
3657 #[test]
3658 fn test_builtin_correl_series() {
3659 let registry = BuiltinRegistry::new();
3660
3661 let series1 = Value::Series(Series::new(PlSmallStr::from("a"), &[1, 2, 3, 4]));
3663 let series2 = Value::Series(Series::new(PlSmallStr::from("b"), &[2, 4, 6, 8]));
3664 let result = registry
3665 .call_function("correl", &[series1, series2])
3666 .unwrap();
3667 assert_eq!(result, Value::Null);
3668 }
3669
3670 #[test]
3671 fn test_builtin_correl_errors() {
3672 let registry = BuiltinRegistry::new();
3673
3674 let result = registry.call_function("correl", &[]);
3676 assert!(result.is_err());
3677 assert!(result
3678 .unwrap_err()
3679 .to_string()
3680 .contains("expects 2 arguments"));
3681
3682 let arr = Value::Array(vec![Value::Int(1), Value::Int(2)]);
3684 let result = registry.call_function("correl", &[arr]);
3685 assert!(result.is_err());
3686 assert!(result
3687 .unwrap_err()
3688 .to_string()
3689 .contains("expects 2 arguments"));
3690
3691 let arr = Value::Array(vec![Value::Int(1), Value::Int(2)]);
3693 let result = registry.call_function("correl", &[arr.clone(), arr.clone(), arr]);
3694 assert!(result.is_err());
3695 assert!(result
3696 .unwrap_err()
3697 .to_string()
3698 .contains("expects 2 arguments"));
3699
3700 let arr1 = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
3702 let arr2 = Value::Array(vec![Value::Int(1), Value::Int(2)]);
3703 let result = registry.call_function("correl", &[arr1, arr2]);
3704 assert!(result.is_err());
3705 assert!(result
3706 .unwrap_err()
3707 .to_string()
3708 .contains("requires two arrays or two series"));
3709
3710 let str1 = Value::String("hello".to_string());
3712 let str2 = Value::String("world".to_string());
3713 let result = registry.call_function("correl", &[str1, str2]);
3714 assert!(result.is_err());
3715 assert!(result
3716 .unwrap_err()
3717 .to_string()
3718 .contains("requires two arrays or two series"));
3719 }
3720
3721 #[test]
3722 fn test_builtin_correl_edge_cases() {
3723 let registry = BuiltinRegistry::new();
3724
3725 let arr1 = Value::Array(vec![]);
3727 let arr2 = Value::Array(vec![]);
3728 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3729 assert_eq!(result, Value::Null);
3730
3731 let arr1 = Value::Array(vec![Value::Int(1)]);
3733 let arr2 = Value::Array(vec![Value::Int(2)]);
3734 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3735 assert_eq!(result, Value::Null);
3736
3737 let arr1 = Value::Array(vec![Value::Int(1), Value::Null, Value::Int(3)]);
3739 let arr2 = Value::Array(vec![Value::Int(2), Value::Null, Value::Int(6)]);
3740 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3741 assert_eq!(result, Value::Float(1.0)); let arr1 = Value::Array(vec![
3745 Value::Int(1),
3746 Value::String("ignore".to_string()),
3747 Value::Int(3),
3748 ]);
3749 let arr2 = Value::Array(vec![
3750 Value::Int(2),
3751 Value::String("ignore".to_string()),
3752 Value::Int(6),
3753 ]);
3754 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3755 assert_eq!(result, Value::Float(1.0));
3756
3757 let arr1 = Value::Array(vec![Value::Int(5), Value::Int(5), Value::Int(5)]);
3759 let arr2 = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
3760 let result = registry.call_function("correl", &[arr1, arr2]).unwrap();
3761 assert_eq!(result, Value::Float(0.0));
3762 }
3763
3764 #[test]
3765 fn test_url_set_domain_without_www() {
3766 let registry = BuiltinRegistry::new();
3767
3768 let url_with_www = Value::String("https://www.example.com/path".to_string());
3770 let result = registry
3771 .call_function("url_set_domain_without_www", &[url_with_www])
3772 .unwrap();
3773 assert_eq!(
3774 result,
3775 Value::String("https://example.com/path".to_string())
3776 );
3777
3778 let url_without_www = Value::String("https://example.com/path".to_string());
3780 let result = registry
3781 .call_function("url_set_domain_without_www", &[url_without_www])
3782 .unwrap();
3783 assert_eq!(
3784 result,
3785 Value::String("https://example.com/path".to_string())
3786 );
3787
3788 let subdomain = Value::String("https://www.sub.example.com/path".to_string());
3790 let result = registry
3791 .call_function("url_set_domain_without_www", &[subdomain])
3792 .unwrap();
3793 assert_eq!(
3794 result,
3795 Value::String("https://sub.example.com/path".to_string())
3796 );
3797
3798 let no_path = Value::String("https://www.example.com".to_string());
3800 let result = registry
3801 .call_function("url_set_domain_without_www", &[no_path])
3802 .unwrap();
3803 assert_eq!(result, Value::String("https://example.com/".to_string()));
3804
3805 let invalid_url = Value::String("not-a-url".to_string());
3807 let result = registry
3808 .call_function("url_set_domain_without_www", &[invalid_url])
3809 .unwrap();
3810 assert_eq!(result, Value::String("not-a-url".to_string()));
3811
3812 let urls = Value::Array(vec![
3814 Value::String("https://www.example.com".to_string()),
3815 Value::String("https://test.com".to_string()),
3816 ]);
3817 let result = registry
3818 .call_function("url_set_domain_without_www", &[urls])
3819 .unwrap();
3820 assert_eq!(
3821 result,
3822 Value::Array(vec![
3823 Value::String("https://example.com/".to_string()),
3824 Value::String("https://test.com/".to_string()),
3825 ])
3826 );
3827 }
3828
3829 #[test]
3830 fn test_transform_values_registered() {
3831 let registry = BuiltinRegistry::new();
3832 assert!(registry.has_function("transform_values"));
3833 let names = registry.function_names();
3834 assert!(names.contains(&"transform_values".to_string()));
3835 }
3836
3837 #[test]
3838 fn test_least_frequent() {
3839 let registry = BuiltinRegistry::new();
3840
3841 let arr = Value::Array(vec![
3843 Value::String("a".to_string()),
3844 Value::String("b".to_string()),
3845 Value::String("a".to_string()),
3846 Value::String("c".to_string()),
3847 Value::String("b".to_string()),
3848 Value::String("a".to_string()),
3849 ]);
3850 let result = registry.call_function("least_frequent", &[arr]).unwrap();
3851 assert_eq!(result, Value::String("c".to_string())); let arr = Value::Array(vec![
3855 Value::Int(1),
3856 Value::Int(2),
3857 Value::Int(1),
3858 Value::Int(3),
3859 Value::Int(2),
3860 Value::Int(1),
3861 ]);
3862 let result = registry.call_function("least_frequent", &[arr]).unwrap();
3863 assert_eq!(result, Value::Int(3)); let arr = Value::Array(vec![]);
3867 let result = registry.call_function("least_frequent", &[arr]).unwrap();
3868 assert_eq!(result, Value::Null);
3869
3870 let arr = Value::Array(vec![Value::String("single".to_string())]);
3872 let result = registry.call_function("least_frequent", &[arr]).unwrap();
3873 assert_eq!(result, Value::String("single".to_string()));
3874
3875 let arr = Value::Array(vec![
3877 Value::String("x".to_string()),
3878 Value::String("y".to_string()),
3879 Value::String("z".to_string()),
3880 ]);
3881 let result = registry.call_function("least_frequent", &[arr]).unwrap();
3882 match result {
3884 Value::String(s) if s == "x" || s == "y" || s == "z" => {}
3885 _ => panic!("Expected one of x, y, z"),
3886 }
3887
3888 let names = Series::new(
3890 PlSmallStr::from("name"),
3891 &["Alice", "Bob", "Alice", "Charlie"],
3892 );
3893 let ages = Series::new(PlSmallStr::from("age"), &[25, 30, 25, 35]);
3894 let df = DataFrame::new(vec![names.into(), ages.into()]).unwrap();
3895 let df_val = Value::DataFrame(df);
3896 let result = registry.call_function("least_frequent", &[df_val]).unwrap();
3897 assert_eq!(result, Value::String("Charlie".to_string()));
3899
3900 let series = Series::new(PlSmallStr::from("values"), &[1, 2, 1, 3, 2, 1]);
3902 let series_val = Value::Series(series);
3903 let result = registry
3904 .call_function("least_frequent", &[series_val])
3905 .unwrap();
3906 assert_eq!(result, Value::Int(3));
3907
3908 let result = registry.call_function("least_frequent", &[]);
3910 assert!(result.is_err());
3911
3912 let result =
3913 registry.call_function("least_frequent", &[Value::String("not array".to_string())]);
3914 assert!(result.is_err());
3915 }
3916
3917 #[test]
3918 fn test_transpose_registered() {
3919 let registry = BuiltinRegistry::new();
3920 assert!(registry.has_function("transpose"));
3921 }
3922
3923 #[test]
3924 fn test_iferror_via_registry() {
3925 let registry = BuiltinRegistry::new();
3926
3927 assert!(registry.has_function("iferror"));
3929
3930 let result = registry
3932 .call_function(
3933 "iferror",
3934 &[Value::Null, Value::String("default".to_string())],
3935 )
3936 .unwrap();
3937 assert_eq!(result, Value::String("default".to_string()));
3938
3939 let result = registry
3941 .call_function(
3942 "iferror",
3943 &[Value::Int(42), Value::String("default".to_string())],
3944 )
3945 .unwrap();
3946 assert_eq!(result, Value::Int(42));
3947
3948 let result = registry.call_function("iferror", &[Value::Null]);
3950 assert!(result.is_err());
3951 assert!(result
3952 .unwrap_err()
3953 .to_string()
3954 .contains("iferror() expects 2 arguments"));
3955 }
3956
3957 #[test]
3958 fn test_truncate_date_function() {
3959 let registry = BuiltinRegistry::new();
3960
3961 let result = registry
3963 .call_function(
3964 "truncate_date",
3965 &[
3966 Value::String("2021-06-15T14:30:45Z".to_string()),
3967 Value::String("year".to_string()),
3968 ],
3969 )
3970 .unwrap();
3971 assert_eq!(result, Value::Int(1609459200));
3973
3974 let result = registry
3976 .call_function(
3977 "truncate_date",
3978 &[
3979 Value::String("2021-06-15T14:30:45Z".to_string()),
3980 Value::String("month".to_string()),
3981 ],
3982 )
3983 .unwrap();
3984 assert_eq!(result, Value::Int(1622505600));
3986
3987 let result = registry
3989 .call_function(
3990 "truncate_date",
3991 &[
3992 Value::String("2021-06-15T14:30:45Z".to_string()),
3993 Value::String("day".to_string()),
3994 ],
3995 )
3996 .unwrap();
3997 assert_eq!(result, Value::Int(1623715200));
3999
4000 let result = registry
4002 .call_function(
4003 "truncate_date",
4004 &[
4005 Value::String("2021-06-15T14:30:45Z".to_string()),
4006 Value::String("hour".to_string()),
4007 ],
4008 )
4009 .unwrap();
4010 assert_eq!(result, Value::Int(1623765600));
4012
4013 let result = registry
4015 .call_function(
4016 "truncate_date",
4017 &[
4018 Value::String("2021-06-15T14:30:45Z".to_string()),
4019 Value::String("minute".to_string()),
4020 ],
4021 )
4022 .unwrap();
4023 assert_eq!(result, Value::Int(1623767400));
4025
4026 let result = registry
4028 .call_function(
4029 "truncate_date",
4030 &[Value::Int(1623767400), Value::String("day".to_string())],
4031 )
4032 .unwrap();
4033 assert_eq!(result, Value::Int(1623715200));
4034
4035 let result = registry.call_function(
4037 "truncate_date",
4038 &[
4039 Value::String("2021-06-15T14:30:45Z".to_string()),
4040 Value::String("invalid".to_string()),
4041 ],
4042 );
4043 assert!(result.is_err());
4044 assert!(result
4045 .unwrap_err()
4046 .to_string()
4047 .contains("truncate_date() invalid unit"));
4048
4049 let result = registry.call_function(
4051 "truncate_date",
4052 &[Value::String("2021-06-15T14:30:45Z".to_string())],
4053 );
4054 assert!(result.is_err());
4055 assert!(result
4056 .unwrap_err()
4057 .to_string()
4058 .contains("truncate_date() expects 2 arguments"));
4059
4060 let result = registry.call_function(
4062 "truncate_date",
4063 &[
4064 Value::String("invalid-date".to_string()),
4065 Value::String("day".to_string()),
4066 ],
4067 );
4068 assert!(result.is_err());
4069 }
4070
4071 #[test]
4072 fn test_url_strip_port_if_default() {
4073 let registry = BuiltinRegistry::new();
4074
4075 let result = registry
4077 .call_function(
4078 "url_strip_port_if_default",
4079 &[Value::String("http://example.com:80/path".to_string())],
4080 )
4081 .unwrap();
4082 assert_eq!(result, Value::String("http://example.com/path".to_string()));
4083
4084 let result = registry
4086 .call_function(
4087 "url_strip_port_if_default",
4088 &[Value::String("https://example.com:443/path".to_string())],
4089 )
4090 .unwrap();
4091 assert_eq!(
4092 result,
4093 Value::String("https://example.com/path".to_string())
4094 );
4095
4096 let result = registry
4098 .call_function(
4099 "url_strip_port_if_default",
4100 &[Value::String("ftp://example.com:21/path".to_string())],
4101 )
4102 .unwrap();
4103 assert_eq!(result, Value::String("ftp://example.com/path".to_string()));
4104
4105 let result = registry
4107 .call_function(
4108 "url_strip_port_if_default",
4109 &[Value::String("ssh://example.com:22/path".to_string())],
4110 )
4111 .unwrap();
4112 assert_eq!(result, Value::String("ssh://example.com/path".to_string()));
4113
4114 let result = registry
4116 .call_function(
4117 "url_strip_port_if_default",
4118 &[Value::String("telnet://example.com:23/".to_string())],
4119 )
4120 .unwrap();
4121 assert_eq!(result, Value::String("telnet://example.com/".to_string()));
4122
4123 let result = registry
4125 .call_function(
4126 "url_strip_port_if_default",
4127 &[Value::String("http://example.com:8080/path".to_string())],
4128 )
4129 .unwrap();
4130 assert_eq!(
4131 result,
4132 Value::String("http://example.com:8080/path".to_string())
4133 );
4134
4135 let result = registry
4137 .call_function(
4138 "url_strip_port_if_default",
4139 &[Value::String("https://example.com:8443/path".to_string())],
4140 )
4141 .unwrap();
4142 assert_eq!(
4143 result,
4144 Value::String("https://example.com:8443/path".to_string())
4145 );
4146
4147 let result = registry
4149 .call_function(
4150 "url_strip_port_if_default",
4151 &[Value::String("http://example.com/path".to_string())],
4152 )
4153 .unwrap();
4154 assert_eq!(result, Value::String("http://example.com/path".to_string()));
4155
4156 let result = registry
4158 .call_function(
4159 "url_strip_port_if_default",
4160 &[Value::String("not-a-url".to_string())],
4161 )
4162 .unwrap();
4163 assert_eq!(result, Value::String("not-a-url".to_string()));
4164
4165 let urls = vec![
4167 Value::String("http://example.com:80/".to_string()),
4168 Value::String("https://example.com:443/".to_string()),
4169 Value::String("http://example.com:8080/".to_string()),
4170 ];
4171 let result = registry
4172 .call_function("url_strip_port_if_default", &[Value::Array(urls)])
4173 .unwrap();
4174 match result {
4175 Value::Array(arr) => {
4176 assert_eq!(arr.len(), 3);
4177 assert_eq!(arr[0], Value::String("http://example.com/".to_string()));
4178 assert_eq!(arr[1], Value::String("https://example.com/".to_string()));
4179 assert_eq!(
4180 arr[2],
4181 Value::String("http://example.com:8080/".to_string())
4182 );
4183 }
4184 _ => panic!("Expected Array"),
4185 }
4186
4187 let result = registry.call_function("url_strip_port_if_default", &[Value::Int(42)]);
4189 assert!(result.is_err());
4190 assert!(result
4191 .unwrap_err()
4192 .to_string()
4193 .contains("url_strip_port_if_default() requires string, array, DataFrame, or Series"));
4194
4195 let result = registry.call_function("url_strip_port_if_default", &[]);
4197 assert!(result.is_err());
4198 assert!(result
4199 .unwrap_err()
4200 .to_string()
4201 .contains("url_strip_port_if_default() expects 1 argument"));
4202
4203 let result = registry.call_function(
4204 "url_strip_port_if_default",
4205 &[
4206 Value::String("test".to_string()),
4207 Value::String("extra".to_string()),
4208 ],
4209 );
4210 assert!(result.is_err());
4211 assert!(result
4212 .unwrap_err()
4213 .to_string()
4214 .contains("url_strip_port_if_default() expects 1 argument"));
4215 }
4216
4217 #[test]
4218 fn test_url_strip_port() {
4219 let registry = BuiltinRegistry::new();
4220
4221 let result = registry
4223 .call_function(
4224 "url_strip_port",
4225 &[Value::String("http://example.com:8080/path".to_string())],
4226 )
4227 .unwrap();
4228 assert_eq!(result, Value::String("http://example.com/path".to_string()));
4229
4230 let result = registry
4232 .call_function(
4233 "url_strip_port",
4234 &[Value::String("https://example.com:8443/path".to_string())],
4235 )
4236 .unwrap();
4237 assert_eq!(
4238 result,
4239 Value::String("https://example.com/path".to_string())
4240 );
4241
4242 let result = registry
4244 .call_function(
4245 "url_strip_port",
4246 &[Value::String("http://example.com/path".to_string())],
4247 )
4248 .unwrap();
4249 assert_eq!(result, Value::String("http://example.com/path".to_string()));
4250
4251 let result = registry
4253 .call_function("url_strip_port", &[Value::String("not-a-url".to_string())])
4254 .unwrap();
4255 assert_eq!(result, Value::String("not-a-url".to_string()));
4256
4257 let urls = vec![
4259 Value::String("http://example.com:8080/".to_string()),
4260 Value::String("https://example.com:8443/".to_string()),
4261 Value::String("http://example.com/".to_string()),
4262 ];
4263 let result = registry
4264 .call_function("url_strip_port", &[Value::Array(urls)])
4265 .unwrap();
4266 match result {
4267 Value::Array(arr) => {
4268 assert_eq!(arr.len(), 3);
4269 assert_eq!(arr[0], Value::String("http://example.com/".to_string()));
4270 assert_eq!(arr[1], Value::String("https://example.com/".to_string()));
4271 assert_eq!(arr[2], Value::String("http://example.com/".to_string()));
4272 }
4273 _ => panic!("Expected Array"),
4274 }
4275
4276 let result = registry.call_function("url_strip_port", &[Value::Int(42)]);
4278 assert!(result.is_err());
4279 assert!(result
4280 .unwrap_err()
4281 .to_string()
4282 .contains("url_strip_port() requires string, array, DataFrame, or Series"));
4283
4284 let result = registry.call_function("url_strip_port", &[]);
4286 assert!(result.is_err());
4287 assert!(result
4288 .unwrap_err()
4289 .to_string()
4290 .contains("url_strip_port() expects 1 argument"));
4291
4292 let result = registry.call_function(
4293 "url_strip_port",
4294 &[
4295 Value::String("test".to_string()),
4296 Value::String("extra".to_string()),
4297 ],
4298 );
4299 assert!(result.is_err());
4300 assert!(result
4301 .unwrap_err()
4302 .to_string()
4303 .contains("url_strip_port() expects 1 argument"));
4304 }
4305
4306 #[test]
4307 fn test_url_set_port() {
4308 let registry = BuiltinRegistry::new();
4309
4310 let result = registry
4312 .call_function(
4313 "url_set_port",
4314 &[
4315 Value::String("http://example.com/path".to_string()),
4316 Value::Int(8080),
4317 ],
4318 )
4319 .unwrap();
4320 assert_eq!(
4321 result,
4322 Value::String("http://example.com:8080/path".to_string())
4323 );
4324
4325 let result = registry
4327 .call_function(
4328 "url_set_port",
4329 &[
4330 Value::String("http://example.com:80/path".to_string()),
4331 Value::Int(8080),
4332 ],
4333 )
4334 .unwrap();
4335 assert_eq!(
4336 result,
4337 Value::String("http://example.com:8080/path".to_string())
4338 );
4339
4340 let result = registry
4342 .call_function(
4343 "url_set_port",
4344 &[
4345 Value::String("https://example.com/path".to_string()),
4346 Value::String("8443".to_string()),
4347 ],
4348 )
4349 .unwrap();
4350 assert_eq!(
4351 result,
4352 Value::String("https://example.com:8443/path".to_string())
4353 );
4354
4355 let result = registry
4357 .call_function(
4358 "url_set_port",
4359 &[
4360 Value::String("http://example.com/path".to_string()),
4361 Value::Int(0),
4362 ],
4363 )
4364 .unwrap();
4365 assert_eq!(
4366 result,
4367 Value::String("http://example.com:0/path".to_string())
4368 );
4369
4370 let result = registry
4372 .call_function(
4373 "url_set_port",
4374 &[
4375 Value::String("http://example.com/path".to_string()),
4376 Value::Int(65535),
4377 ],
4378 )
4379 .unwrap();
4380 assert_eq!(
4381 result,
4382 Value::String("http://example.com:65535/path".to_string())
4383 );
4384
4385 let result = registry
4387 .call_function(
4388 "url_set_port",
4389 &[Value::String("not-a-url".to_string()), Value::Int(8080)],
4390 )
4391 .unwrap();
4392 assert_eq!(result, Value::String("not-a-url".to_string()));
4393
4394 let urls = Value::Array(vec![
4396 Value::String("http://example.com/".to_string()),
4397 Value::String("https://test.com/path".to_string()),
4398 ]);
4399 let result = registry
4400 .call_function("url_set_port", &[urls, Value::Int(9000)])
4401 .unwrap();
4402 match result {
4403 Value::Array(arr) => {
4404 assert_eq!(arr.len(), 2);
4405 assert_eq!(
4406 arr[0],
4407 Value::String("http://example.com:9000/".to_string())
4408 );
4409 assert_eq!(
4410 arr[1],
4411 Value::String("https://test.com:9000/path".to_string())
4412 );
4413 }
4414 _ => panic!("Expected Array"),
4415 }
4416
4417 let result = registry.call_function(
4419 "url_set_port",
4420 &[
4421 Value::String("http://example.com/".to_string()),
4422 Value::String("invalid".to_string()),
4423 ],
4424 );
4425 assert!(result.is_err());
4426 assert!(result
4427 .unwrap_err()
4428 .to_string()
4429 .contains("Invalid port number"));
4430
4431 let result = registry.call_function(
4433 "url_set_port",
4434 &[
4435 Value::String("http://example.com/".to_string()),
4436 Value::Float(8080.0),
4437 ],
4438 );
4439 assert!(result.is_err());
4440 assert!(result
4441 .unwrap_err()
4442 .to_string()
4443 .contains("url_set_port() second argument must be an integer or string"));
4444
4445 let result = registry.call_function("url_set_port", &[]);
4447 assert!(result.is_err());
4448 assert!(result
4449 .unwrap_err()
4450 .to_string()
4451 .contains("url_set_port() expects 2 arguments"));
4452
4453 let result = registry.call_function(
4455 "url_set_port",
4456 &[Value::String("http://example.com/".to_string())],
4457 );
4458 assert!(result.is_err());
4459 assert!(result
4460 .unwrap_err()
4461 .to_string()
4462 .contains("url_set_port() expects 2 arguments"));
4463
4464 let result = registry.call_function(
4466 "url_set_port",
4467 &[
4468 Value::String("http://example.com/".to_string()),
4469 Value::Int(8080),
4470 Value::Int(1),
4471 ],
4472 );
4473 assert!(result.is_err());
4474 assert!(result
4475 .unwrap_err()
4476 .to_string()
4477 .contains("url_set_port() expects 2 arguments"));
4478
4479 let df = DataFrame::new(vec![Column::new(
4481 PlSmallStr::from("urls"),
4482 &["http://example.com/", "https://test.com/path"],
4483 )])
4484 .unwrap();
4485 let result = registry
4486 .call_function("url_set_port", &[Value::DataFrame(df), Value::Int(9000)])
4487 .unwrap();
4488 match result {
4489 Value::DataFrame(result_df) => {
4490 let urls_col = result_df.column("urls").unwrap().str().unwrap();
4491 assert_eq!(urls_col.get(0).unwrap(), "http://example.com:9000/");
4492 assert_eq!(urls_col.get(1).unwrap(), "https://test.com:9000/path");
4493 }
4494 _ => panic!("Expected DataFrame"),
4495 }
4496
4497 let series = Series::new(
4499 "urls".into(),
4500 &["http://example.com/", "https://test.com/path"],
4501 );
4502 let result = registry
4503 .call_function("url_set_port", &[Value::Series(series), Value::Int(9000)])
4504 .unwrap();
4505 match result {
4506 Value::Series(result_series) => {
4507 let urls_col = result_series.str().unwrap();
4508 assert_eq!(urls_col.get(0).unwrap(), "http://example.com:9000/");
4509 assert_eq!(urls_col.get(1).unwrap(), "https://test.com:9000/path");
4510 }
4511 _ => panic!("Expected Series"),
4512 }
4513
4514 let result = registry.call_function("url_set_port", &[Value::Int(42), Value::Int(8080)]);
4516 assert!(result.is_err());
4517 assert!(result
4518 .unwrap_err()
4519 .to_string()
4520 .contains("url_set_port() requires string, array, DataFrame, or Series"));
4521 }
4522
4523 #[test]
4524 fn test_time_series_range_function() {
4525 let registry = BuiltinRegistry::new();
4526
4527 let start = Value::Int(1609459200); let end = Value::Int(1609459260); let interval = Value::String("10s".to_string());
4531 let result = registry
4532 .call_function("time_series_range", &[start.clone(), end, interval])
4533 .unwrap();
4534 if let Value::Array(arr) = result {
4535 assert_eq!(arr.len(), 7); assert_eq!(arr[0], Value::Int(1609459200));
4537 assert_eq!(arr[6], Value::Int(1609459260));
4538 } else {
4539 panic!("Expected array result");
4540 }
4541
4542 let start = Value::Int(1609459200);
4544 let end = Value::Int(1609462800); let interval = Value::String("15m".to_string());
4546 let result = registry
4547 .call_function("time_series_range", &[start, end, interval])
4548 .unwrap();
4549 if let Value::Array(arr) = result {
4550 assert_eq!(arr.len(), 5); } else {
4552 panic!("Expected array result");
4553 }
4554
4555 let start = Value::Int(1609459260);
4557 let end = Value::Int(1609459200);
4558 let interval = Value::String("10s".to_string());
4559 let result = registry
4560 .call_function("time_series_range", &[start, end, interval])
4561 .unwrap();
4562 if let Value::Array(arr) = result {
4563 assert_eq!(arr.len(), 0);
4564 } else {
4565 panic!("Expected array result");
4566 }
4567
4568 let start = Value::String("2021-01-01T00:00:00Z".to_string());
4570 let end = Value::String("2021-01-01T00:00:30Z".to_string());
4571 let interval = Value::String("10s".to_string());
4572 let result = registry
4573 .call_function("time_series_range", &[start, end, interval])
4574 .unwrap();
4575 if let Value::Array(arr) = result {
4576 assert_eq!(arr.len(), 4); } else {
4578 panic!("Expected array result");
4579 }
4580
4581 let start = Value::Int(1609459200);
4583 let end = Value::Int(1609459260);
4584 let interval = Value::String("10x".to_string());
4585 let result = registry.call_function("time_series_range", &[start.clone(), end, interval]);
4586 assert!(result.is_err());
4587
4588 let result = registry.call_function("time_series_range", &[start]);
4590 assert!(result.is_err());
4591 }
4592
4593 #[test]
4594 fn test_map_registered_via_inventory() {
4595 let registry = BuiltinRegistry::new();
4596 assert!(registry.has_function("map"));
4597 let function_names = registry.function_names();
4598 assert!(function_names.contains(&"map".to_string()));
4599 }
4600}