1717
1818//! Runtime configuration, via [`ConfigOptions`]
1919
20+ use crate :: error:: _config_err;
21+ use crate :: parsers:: CompressionTypeVariant ;
22+ use crate :: utils:: get_available_parallelism;
23+ use crate :: { DataFusionError , Result } ;
2024use std:: any:: Any ;
2125use std:: collections:: { BTreeMap , HashMap } ;
2226use std:: error:: Error ;
2327use std:: fmt:: { self , Display } ;
2428use std:: str:: FromStr ;
2529
26- use crate :: error:: _config_err;
27- use crate :: parsers:: CompressionTypeVariant ;
28- use crate :: utils:: get_available_parallelism;
29- use crate :: { DataFusionError , Result } ;
30-
3130/// A macro that wraps a configuration struct and automatically derives
3231/// [`Default`] and [`ConfigField`] for it, allowing it to be used
3332/// in the [`ConfigOptions`] configuration tree.
@@ -759,6 +758,59 @@ impl ExecutionOptions {
759758 }
760759}
761760
761+ config_namespace ! {
762+ /// Options controlling the format of output when printing record batches
763+ /// Copies [`arrow::util::display::FormatOptions`]
764+ pub struct FormatOptions {
765+ /// If set to `true` any formatting errors will be written to the output
766+ /// instead of being converted into a [`std::fmt::Error`]
767+ pub safe: bool , default = true
768+ /// Format string for nulls
769+ pub null: String , default = "" . into( )
770+ /// Date format for date arrays
771+ pub date_format: Option <String >, default = Some ( "%Y-%m-%d" . to_string( ) )
772+ /// Format for DateTime arrays
773+ pub datetime_format: Option <String >, default = Some ( "%Y-%m-%dT%H:%M:%S%.f" . to_string( ) )
774+ /// Timestamp format for timestamp arrays
775+ pub timestamp_format: Option <String >, default = Some ( "%Y-%m-%dT%H:%M:%S%.f" . to_string( ) )
776+ /// Timestamp format for timestamp with timezone arrays. When `None`, ISO 8601 format is used.
777+ pub timestamp_tz_format: Option <String >, default = None
778+ /// Time format for time arrays
779+ pub time_format: Option <String >, default = Some ( "%H:%M:%S%.f" . to_string( ) )
780+ /// Duration format. Can be either `"pretty"` or `"ISO8601"`
781+ pub duration_format: String , transform = str :: to_lowercase, default = "pretty" . into( )
782+ /// Show types in visual representation batches
783+ pub types_info: bool , default = false
784+ }
785+ }
786+
787+ impl < ' a > TryInto < arrow:: util:: display:: FormatOptions < ' a > > for & ' a FormatOptions {
788+ type Error = DataFusionError ;
789+ fn try_into ( self ) -> Result < arrow:: util:: display:: FormatOptions < ' a > > {
790+ let duration_format = match self . duration_format . as_str ( ) {
791+ "pretty" => arrow:: util:: display:: DurationFormat :: Pretty ,
792+ "iso8601" => arrow:: util:: display:: DurationFormat :: ISO8601 ,
793+ _ => {
794+ return _config_err ! (
795+ "Invalid duration format: {}. Valid values are pretty or iso8601" ,
796+ self . duration_format
797+ )
798+ }
799+ } ;
800+
801+ Ok ( arrow:: util:: display:: FormatOptions :: new ( )
802+ . with_display_error ( self . safe )
803+ . with_null ( & self . null )
804+ . with_date_format ( self . date_format . as_deref ( ) )
805+ . with_datetime_format ( self . datetime_format . as_deref ( ) )
806+ . with_timestamp_format ( self . timestamp_format . as_deref ( ) )
807+ . with_timestamp_tz_format ( self . timestamp_tz_format . as_deref ( ) )
808+ . with_time_format ( self . time_format . as_deref ( ) )
809+ . with_duration_format ( duration_format)
810+ . with_types_info ( self . types_info ) )
811+ }
812+ }
813+
762814/// A key value pair, with a corresponding description
763815#[ derive( Debug ) ]
764816pub struct ConfigEntry {
@@ -788,6 +840,8 @@ pub struct ConfigOptions {
788840 pub explain : ExplainOptions ,
789841 /// Optional extensions registered using [`Extensions::insert`]
790842 pub extensions : Extensions ,
843+ /// Formatting options when printing batches
844+ pub format : FormatOptions ,
791845}
792846
793847impl ConfigField for ConfigOptions {
@@ -800,6 +854,7 @@ impl ConfigField for ConfigOptions {
800854 "optimizer" => self . optimizer . set ( rem, value) ,
801855 "explain" => self . explain . set ( rem, value) ,
802856 "sql_parser" => self . sql_parser . set ( rem, value) ,
857+ "format" => self . format . set ( rem, value) ,
803858 _ => _config_err ! ( "Config value \" {key}\" not found on ConfigOptions" ) ,
804859 }
805860 }
@@ -810,6 +865,7 @@ impl ConfigField for ConfigOptions {
810865 self . optimizer . visit ( v, "datafusion.optimizer" , "" ) ;
811866 self . explain . visit ( v, "datafusion.explain" , "" ) ;
812867 self . sql_parser . visit ( v, "datafusion.sql_parser" , "" ) ;
868+ self . format . visit ( v, "datafusion.format" , "" ) ;
813869 }
814870}
815871
@@ -2004,11 +2060,11 @@ config_namespace! {
20042060 }
20052061}
20062062
2007- pub trait FormatOptionsExt : Display { }
2063+ pub trait OutputFormatExt : Display { }
20082064
20092065#[ derive( Debug , Clone , PartialEq ) ]
20102066#[ allow( clippy:: large_enum_variant) ]
2011- pub enum FormatOptions {
2067+ pub enum OutputFormat {
20122068 CSV ( CsvOptions ) ,
20132069 JSON ( JsonOptions ) ,
20142070 #[ cfg( feature = "parquet" ) ]
@@ -2017,15 +2073,15 @@ pub enum FormatOptions {
20172073 ARROW ,
20182074}
20192075
2020- impl Display for FormatOptions {
2076+ impl Display for OutputFormat {
20212077 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
20222078 let out = match self {
2023- FormatOptions :: CSV ( _) => "csv" ,
2024- FormatOptions :: JSON ( _) => "json" ,
2079+ OutputFormat :: CSV ( _) => "csv" ,
2080+ OutputFormat :: JSON ( _) => "json" ,
20252081 #[ cfg( feature = "parquet" ) ]
2026- FormatOptions :: PARQUET ( _) => "parquet" ,
2027- FormatOptions :: AVRO => "avro" ,
2028- FormatOptions :: ARROW => "arrow" ,
2082+ OutputFormat :: PARQUET ( _) => "parquet" ,
2083+ OutputFormat :: AVRO => "avro" ,
2084+ OutputFormat :: ARROW => "arrow" ,
20292085 } ;
20302086 write ! ( f, "{}" , out)
20312087 }
0 commit comments