datafusion_spark/function/datetime/
monthname.rs1use std::sync::Arc;
19
20use arrow::array::{AsArray, StringArray};
21use arrow::compute::{DatePart, date_part};
22use arrow::datatypes::{DataType, Field, FieldRef};
23use datafusion_common::types::{NativeType, logical_date};
24use datafusion_common::utils::take_function_args;
25use datafusion_common::{Result, ScalarValue, internal_err};
26use datafusion_expr::{
27 Coercion, ColumnarValue, ReturnFieldArgs, ScalarFunctionArgs, ScalarUDFImpl,
28 Signature, TypeSignatureClass, Volatility,
29};
30
31const MONTH_NAMES: [&str; 12] = [
32 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
33];
34
35fn month_number_to_name(month: i32) -> Option<&'static str> {
36 MONTH_NAMES.get((month - 1) as usize).copied()
37}
38
39#[derive(Debug, PartialEq, Eq, Hash)]
44pub struct SparkMonthName {
45 signature: Signature,
46}
47
48impl Default for SparkMonthName {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl SparkMonthName {
55 pub fn new() -> Self {
56 Self {
57 signature: Signature::coercible(
58 vec![Coercion::new_implicit(
59 TypeSignatureClass::Native(logical_date()),
60 vec![TypeSignatureClass::Timestamp],
61 NativeType::Date,
62 )],
63 Volatility::Immutable,
64 ),
65 }
66 }
67}
68
69impl ScalarUDFImpl for SparkMonthName {
70 fn name(&self) -> &str {
71 "monthname"
72 }
73
74 fn signature(&self) -> &Signature {
75 &self.signature
76 }
77
78 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
79 internal_err!("return_field_from_args should be used instead")
80 }
81
82 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
83 let nullable = args.arg_fields.iter().any(|f| f.is_nullable());
84 Ok(Arc::new(Field::new(self.name(), DataType::Utf8, nullable)))
85 }
86
87 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
88 let [arg] = take_function_args(self.name(), args.args)?;
89 match arg {
90 ColumnarValue::Scalar(scalar) => {
91 if scalar.is_null() {
92 return Ok(ColumnarValue::Scalar(ScalarValue::Utf8(None)));
93 }
94 let arr = scalar.to_array_of_size(1)?;
95 let month_arr = date_part(&arr, DatePart::Month)?;
96 let month_val = month_arr
97 .as_primitive::<arrow::datatypes::Int32Type>()
98 .value(0);
99 let name = month_number_to_name(month_val).map(|s| s.to_string());
100 Ok(ColumnarValue::Scalar(ScalarValue::Utf8(name)))
101 }
102 ColumnarValue::Array(arr) => {
103 let month_arr = date_part(&arr, DatePart::Month)?;
104 let int_arr = month_arr.as_primitive::<arrow::datatypes::Int32Type>();
105
106 let result: StringArray = int_arr
107 .iter()
108 .map(|maybe_month| maybe_month.and_then(month_number_to_name))
109 .collect();
110
111 Ok(ColumnarValue::Array(Arc::new(result)))
112 }
113 }
114 }
115}