This is an automated email from the ASF dual-hosted git repository.

tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new 62958223f Allow format specification in cast (#4169)
62958223f is described below

commit 62958223fb522945ee466b5ec426cbb3f15f405a
Author: Parth Chandra <[email protected]>
AuthorDate: Tue May 9 03:36:50 2023 -0700

    Allow format specification in cast (#4169)
    
    * Allow format specification in cast
    
    * Add documentation change
    
    * Pass format options into value_to_string for Decimal types
---
 arrow-cast/src/cast.rs    | 500 ++++++++++++++++++++++++++++++++++++++--------
 arrow-cast/src/display.rs |   2 +-
 2 files changed, 414 insertions(+), 88 deletions(-)

diff --git a/arrow-cast/src/cast.rs b/arrow-cast/src/cast.rs
index 12e80cab4..d015f4952 100644
--- a/arrow-cast/src/cast.rs
+++ b/arrow-cast/src/cast.rs
@@ -56,12 +56,21 @@ use num::{NumCast, ToPrimitive};
 
 /// CastOptions provides a way to override the default cast behaviors
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct CastOptions {
+pub struct CastOptions<'a> {
     /// how to handle cast failures, either return NULL (safe=true) or return 
ERR (safe=false)
     pub safe: bool,
+    /// Formatting options when casting from temporal types to string
+    pub format_options: FormatOptions<'a>,
 }
 
-pub const DEFAULT_CAST_OPTIONS: CastOptions = CastOptions { safe: true };
+impl<'a> Default for CastOptions<'a> {
+    fn default() -> Self {
+        Self {
+            safe: true,
+            format_options: FormatOptions::default(),
+        }
+    }
+}
 
 /// Return true if a value of type `from_type` can be cast into a
 /// value of `to_type`. Note that such as cast may be lossy.
@@ -334,7 +343,7 @@ pub fn can_cast_types(from_type: &DataType, to_type: 
&DataType) -> bool {
 /// * List to primitive
 /// * Interval and duration
 pub fn cast(array: &dyn Array, to_type: &DataType) -> Result<ArrayRef, 
ArrowError> {
-    cast_with_options(array, to_type, &DEFAULT_CAST_OPTIONS)
+    cast_with_options(array, to_type, &CastOptions::default())
 }
 
 fn cast_integer_to_decimal<
@@ -947,8 +956,8 @@ pub fn cast_with_options(
                         x as f64 / 10_f64.powi(*scale as i32)
                     })
                 }
-                Utf8 => value_to_string::<i32>(array),
-                LargeUtf8 => value_to_string::<i64>(array),
+                Utf8 => value_to_string::<i32>(array, 
Some(&cast_options.format_options)),
+                LargeUtf8 => value_to_string::<i64>(array, 
Some(&cast_options.format_options)),
                 Null => Ok(new_null_array(to_type, array.len())),
                 _ => Err(ArrowError::CastError(format!(
                     "Casting from {from_type:?} to {to_type:?} not supported"
@@ -1016,8 +1025,8 @@ pub fn cast_with_options(
                         x.to_f64().unwrap() / 10_f64.powi(*scale as i32)
                     })
                 }
-                Utf8 => value_to_string::<i32>(array),
-                LargeUtf8 => value_to_string::<i64>(array),
+                Utf8 => value_to_string::<i32>(array, 
Some(&cast_options.format_options)),
+                LargeUtf8 => value_to_string::<i64>(array, 
Some(&cast_options.format_options)),
                 Null => Ok(new_null_array(to_type, array.len())),
                 _ => Err(ArrowError::CastError(format!(
                     "Casting from {from_type:?} to {to_type:?} not supported"
@@ -1413,8 +1422,8 @@ pub fn cast_with_options(
                 "Casting from {from_type:?} to {to_type:?} not supported",
             ))),
         },
-        (from_type, LargeUtf8) if from_type.is_primitive() => 
value_to_string::<i64>(array),
-        (from_type, Utf8) if from_type.is_primitive() => 
value_to_string::<i32>(array),
+        (from_type, LargeUtf8) if from_type.is_primitive() => 
value_to_string::<i64>(array, Some(&cast_options.format_options)),
+        (from_type, Utf8) if from_type.is_primitive() => 
value_to_string::<i32>(array, Some(&cast_options.format_options)),
         // start numeric casts
         (UInt8, UInt16) => {
             cast_numeric_arrays::<UInt8Type, UInt16Type>(array, cast_options)
@@ -2450,10 +2459,14 @@ where
 
 fn value_to_string<O: OffsetSizeTrait>(
     array: &dyn Array,
+    options: Option<&FormatOptions>,
 ) -> Result<ArrayRef, ArrowError> {
     let mut builder = GenericStringBuilder::<O>::new();
-    let options = FormatOptions::default();
-    let formatter = ArrayFormatter::try_new(array, &options)?;
+    let mut fmt_options = &FormatOptions::default();
+    if let Some(fmt_opts) = options {
+        fmt_options = fmt_opts;
+    };
+    let formatter = ArrayFormatter::try_new(array, fmt_options)?;
     let nulls = array.nulls();
     for i in 0..array.len() {
         match nulls.map(|x| x.is_null(i)).unwrap_or_default() {
@@ -3871,7 +3884,10 @@ mod tests {
                 }
             }
 
-            let cast_option = CastOptions { safe: false };
+            let cast_option = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let casted_array_with_option =
                 cast_with_options($INPUT_ARRAY, $OUTPUT_TYPE, 
&cast_option).unwrap();
             let result_array = casted_array_with_option
@@ -4079,8 +4095,14 @@ mod tests {
 
         let array = vec![Some(i128::MAX)];
         let array = create_decimal_array(array, 38, 3).unwrap();
-        let result =
-            cast_with_options(&array, &output_type, &CastOptions { safe: false 
});
+        let result = cast_with_options(
+            &array,
+            &output_type,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!("Cast error: Cannot cast to Decimal128(38, 38). Overflowing 
on 170141183460469231731687303715884105727",
                    result.unwrap_err().to_string());
     }
@@ -4093,8 +4115,14 @@ mod tests {
 
         let array = vec![Some(i128::MAX)];
         let array = create_decimal_array(array, 38, 3).unwrap();
-        let result =
-            cast_with_options(&array, &output_type, &CastOptions { safe: false 
});
+        let result = cast_with_options(
+            &array,
+            &output_type,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!("Cast error: Cannot cast to Decimal256(76, 76). Overflowing 
on 170141183460469231731687303715884105727",
                    result.unwrap_err().to_string());
     }
@@ -4126,8 +4154,14 @@ mod tests {
         assert!(can_cast_types(&input_type, &output_type));
         let array = vec![Some(i256::from_i128(i128::MAX))];
         let array = create_decimal256_array(array, 76, 5).unwrap();
-        let result =
-            cast_with_options(&array, &output_type, &CastOptions { safe: false 
});
+        let result = cast_with_options(
+            &array,
+            &output_type,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!("Cast error: Cannot cast to Decimal128(38, 7). Overflowing 
on 170141183460469231731687303715884105727",
                    result.unwrap_err().to_string());
     }
@@ -4139,8 +4173,14 @@ mod tests {
         assert!(can_cast_types(&input_type, &output_type));
         let array = vec![Some(i256::from_i128(i128::MAX))];
         let array = create_decimal256_array(array, 76, 5).unwrap();
-        let result =
-            cast_with_options(&array, &output_type, &CastOptions { safe: false 
});
+        let result = cast_with_options(
+            &array,
+            &output_type,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!("Cast error: Cannot cast to Decimal256(76, 55). Overflowing 
on 170141183460469231731687303715884105727",
                    result.unwrap_err().to_string());
     }
@@ -4286,30 +4326,54 @@ mod tests {
         // overflow test: out of range of max u8
         let value_array: Vec<Option<i128>> = vec![Some(51300)];
         let array = create_decimal_array(value_array, 38, 2).unwrap();
-        let casted_array =
-            cast_with_options(&array, &DataType::UInt8, &CastOptions { safe: 
false });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::UInt8,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!(
             "Cast error: value of 513 is out of range UInt8".to_string(),
             casted_array.unwrap_err().to_string()
         );
 
-        let casted_array =
-            cast_with_options(&array, &DataType::UInt8, &CastOptions { safe: 
true });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::UInt8,
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
 
         // overflow test: out of range of max i8
         let value_array: Vec<Option<i128>> = vec![Some(24400)];
         let array = create_decimal_array(value_array, 38, 2).unwrap();
-        let casted_array =
-            cast_with_options(&array, &DataType::Int8, &CastOptions { safe: 
false });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::Int8,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!(
             "Cast error: value of 244 is out of range Int8".to_string(),
             casted_array.unwrap_err().to_string()
         );
 
-        let casted_array =
-            cast_with_options(&array, &DataType::Int8, &CastOptions { safe: 
true });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::Int8,
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
 
@@ -4465,15 +4529,27 @@ mod tests {
         // overflow test: out of range of max i8
         let value_array: Vec<Option<i256>> = 
vec![Some(i256::from_i128(24400))];
         let array = create_decimal256_array(value_array, 38, 2).unwrap();
-        let casted_array =
-            cast_with_options(&array, &DataType::Int8, &CastOptions { safe: 
false });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::Int8,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert_eq!(
             "Cast error: value of 244 is out of range Int8".to_string(),
             casted_array.unwrap_err().to_string()
         );
 
-        let casted_array =
-            cast_with_options(&array, &DataType::Int8, &CastOptions { safe: 
true });
+        let casted_array = cast_with_options(
+            &array,
+            &DataType::Int8,
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
+        );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
 
@@ -4886,7 +4962,10 @@ mod tests {
     fn test_cast_int32_to_u8_with_error() {
         let array = Int32Array::from(vec![-5, 6, -7, 8, 100000000]);
         // overflow with the error
-        let cast_option = CastOptions { safe: false };
+        let cast_option = CastOptions {
+            safe: false,
+            format_options: FormatOptions::default(),
+        };
         let result = cast_with_options(&array, &DataType::UInt8, &cast_option);
         assert!(result.is_err());
         result.unwrap();
@@ -5010,8 +5089,14 @@ mod tests {
     #[test]
     fn test_cast_with_options_utf8_to_i32() {
         let array = StringArray::from(vec!["5", "6", "seven", "8", "9.1"]);
-        let result =
-            cast_with_options(&array, &DataType::Int32, &CastOptions { safe: 
false });
+        let result = cast_with_options(
+            &array,
+            &DataType::Int32,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         match result {
             Ok(_) => panic!("expected error"),
             Err(e) => {
@@ -5037,8 +5122,14 @@ mod tests {
     #[test]
     fn test_cast_with_options_utf8_to_bool() {
         let strings = StringArray::from(vec!["true", "false", "invalid", " Y 
", ""]);
-        let casted =
-            cast_with_options(&strings, &DataType::Boolean, &CastOptions { 
safe: false });
+        let casted = cast_with_options(
+            &strings,
+            &DataType::Boolean,
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
+        );
         match casted {
             Ok(_) => panic!("expected error"),
             Err(e) => {
@@ -5244,7 +5335,10 @@ mod tests {
                     }
                 }
 
-                let options = CastOptions { safe: false };
+                let options = CastOptions {
+                    safe: false,
+                    format_options: FormatOptions::default(),
+                };
                 let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
                 assert_eq!(
                     err.to_string(),
@@ -5282,7 +5376,10 @@ mod tests {
             assert!(c.is_null(1));
             assert!(c.is_null(2));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 'Not a 
valid date' to value of Date32 type");
         }
@@ -5314,7 +5411,10 @@ mod tests {
             assert!(c.is_null(3));
             assert!(c.is_null(4));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 
'08:08:61.091323414' to value of Time32(Second) type");
         }
@@ -5346,7 +5446,10 @@ mod tests {
             assert!(c.is_null(3));
             assert!(c.is_null(4));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 
'08:08:61.091323414' to value of Time32(Millisecond) type");
         }
@@ -5372,7 +5475,10 @@ mod tests {
             assert!(c.is_null(1));
             assert!(c.is_null(2));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 'Not a 
valid time' to value of Time64(Microsecond) type");
         }
@@ -5398,7 +5504,10 @@ mod tests {
             assert!(c.is_null(1));
             assert!(c.is_null(2));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 'Not a 
valid time' to value of Time64(Nanosecond) type");
         }
@@ -5424,7 +5533,10 @@ mod tests {
             assert!(c.is_null(1));
             assert!(c.is_null(2));
 
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let err = cast_with_options(array, &to_type, 
&options).unwrap_err();
             assert_eq!(err.to_string(), "Cast error: Cannot cast string 'Not a 
valid date' to value of Date64 type");
         }
@@ -5435,7 +5547,10 @@ mod tests {
             let source_string_array =
                 Arc::new(StringArray::from($data_vec.clone())) as ArrayRef;
 
-            let options = CastOptions { safe: true };
+            let options = CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            };
 
             let target_interval_array = cast_with_options(
                 &source_string_array.clone(),
@@ -5559,7 +5674,10 @@ mod tests {
     macro_rules! test_unsafe_string_to_interval_err {
         ($data_vec:expr, $interval_unit:expr, $error_msg:expr) => {
             let string_array = Arc::new(StringArray::from($data_vec.clone())) 
as ArrayRef;
-            let options = CastOptions { safe: false };
+            let options = CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            };
             let arrow_err = cast_with_options(
                 &string_array.clone(),
                 &DataType::Interval($interval_unit),
@@ -5659,14 +5777,20 @@ mod tests {
         let array_ref = cast_with_options(
             &a1,
             &DataType::FixedSizeBinary(5),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(array_ref.is_err());
 
         let array_ref = cast_with_options(
             &a2,
             &DataType::FixedSizeBinary(5),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(array_ref.is_err());
     }
@@ -5751,7 +5875,10 @@ mod tests {
         assert!(b.is_null(0));
         // test overflow, unsafe cast
         let array = TimestampSecondArray::from(vec![Some(i64::MAX)]);
-        let options = CastOptions { safe: false };
+        let options = CastOptions {
+            safe: false,
+            format_options: FormatOptions::default(),
+        };
         let b = cast_with_options(&array, &DataType::Date64, &options);
         assert!(b.is_err());
     }
@@ -6000,6 +6127,136 @@ mod tests {
         assert_eq!("2018-12-25T00:00:00", c.value(1));
     }
 
+    #[test]
+    fn test_cast_timestamp_to_strings() {
+        // "2018-12-25T00:00:02.001", "1997-05-19T00:00:03.005", None
+        let array = TimestampMillisecondArray::from(vec![
+            Some(864000003005),
+            Some(1545696002001),
+            None,
+        ]);
+        let out = cast(&array, &DataType::Utf8).unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<StringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19T00:00:03.005"),
+                Some("2018-12-25T00:00:02.001"),
+                None
+            ]
+        );
+        let out = cast(&array, &DataType::LargeUtf8).unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<LargeStringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19T00:00:03.005"),
+                Some("2018-12-25T00:00:02.001"),
+                None
+            ]
+        );
+    }
+
+    #[test]
+    fn test_cast_timestamp_to_strings_opt() {
+        let ts_format = "%Y-%m-%d %H:%M:%S%.6f";
+        let tz = "+0545"; // UTC + 0545 is Asia/Kathmandu
+        let cast_options = CastOptions {
+            safe: true,
+            format_options: FormatOptions::default()
+                .with_timestamp_format(Some(ts_format))
+                .with_timestamp_tz_format(Some(ts_format)),
+        };
+        // "2018-12-25T00:00:02.001", "1997-05-19T00:00:03.005", None
+        let array_without_tz = TimestampMillisecondArray::from(vec![
+            Some(864000003005),
+            Some(1545696002001),
+            None,
+        ]);
+        let out =
+            cast_with_options(&array_without_tz, &DataType::Utf8, 
&cast_options).unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<StringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19 00:00:03.005000"),
+                Some("2018-12-25 00:00:02.001000"),
+                None
+            ]
+        );
+        let out =
+            cast_with_options(&array_without_tz, &DataType::LargeUtf8, 
&cast_options)
+                .unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<LargeStringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19 00:00:03.005000"),
+                Some("2018-12-25 00:00:02.001000"),
+                None
+            ]
+        );
+
+        let array_with_tz = TimestampMillisecondArray::from(vec![
+            Some(864000003005),
+            Some(1545696002001),
+            None,
+        ])
+        .with_timezone(tz.to_string());
+        let out =
+            cast_with_options(&array_with_tz, &DataType::Utf8, 
&cast_options).unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<StringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19 05:45:03.005000"),
+                Some("2018-12-25 05:45:02.001000"),
+                None
+            ]
+        );
+        let out = cast_with_options(&array_with_tz, &DataType::LargeUtf8, 
&cast_options)
+            .unwrap();
+        let out = out
+            .as_any()
+            .downcast_ref::<LargeStringArray>()
+            .unwrap()
+            .into_iter()
+            .collect::<Vec<_>>();
+        assert_eq!(
+            out,
+            vec![
+                Some("1997-05-19 05:45:03.005000"),
+                Some("2018-12-25 05:45:02.001000"),
+                None
+            ]
+        );
+    }
+
     #[test]
     fn test_cast_between_timestamps() {
         let array = TimestampMillisecondArray::from(vec![
@@ -7698,7 +7955,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal128(38, 30),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -7706,7 +7966,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal128(38, 30),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
     }
@@ -7718,7 +7981,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal256(76, 76),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -7726,7 +7992,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal256(76, 76),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
     }
@@ -7738,7 +8007,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal128(38, 30),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -7746,7 +8018,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal128(38, 30),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         let err = casted_array.unwrap_err().to_string();
         let expected_error = "Cast error: Cannot cast to Decimal128(38, 30)";
@@ -7763,7 +8038,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal256(76, 50),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -7771,7 +8049,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal256(76, 50),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         let err = casted_array.unwrap_err().to_string();
         let expected_error = "Cast error: Cannot cast to Decimal256(76, 50)";
@@ -8097,7 +8378,10 @@ mod tests {
         let output_type = DataType::Decimal128(38, 2);
         let str_array = StringArray::from(vec!["4.4.5"]);
         let array = Arc::new(str_array) as ArrayRef;
-        let option = CastOptions { safe: false };
+        let option = CastOptions {
+            safe: false,
+            format_options: FormatOptions::default(),
+        };
         let casted_err = cast_with_options(&array, &output_type, 
&option).unwrap_err();
         assert!(casted_err
             .to_string()
@@ -8324,7 +8608,10 @@ mod tests {
             let b = cast_with_options(
                 &array,
                 &DataType::Timestamp(TimeUnit::Nanosecond, Some(tz.clone())),
-                &CastOptions { safe: false },
+                &CastOptions {
+                    safe: false,
+                    format_options: FormatOptions::default(),
+                },
             )
             .unwrap();
 
@@ -8373,7 +8660,10 @@ mod tests {
         let v1: &[u8] = b"\xFF invalid";
         let v2: &[u8] = b"\x00 Foo";
         let s = BinaryArray::from(vec![v1, v2]);
-        let options = CastOptions { safe: true };
+        let options = CastOptions {
+            safe: true,
+            format_options: FormatOptions::default(),
+        };
         let array = cast_with_options(&s, &DataType::Utf8, &options).unwrap();
         let a = array.as_string::<i32>();
         a.to_data().validate_full().unwrap();
@@ -8467,7 +8757,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal128(7, 3),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -8475,7 +8768,10 @@ mod tests {
         let err = cast_with_options(
             &array,
             &DataType::Decimal128(7, 3),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert_eq!("Invalid argument error: 1234567000 is too large to store 
in a Decimal128 of precision 7. Max is 9999999", err.unwrap_err().to_string());
     }
@@ -8487,7 +8783,10 @@ mod tests {
         let casted_array = cast_with_options(
             &array,
             &DataType::Decimal256(7, 3),
-            &CastOptions { safe: true },
+            &CastOptions {
+                safe: true,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_ok());
         assert!(casted_array.unwrap().is_null(0));
@@ -8495,7 +8794,10 @@ mod tests {
         let err = cast_with_options(
             &array,
             &DataType::Decimal256(7, 3),
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert_eq!("Invalid argument error: 1234567000 is too large to store 
in a Decimal256 of precision 7. Max is 9999999", err.unwrap_err().to_string());
     }
@@ -8532,7 +8834,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_duration_to_interval::<DurationSecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8544,14 +8846,17 @@ mod tests {
         let array = vec![i64::MAX];
         let casted_array = 
cast_from_duration_to_interval::<DurationSecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_duration_to_interval::<DurationSecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8559,7 +8864,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_duration_to_interval::<DurationMillisecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8571,14 +8876,17 @@ mod tests {
         let array = vec![i64::MAX];
         let casted_array = 
cast_from_duration_to_interval::<DurationMillisecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_duration_to_interval::<DurationMillisecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8586,7 +8894,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_duration_to_interval::<DurationMicrosecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8598,14 +8906,17 @@ mod tests {
         let array = vec![i64::MAX];
         let casted_array = 
cast_from_duration_to_interval::<DurationMicrosecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_duration_to_interval::<DurationMicrosecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8613,7 +8924,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_duration_to_interval::<DurationNanosecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8625,7 +8936,10 @@ mod tests {
         let array = vec![i64::MAX];
         let casted_array = 
cast_from_duration_to_interval::<DurationNanosecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         )
         .unwrap();
         assert_eq!(casted_array.value(0), 9223372036854775807);
@@ -8657,7 +8971,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_interval_to_duration::<DurationSecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8669,14 +8983,17 @@ mod tests {
         let array = vec![i128::MAX];
         let casted_array = 
cast_from_interval_to_duration::<DurationSecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_interval_to_duration::<DurationSecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8684,7 +9001,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_interval_to_duration::<DurationMillisecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(casted_array.value(0), 1);
@@ -8692,14 +9009,17 @@ mod tests {
         let array = vec![i128::MAX];
         let casted_array = 
cast_from_interval_to_duration::<DurationMillisecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_interval_to_duration::<DurationMillisecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8707,7 +9027,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_interval_to_duration::<DurationMicrosecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8719,14 +9039,17 @@ mod tests {
         let array = vec![i128::MAX];
         let casted_array = 
cast_from_interval_to_duration::<DurationMicrosecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert!(!casted_array.is_valid(0));
 
         let casted_array = 
cast_from_interval_to_duration::<DurationMicrosecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
 
@@ -8734,7 +9057,7 @@ mod tests {
         let array = vec![1234567];
         let casted_array = 
cast_from_interval_to_duration::<DurationNanosecondType>(
             array,
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8746,7 +9069,7 @@ mod tests {
         let array = vec![i128::MAX];
         let casted_array = 
cast_from_interval_to_duration::<DurationNanosecondType>(
             array.clone(),
-            &DEFAULT_CAST_OPTIONS,
+            &CastOptions::default(),
         )
         .unwrap();
         assert_eq!(
@@ -8757,7 +9080,10 @@ mod tests {
 
         let casted_array = 
cast_from_interval_to_duration::<DurationNanosecondType>(
             array,
-            &CastOptions { safe: false },
+            &CastOptions {
+                safe: false,
+                format_options: FormatOptions::default(),
+            },
         );
         assert!(casted_array.is_err());
     }
diff --git a/arrow-cast/src/display.rs b/arrow-cast/src/display.rs
index 0bca9ce65..1c2ecfc5e 100644
--- a/arrow-cast/src/display.rs
+++ b/arrow-cast/src/display.rs
@@ -39,7 +39,7 @@ type TimeFormat<'a> = Option<&'a str>;
 /// By default nulls are formatted as `""` and temporal types formatted
 /// according to RFC3339
 ///
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FormatOptions<'a> {
     /// If set to `true` any formatting errors will be written to the output
     /// instead of being converted into a [`std::fmt::Error`]


Reply via email to