1use std::sync::LazyLock;
19
20use datafusion_common::{exec_err, Result, ScalarValue};
21use datafusion_doc::scalar_doc_sections::DOC_SECTION_MATH;
22use datafusion_expr::interval_arithmetic::Interval;
23use datafusion_expr::sort_properties::{ExprProperties, SortProperties};
24use datafusion_expr::Documentation;
25
26pub fn acos_order(input: &[ExprProperties]) -> Result<SortProperties> {
28 let arg = &input[0];
29 let range = &arg.range;
30
31 let valid_domain =
32 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
33
34 if valid_domain.contains(range)? == Interval::CERTAINLY_TRUE {
35 Ok(-arg.sort_properties)
36 } else {
37 exec_err!("Input range of ACOS contains out-of-domain values")
38 }
39}
40
41static DOCUMENTATION_ACOS: LazyLock<Documentation> = LazyLock::new(|| {
42 Documentation::builder(
43 DOC_SECTION_MATH,
44 "Returns the arc cosine or inverse cosine of a number.",
45 "acos(numeric_expression)",
46 )
47 .with_standard_argument("numeric_expression", Some("Numeric"))
48 .with_sql_example(
49 r#"```sql
50> SELECT acos(1);
51+----------+
52| acos(1) |
53+----------+
54| 0.0 |
55+----------+
56```"#,
57 )
58 .build()
59});
60
61pub fn get_acos_doc() -> &'static Documentation {
62 &DOCUMENTATION_ACOS
63}
64
65pub fn acosh_order(input: &[ExprProperties]) -> Result<SortProperties> {
67 let arg = &input[0];
68 let range = &arg.range;
69
70 let valid_domain = Interval::try_new(
71 ScalarValue::new_one(&range.lower().data_type())?,
72 ScalarValue::try_from(&range.upper().data_type())?,
73 )?;
74
75 if valid_domain.contains(range)? == Interval::CERTAINLY_TRUE {
76 Ok(arg.sort_properties)
77 } else {
78 exec_err!("Input range of ACOSH contains out-of-domain values")
79 }
80}
81
82static DOCUMENTATION_ACOSH: LazyLock<Documentation> =
83 LazyLock::new(|| {
84 Documentation::builder(
85 DOC_SECTION_MATH,
86 "Returns the area hyperbolic cosine or inverse hyperbolic cosine of a number.",
87 "acosh(numeric_expression)",
88 )
89 .with_standard_argument("numeric_expression", Some("Numeric"))
90 .with_sql_example(r#"```sql
91> SELECT acosh(2);
92+------------+
93| acosh(2) |
94+------------+
95| 1.31696 |
96+------------+
97```"#)
98 .build()
99 });
100
101pub fn get_acosh_doc() -> &'static Documentation {
102 &DOCUMENTATION_ACOSH
103}
104
105pub fn asin_order(input: &[ExprProperties]) -> Result<SortProperties> {
107 let arg = &input[0];
108 let range = &arg.range;
109
110 let valid_domain =
111 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
112
113 if valid_domain.contains(range)? == Interval::CERTAINLY_TRUE {
114 Ok(arg.sort_properties)
115 } else {
116 exec_err!("Input range of ASIN contains out-of-domain values")
117 }
118}
119
120static DOCUMENTATION_ASIN: LazyLock<Documentation> = LazyLock::new(|| {
121 Documentation::builder(
122 DOC_SECTION_MATH,
123 "Returns the arc sine or inverse sine of a number.",
124 "asin(numeric_expression)",
125 )
126 .with_standard_argument("numeric_expression", Some("Numeric"))
127 .with_sql_example(
128 r#"```sql
129> SELECT asin(0.5);
130+------------+
131| asin(0.5) |
132+------------+
133| 0.5235988 |
134+------------+
135```"#,
136 )
137 .build()
138});
139
140pub fn get_asin_doc() -> &'static Documentation {
141 &DOCUMENTATION_ASIN
142}
143
144pub fn asinh_order(input: &[ExprProperties]) -> Result<SortProperties> {
146 Ok(input[0].sort_properties)
147}
148
149static DOCUMENTATION_ASINH: LazyLock<Documentation> = LazyLock::new(|| {
150 Documentation::builder(
151 DOC_SECTION_MATH,
152 "Returns the area hyperbolic sine or inverse hyperbolic sine of a number.",
153 "asinh(numeric_expression)",
154 )
155 .with_standard_argument("numeric_expression", Some("Numeric"))
156 .with_sql_example(
157 r#" ```sql
158> SELECT asinh(1);
159+------------+
160| asinh(1) |
161+------------+
162| 0.8813736 |
163+------------+
164```"#,
165 )
166 .build()
167});
168
169pub fn get_asinh_doc() -> &'static Documentation {
170 &DOCUMENTATION_ASINH
171}
172
173pub fn atan_order(input: &[ExprProperties]) -> Result<SortProperties> {
175 Ok(input[0].sort_properties)
176}
177
178static DOCUMENTATION_ATAN: LazyLock<Documentation> = LazyLock::new(|| {
179 Documentation::builder(
180 DOC_SECTION_MATH,
181 "Returns the arc tangent or inverse tangent of a number.",
182 "atan(numeric_expression)",
183 )
184 .with_standard_argument("numeric_expression", Some("Numeric"))
185 .with_sql_example(
186 r#"```sql
187 > SELECT atan(1);
188+-----------+
189| atan(1) |
190+-----------+
191| 0.7853982 |
192+-----------+
193```"#,
194 )
195 .build()
196});
197
198pub fn get_atan_doc() -> &'static Documentation {
199 &DOCUMENTATION_ATAN
200}
201
202pub fn atanh_order(input: &[ExprProperties]) -> Result<SortProperties> {
204 let arg = &input[0];
205 let range = &arg.range;
206
207 let valid_domain =
208 Interval::make_symmetric_unit_interval(&range.lower().data_type())?;
209
210 if valid_domain.contains(range)? == Interval::CERTAINLY_TRUE {
211 Ok(arg.sort_properties)
212 } else {
213 exec_err!("Input range of ATANH contains out-of-domain values")
214 }
215}
216
217static DOCUMENTATION_ATANH: LazyLock<Documentation> =
218 LazyLock::new(|| {
219 Documentation::builder(
220 DOC_SECTION_MATH,
221 "Returns the area hyperbolic tangent or inverse hyperbolic tangent of a number.",
222 "atanh(numeric_expression)",
223 )
224 .with_standard_argument("numeric_expression", Some("Numeric"))
225 .with_sql_example(r#"```sql
226 > SELECT atanh(0.5);
227+-------------+
228| atanh(0.5) |
229+-------------+
230| 0.5493061 |
231+-------------+
232```"#)
233 .build()
234 });
235
236pub fn get_atanh_doc() -> &'static Documentation {
237 &DOCUMENTATION_ATANH
238}
239
240pub fn atan2_order(_input: &[ExprProperties]) -> Result<SortProperties> {
243 Ok(SortProperties::Unordered)
244}
245
246static DOCUMENTATION_ATANH2: LazyLock<Documentation> =
247 LazyLock::new(|| {
248 Documentation::builder(
249 DOC_SECTION_MATH,
250 "Returns the arc tangent or inverse tangent of `expression_y / expression_x`.",
251 "atan2(expression_y, expression_x)",
252 )
253 .with_argument(
254 "expression_y",
255 r#"First numeric expression to operate on.
256Can be a constant, column, or function, and any combination of arithmetic operators."#,
257 )
258 .with_argument(
259 "expression_x",
260 r#"Second numeric expression to operate on.
261Can be a constant, column, or function, and any combination of arithmetic operators."#,
262 )
263 .with_sql_example(r#"```sql
264> SELECT atan2(1, 1);
265+------------+
266| atan2(1,1) |
267+------------+
268| 0.7853982 |
269+------------+
270```"#)
271 .build()
272 });
273
274pub fn get_atan2_doc() -> &'static Documentation {
275 &DOCUMENTATION_ATANH2
276}
277
278pub fn cbrt_order(input: &[ExprProperties]) -> Result<SortProperties> {
280 Ok(input[0].sort_properties)
281}
282
283static DOCUMENTATION_CBRT: LazyLock<Documentation> = LazyLock::new(|| {
284 Documentation::builder(
285 DOC_SECTION_MATH,
286 "Returns the cube root of a number.",
287 "cbrt(numeric_expression)",
288 )
289 .with_standard_argument("numeric_expression", Some("Numeric"))
290 .with_sql_example(
291 r#"```sql
292> SELECT cbrt(27);
293+-----------+
294| cbrt(27) |
295+-----------+
296| 3.0 |
297+-----------+
298```"#,
299 )
300 .build()
301});
302
303pub fn get_cbrt_doc() -> &'static Documentation {
304 &DOCUMENTATION_CBRT
305}
306
307pub fn ceil_order(input: &[ExprProperties]) -> Result<SortProperties> {
309 Ok(input[0].sort_properties)
310}
311
312static DOCUMENTATION_CEIL: LazyLock<Documentation> = LazyLock::new(|| {
313 Documentation::builder(
314 DOC_SECTION_MATH,
315 "Returns the nearest integer greater than or equal to a number.",
316 "ceil(numeric_expression)",
317 )
318 .with_standard_argument("numeric_expression", Some("Numeric"))
319 .with_sql_example(
320 r#"```sql
321 > SELECT ceil(3.14);
322+------------+
323| ceil(3.14) |
324+------------+
325| 4.0 |
326+------------+
327```"#,
328 )
329 .build()
330});
331
332pub fn get_ceil_doc() -> &'static Documentation {
333 &DOCUMENTATION_CEIL
334}
335
336pub fn cos_order(_input: &[ExprProperties]) -> Result<SortProperties> {
340 Ok(SortProperties::Unordered)
341}
342
343static DOCUMENTATION_COS: LazyLock<Documentation> = LazyLock::new(|| {
344 Documentation::builder(
345 DOC_SECTION_MATH,
346 "Returns the cosine of a number.",
347 "cos(numeric_expression)",
348 )
349 .with_standard_argument("numeric_expression", Some("Numeric"))
350 .with_sql_example(
351 r#"```sql
352> SELECT cos(0);
353+--------+
354| cos(0) |
355+--------+
356| 1.0 |
357+--------+
358```"#,
359 )
360 .build()
361});
362
363pub fn get_cos_doc() -> &'static Documentation {
364 &DOCUMENTATION_COS
365}
366
367pub fn cosh_order(input: &[ExprProperties]) -> Result<SortProperties> {
369 let arg = &input[0];
370 let range = &arg.range;
371
372 let zero_point = Interval::make_zero(&range.lower().data_type())?;
373
374 if range.gt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
375 Ok(arg.sort_properties)
376 } else if range.lt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
377 Ok(-arg.sort_properties)
378 } else {
379 Ok(SortProperties::Unordered)
380 }
381}
382
383static DOCUMENTATION_COSH: LazyLock<Documentation> = LazyLock::new(|| {
384 Documentation::builder(
385 DOC_SECTION_MATH,
386 "Returns the hyperbolic cosine of a number.",
387 "cosh(numeric_expression)",
388 )
389 .with_standard_argument("numeric_expression", Some("Numeric"))
390 .with_sql_example(
391 r#"```sql
392> SELECT cosh(1);
393+-----------+
394| cosh(1) |
395+-----------+
396| 1.5430806 |
397+-----------+
398```"#,
399 )
400 .build()
401});
402
403pub fn get_cosh_doc() -> &'static Documentation {
404 &DOCUMENTATION_COSH
405}
406
407pub fn degrees_order(input: &[ExprProperties]) -> Result<SortProperties> {
409 Ok(input[0].sort_properties)
410}
411
412static DOCUMENTATION_DEGREES: LazyLock<Documentation> = LazyLock::new(|| {
413 Documentation::builder(
414 DOC_SECTION_MATH,
415 "Converts radians to degrees.",
416 "degrees(numeric_expression)",
417 )
418 .with_standard_argument("numeric_expression", Some("Numeric"))
419 .with_sql_example(
420 r#"```sql
421 > SELECT degrees(pi());
422+------------+
423| degrees(0) |
424+------------+
425| 180.0 |
426+------------+
427```"#,
428 )
429 .build()
430});
431
432pub fn get_degrees_doc() -> &'static Documentation {
433 &DOCUMENTATION_DEGREES
434}
435
436pub fn exp_order(input: &[ExprProperties]) -> Result<SortProperties> {
438 Ok(input[0].sort_properties)
439}
440
441static DOCUMENTATION_EXP: LazyLock<Documentation> = LazyLock::new(|| {
442 Documentation::builder(
443 DOC_SECTION_MATH,
444 "Returns the base-e exponential of a number.",
445 "exp(numeric_expression)",
446 )
447 .with_standard_argument("numeric_expression", Some("Numeric"))
448 .with_sql_example(
449 r#"```sql
450> SELECT exp(1);
451+---------+
452| exp(1) |
453+---------+
454| 2.71828 |
455+---------+
456```"#,
457 )
458 .build()
459});
460
461pub fn get_exp_doc() -> &'static Documentation {
462 &DOCUMENTATION_EXP
463}
464
465pub fn floor_order(input: &[ExprProperties]) -> Result<SortProperties> {
467 Ok(input[0].sort_properties)
468}
469
470static DOCUMENTATION_FLOOR: LazyLock<Documentation> = LazyLock::new(|| {
471 Documentation::builder(
472 DOC_SECTION_MATH,
473 "Returns the nearest integer less than or equal to a number.",
474 "floor(numeric_expression)",
475 )
476 .with_standard_argument("numeric_expression", Some("Numeric"))
477 .with_sql_example(
478 r#"```sql
479> SELECT floor(3.14);
480+-------------+
481| floor(3.14) |
482+-------------+
483| 3.0 |
484+-------------+
485```"#,
486 )
487 .build()
488});
489
490pub fn get_floor_doc() -> &'static Documentation {
491 &DOCUMENTATION_FLOOR
492}
493
494pub fn ln_order(input: &[ExprProperties]) -> Result<SortProperties> {
496 let arg = &input[0];
497 let range = &arg.range;
498
499 let zero_point = Interval::make_zero(&range.lower().data_type())?;
500
501 if range.gt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
502 Ok(arg.sort_properties)
503 } else {
504 exec_err!("Input range of LN contains out-of-domain values")
505 }
506}
507
508static DOCUMENTATION_LN: LazyLock<Documentation> = LazyLock::new(|| {
509 Documentation::builder(
510 DOC_SECTION_MATH,
511 "Returns the natural logarithm of a number.",
512 "ln(numeric_expression)",
513 )
514 .with_standard_argument("numeric_expression", Some("Numeric"))
515 .with_sql_example(
516 r#"```sql
517> SELECT ln(2.71828);
518+-------------+
519| ln(2.71828) |
520+-------------+
521| 1.0 |
522+-------------+
523```"#,
524 )
525 .build()
526});
527
528pub fn get_ln_doc() -> &'static Documentation {
529 &DOCUMENTATION_LN
530}
531
532pub fn log2_order(input: &[ExprProperties]) -> Result<SortProperties> {
534 let arg = &input[0];
535 let range = &arg.range;
536
537 let zero_point = Interval::make_zero(&range.lower().data_type())?;
538
539 if range.gt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
540 Ok(arg.sort_properties)
541 } else {
542 exec_err!("Input range of LOG2 contains out-of-domain values")
543 }
544}
545
546static DOCUMENTATION_LOG2: LazyLock<Documentation> = LazyLock::new(|| {
547 Documentation::builder(
548 DOC_SECTION_MATH,
549 "Returns the base-2 logarithm of a number.",
550 "log2(numeric_expression)",
551 )
552 .with_standard_argument("numeric_expression", Some("Numeric"))
553 .with_sql_example(
554 r#"```sql
555> SELECT log2(8);
556+-----------+
557| log2(8) |
558+-----------+
559| 3.0 |
560+-----------+
561```"#,
562 )
563 .build()
564});
565
566pub fn get_log2_doc() -> &'static Documentation {
567 &DOCUMENTATION_LOG2
568}
569
570pub fn log10_order(input: &[ExprProperties]) -> Result<SortProperties> {
572 let arg = &input[0];
573 let range = &arg.range;
574
575 let zero_point = Interval::make_zero(&range.lower().data_type())?;
576
577 if range.gt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
578 Ok(arg.sort_properties)
579 } else {
580 exec_err!("Input range of LOG10 contains out-of-domain values")
581 }
582}
583
584static DOCUMENTATION_LOG10: LazyLock<Documentation> = LazyLock::new(|| {
585 Documentation::builder(
586 DOC_SECTION_MATH,
587 "Returns the base-10 logarithm of a number.",
588 "log10(numeric_expression)",
589 )
590 .with_standard_argument("numeric_expression", Some("Numeric"))
591 .with_sql_example(
592 r#"```sql
593> SELECT log10(100);
594+-------------+
595| log10(100) |
596+-------------+
597| 2.0 |
598+-------------+
599```"#,
600 )
601 .build()
602});
603
604pub fn get_log10_doc() -> &'static Documentation {
605 &DOCUMENTATION_LOG10
606}
607
608pub fn radians_order(input: &[ExprProperties]) -> Result<SortProperties> {
610 Ok(input[0].sort_properties)
611}
612
613static DOCUMENTATION_RADIANS: LazyLock<Documentation> = LazyLock::new(|| {
614 Documentation::builder(
615 DOC_SECTION_MATH,
616 "Converts degrees to radians.",
617 "radians(numeric_expression)",
618 )
619 .with_standard_argument("numeric_expression", Some("Numeric"))
620 .with_sql_example(
621 r#"```sql
622> SELECT radians(180);
623+----------------+
624| radians(180) |
625+----------------+
626| 3.14159265359 |
627+----------------+
628```"#,
629 )
630 .build()
631});
632
633pub fn get_radians_doc() -> &'static Documentation {
634 &DOCUMENTATION_RADIANS
635}
636
637pub fn sin_order(_input: &[ExprProperties]) -> Result<SortProperties> {
641 Ok(SortProperties::Unordered)
642}
643
644static DOCUMENTATION_SIN: LazyLock<Documentation> = LazyLock::new(|| {
645 Documentation::builder(
646 DOC_SECTION_MATH,
647 "Returns the sine of a number.",
648 "sin(numeric_expression)",
649 )
650 .with_standard_argument("numeric_expression", Some("Numeric"))
651 .with_sql_example(
652 r#"```sql
653> SELECT sin(0);
654+----------+
655| sin(0) |
656+----------+
657| 0.0 |
658+----------+
659```"#,
660 )
661 .build()
662});
663
664pub fn get_sin_doc() -> &'static Documentation {
665 &DOCUMENTATION_SIN
666}
667
668pub fn sinh_order(input: &[ExprProperties]) -> Result<SortProperties> {
670 Ok(input[0].sort_properties)
671}
672
673static DOCUMENTATION_SINH: LazyLock<Documentation> = LazyLock::new(|| {
674 Documentation::builder(
675 DOC_SECTION_MATH,
676 "Returns the hyperbolic sine of a number.",
677 "sinh(numeric_expression)",
678 )
679 .with_standard_argument("numeric_expression", Some("Numeric"))
680 .with_sql_example(
681 r#"```sql
682> SELECT sinh(1);
683+-----------+
684| sinh(1) |
685+-----------+
686| 1.1752012 |
687+-----------+
688```"#,
689 )
690 .build()
691});
692
693pub fn get_sinh_doc() -> &'static Documentation {
694 &DOCUMENTATION_SINH
695}
696
697pub fn sqrt_order(input: &[ExprProperties]) -> Result<SortProperties> {
699 let arg = &input[0];
700 let range = &arg.range;
701
702 let zero_point = Interval::make_zero(&range.lower().data_type())?;
703
704 if range.gt_eq(&zero_point)? == Interval::CERTAINLY_TRUE {
705 Ok(arg.sort_properties)
706 } else {
707 exec_err!("Input range of SQRT contains out-of-domain values")
708 }
709}
710
711static DOCUMENTATION_SQRT: LazyLock<Documentation> = LazyLock::new(|| {
712 Documentation::builder(
713 DOC_SECTION_MATH,
714 "Returns the square root of a number.",
715 "sqrt(numeric_expression)",
716 )
717 .with_standard_argument("numeric_expression", Some("Numeric"))
718 .build()
719});
720
721pub fn get_sqrt_doc() -> &'static Documentation {
722 &DOCUMENTATION_SQRT
723}
724
725pub fn tan_order(_input: &[ExprProperties]) -> Result<SortProperties> {
729 Ok(SortProperties::Unordered)
730}
731
732static DOCUMENTATION_TAN: LazyLock<Documentation> = LazyLock::new(|| {
733 Documentation::builder(
734 DOC_SECTION_MATH,
735 "Returns the tangent of a number.",
736 "tan(numeric_expression)",
737 )
738 .with_standard_argument("numeric_expression", Some("Numeric"))
739 .with_sql_example(
740 r#"```sql
741> SELECT tan(pi()/4);
742+--------------+
743| tan(PI()/4) |
744+--------------+
745| 1.0 |
746+--------------+
747```"#,
748 )
749 .build()
750});
751
752pub fn get_tan_doc() -> &'static Documentation {
753 &DOCUMENTATION_TAN
754}
755
756pub fn tanh_order(input: &[ExprProperties]) -> Result<SortProperties> {
758 Ok(input[0].sort_properties)
759}
760
761static DOCUMENTATION_TANH: LazyLock<Documentation> = LazyLock::new(|| {
762 Documentation::builder(
763 DOC_SECTION_MATH,
764 "Returns the hyperbolic tangent of a number.",
765 "tanh(numeric_expression)",
766 )
767 .with_standard_argument("numeric_expression", Some("Numeric"))
768 .with_sql_example(
769 r#"```sql
770 > SELECT tanh(20);
771 +----------+
772 | tanh(20) |
773 +----------+
774 | 1.0 |
775 +----------+
776 ```"#,
777 )
778 .build()
779});
780
781pub fn get_tanh_doc() -> &'static Documentation {
782 &DOCUMENTATION_TANH
783}
784
785#[cfg(test)]
786mod tests {
787 use arrow::compute::SortOptions;
788 use datafusion_common::Result;
789
790 use super::*;
791
792 #[derive(Debug)]
793 struct MonotonicityTestCase {
794 name: &'static str,
795 func: fn(&[ExprProperties]) -> Result<SortProperties>,
796 lower: f64,
797 upper: f64,
798 input_sort: SortProperties,
799 expected: Result<SortProperties>,
800 }
801
802 #[test]
803 fn test_monotonicity_table() {
804 fn create_ep(lower: f64, upper: f64, sp: SortProperties) -> ExprProperties {
805 ExprProperties {
806 range: Interval::try_new(
807 ScalarValue::from(lower),
808 ScalarValue::from(upper),
809 )
810 .unwrap(),
811 sort_properties: sp,
812 preserves_lex_ordering: false,
813 }
814 }
815
816 let test_cases = vec![
817 MonotonicityTestCase {
818 name: "acos_order within domain",
819 func: acos_order,
820 lower: -0.5,
821 upper: 0.5,
822 input_sort: SortProperties::Ordered(SortOptions {
823 descending: false,
824 nulls_first: false,
825 }),
826 expected: Ok(SortProperties::Ordered(SortOptions {
827 descending: true,
828 nulls_first: false,
829 })),
830 },
831 MonotonicityTestCase {
832 name: "acos_order out of domain",
833 func: acos_order,
834 lower: -2.0,
835 upper: 1.0,
836 input_sort: SortProperties::Ordered(SortOptions {
837 descending: false,
838 nulls_first: false,
839 }),
840 expected: exec_err!("Input range of ACOS contains out-of-domain values"),
841 },
842 MonotonicityTestCase {
843 name: "acosh_order within domain",
844 func: acosh_order,
845 lower: 2.0,
846 upper: 100.0,
847 input_sort: SortProperties::Ordered(SortOptions {
848 descending: false,
849 nulls_first: true,
850 }),
851 expected: Ok(SortProperties::Ordered(SortOptions {
852 descending: false,
853 nulls_first: true,
854 })),
855 },
856 MonotonicityTestCase {
857 name: "acosh_order out of domain",
858 func: acosh_order,
859 lower: 0.5,
860 upper: 1.0,
861 input_sort: SortProperties::Ordered(SortOptions {
862 descending: true,
863 nulls_first: false,
864 }),
865 expected: exec_err!("Input range of ACOSH contains out-of-domain values"),
866 },
867 MonotonicityTestCase {
868 name: "asin_order within domain",
869 func: asin_order,
870 lower: -0.5,
871 upper: 0.5,
872 input_sort: SortProperties::Ordered(SortOptions {
873 descending: false,
874 nulls_first: false,
875 }),
876 expected: Ok(SortProperties::Ordered(SortOptions {
877 descending: false,
878 nulls_first: false,
879 })),
880 },
881 MonotonicityTestCase {
882 name: "asin_order out of domain",
883 func: asin_order,
884 lower: -2.0,
885 upper: 1.0,
886 input_sort: SortProperties::Ordered(SortOptions {
887 descending: false,
888 nulls_first: false,
889 }),
890 expected: exec_err!("Input range of ASIN contains out-of-domain values"),
891 },
892 MonotonicityTestCase {
893 name: "asinh_order within domain",
894 func: asinh_order,
895 lower: -1.0,
896 upper: 1.0,
897 input_sort: SortProperties::Ordered(SortOptions {
898 descending: false,
899 nulls_first: false,
900 }),
901 expected: Ok(SortProperties::Ordered(SortOptions {
902 descending: false,
903 nulls_first: false,
904 })),
905 },
906 MonotonicityTestCase {
907 name: "asinh_order out of domain",
908 func: asinh_order,
909 lower: -2.0,
910 upper: 1.0,
911 input_sort: SortProperties::Ordered(SortOptions {
912 descending: false,
913 nulls_first: false,
914 }),
915 expected: Ok(SortProperties::Ordered(SortOptions {
916 descending: false,
917 nulls_first: false,
918 })),
919 },
920 MonotonicityTestCase {
921 name: "atan_order within domain",
922 func: atan_order,
923 lower: -1.0,
924 upper: 1.0,
925 input_sort: SortProperties::Ordered(SortOptions {
926 descending: false,
927 nulls_first: false,
928 }),
929 expected: Ok(SortProperties::Ordered(SortOptions {
930 descending: false,
931 nulls_first: false,
932 })),
933 },
934 MonotonicityTestCase {
935 name: "atan_order out of domain",
936 func: atan_order,
937 lower: -2.0,
938 upper: 1.0,
939 input_sort: SortProperties::Ordered(SortOptions {
940 descending: false,
941 nulls_first: false,
942 }),
943 expected: Ok(SortProperties::Ordered(SortOptions {
944 descending: false,
945 nulls_first: false,
946 })),
947 },
948 MonotonicityTestCase {
949 name: "atanh_order within domain",
950 func: atanh_order,
951 lower: -0.6,
952 upper: 0.6,
953 input_sort: SortProperties::Ordered(SortOptions {
954 descending: false,
955 nulls_first: false,
956 }),
957 expected: Ok(SortProperties::Ordered(SortOptions {
958 descending: false,
959 nulls_first: false,
960 })),
961 },
962 MonotonicityTestCase {
963 name: "atanh_order out of domain",
964 func: atanh_order,
965 lower: -2.0,
966 upper: 1.0,
967 input_sort: SortProperties::Ordered(SortOptions {
968 descending: false,
969 nulls_first: false,
970 }),
971 expected: exec_err!("Input range of ATANH contains out-of-domain values"),
972 },
973 MonotonicityTestCase {
974 name: "cbrt_order within domain",
975 func: cbrt_order,
976 lower: -1.0,
977 upper: 1.0,
978 input_sort: SortProperties::Ordered(SortOptions {
979 descending: false,
980 nulls_first: false,
981 }),
982 expected: Ok(SortProperties::Ordered(SortOptions {
983 descending: false,
984 nulls_first: false,
985 })),
986 },
987 MonotonicityTestCase {
988 name: "cbrt_order out of domain",
989 func: cbrt_order,
990 lower: -2.0,
991 upper: 1.0,
992 input_sort: SortProperties::Ordered(SortOptions {
993 descending: false,
994 nulls_first: false,
995 }),
996 expected: Ok(SortProperties::Ordered(SortOptions {
997 descending: false,
998 nulls_first: false,
999 })),
1000 },
1001 MonotonicityTestCase {
1002 name: "ceil_order within domain",
1003 func: ceil_order,
1004 lower: -1.0,
1005 upper: 1.0,
1006 input_sort: SortProperties::Ordered(SortOptions {
1007 descending: false,
1008 nulls_first: false,
1009 }),
1010 expected: Ok(SortProperties::Ordered(SortOptions {
1011 descending: false,
1012 nulls_first: false,
1013 })),
1014 },
1015 MonotonicityTestCase {
1016 name: "ceil_order out of domain",
1017 func: ceil_order,
1018 lower: -2.0,
1019 upper: 1.0,
1020 input_sort: SortProperties::Ordered(SortOptions {
1021 descending: false,
1022 nulls_first: false,
1023 }),
1024 expected: Ok(SortProperties::Ordered(SortOptions {
1025 descending: false,
1026 nulls_first: false,
1027 })),
1028 },
1029 MonotonicityTestCase {
1030 name: "cos_order within domain",
1031 func: cos_order,
1032 lower: 0.0,
1033 upper: 2.0 * std::f64::consts::PI,
1034 input_sort: SortProperties::Ordered(SortOptions {
1035 descending: false,
1036 nulls_first: false,
1037 }),
1038 expected: Ok(SortProperties::Unordered),
1039 },
1040 MonotonicityTestCase {
1041 name: "cos_order out of domain",
1042 func: cos_order,
1043 lower: -2.0,
1044 upper: 1.0,
1045 input_sort: SortProperties::Ordered(SortOptions {
1046 descending: false,
1047 nulls_first: false,
1048 }),
1049 expected: Ok(SortProperties::Unordered),
1050 },
1051 MonotonicityTestCase {
1052 name: "cosh_order within domain positive",
1053 func: cosh_order,
1054 lower: 5.0,
1055 upper: 100.0,
1056 input_sort: SortProperties::Ordered(SortOptions {
1057 descending: false,
1058 nulls_first: false,
1059 }),
1060 expected: Ok(SortProperties::Ordered(SortOptions {
1061 descending: false,
1062 nulls_first: false,
1063 })),
1064 },
1065 MonotonicityTestCase {
1066 name: "cosh_order within domain negative",
1067 func: cosh_order,
1068 lower: -100.0,
1069 upper: -5.0,
1070 input_sort: SortProperties::Ordered(SortOptions {
1071 descending: false,
1072 nulls_first: false,
1073 }),
1074 expected: Ok(SortProperties::Ordered(SortOptions {
1075 descending: true,
1076 nulls_first: false,
1077 })),
1078 },
1079 MonotonicityTestCase {
1080 name: "cosh_order out of domain so unordered",
1081 func: cosh_order,
1082 lower: -1.0,
1083 upper: 1.0,
1084 input_sort: SortProperties::Ordered(SortOptions {
1085 descending: false,
1086 nulls_first: false,
1087 }),
1088 expected: Ok(SortProperties::Unordered),
1089 },
1090 MonotonicityTestCase {
1091 name: "degrees_order",
1092 func: degrees_order,
1093 lower: -1.0,
1094 upper: 1.0,
1095 input_sort: SortProperties::Ordered(SortOptions {
1096 descending: true,
1097 nulls_first: true,
1098 }),
1099 expected: Ok(SortProperties::Ordered(SortOptions {
1100 descending: true,
1101 nulls_first: true,
1102 })),
1103 },
1104 MonotonicityTestCase {
1105 name: "exp_order",
1106 func: exp_order,
1107 lower: -1000.0,
1108 upper: 1000.0,
1109 input_sort: SortProperties::Ordered(SortOptions {
1110 descending: false,
1111 nulls_first: false,
1112 }),
1113 expected: Ok(SortProperties::Ordered(SortOptions {
1114 descending: false,
1115 nulls_first: false,
1116 })),
1117 },
1118 MonotonicityTestCase {
1119 name: "floor_order",
1120 func: floor_order,
1121 lower: -1.0,
1122 upper: 1.0,
1123 input_sort: SortProperties::Ordered(SortOptions {
1124 descending: true,
1125 nulls_first: true,
1126 }),
1127 expected: Ok(SortProperties::Ordered(SortOptions {
1128 descending: true,
1129 nulls_first: true,
1130 })),
1131 },
1132 MonotonicityTestCase {
1133 name: "ln_order within domain",
1134 func: ln_order,
1135 lower: 1.0,
1136 upper: 2.0,
1137 input_sort: SortProperties::Ordered(SortOptions {
1138 descending: false,
1139 nulls_first: false,
1140 }),
1141 expected: Ok(SortProperties::Ordered(SortOptions {
1142 descending: false,
1143 nulls_first: false,
1144 })),
1145 },
1146 MonotonicityTestCase {
1147 name: "ln_order out of domain",
1148 func: ln_order,
1149 lower: -5.0,
1150 upper: -4.0,
1151 input_sort: SortProperties::Ordered(SortOptions {
1152 descending: false,
1153 nulls_first: false,
1154 }),
1155 expected: exec_err!("Input range of LN contains out-of-domain values"),
1156 },
1157 ];
1158
1159 for tcase in test_cases {
1160 let input = vec![create_ep(tcase.lower, tcase.upper, tcase.input_sort)];
1161 let actual = (tcase.func)(&input);
1162 match (&actual, &tcase.expected) {
1163 (Ok(a), Ok(e)) => assert_eq!(
1164 a, e,
1165 "Test '{}' failed: got {:?}, expected {:?}",
1166 tcase.name, a, e
1167 ),
1168 (Err(e1), Err(e2)) => {
1169 assert_eq!(
1170 e1.strip_backtrace().to_string(),
1171 e2.strip_backtrace().to_string(),
1172 "Test '{}' failed: got {:?}, expected {:?}",
1173 tcase.name,
1174 e1,
1175 e2
1176 )
1177 } _ => panic!(
1179 "Test '{}' failed: got {:?}, expected {:?}",
1180 tcase.name, actual, tcase.expected
1181 ),
1182 }
1183 }
1184 }
1185}