alamb commented on code in PR #8829:
URL: https://github.com/apache/arrow-rs/pull/8829#discussion_r2524529377


##########
arrow-cast/src/display.rs:
##########
@@ -57,23 +57,23 @@ pub enum DurationFormat {
 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`]
-    safe: bool,
+    pub safe: bool,

Review Comment:
   > Make fields in FormatOptions public. This is necessary as the custom 
ArrayFormatter must also have access to the formatting options. (see <NULL> in 
the test)
   
   Rather than making these public, what about adding accessors for them? I 
think that would make it easier to change the underlying implementation in the 
future without causing breaking API changes
   
   I think by making all these fields  `pub` it means people can construct 
format options explicitly like
   
   ```rust
   let options = FormatOptions {
     safe: false,
     null: "", 
   ...
   };
   ```
   
   So adding any new field to the struct will be a breaking API change
   
   If we keep them private fields, then we can add new fields without breaking 
existing peopel



##########
arrow-cast/src/pretty.rs:
##########
@@ -131,7 +214,27 @@ pub fn pretty_format_batches_with_options(
     results: &[RecordBatch],
     options: &FormatOptions,
 ) -> Result<impl Display + use<>, ArrowError> {
-    create_table(None, results, options)
+    create_table(None, results, options, None)
+}
+
+/// Create a visual representation of [`RecordBatch`]es with formatting 
options.
+///
+/// # Arguments
+/// * `results` - A slice of record batches to display
+/// * `options` - [`FormatOptions`] that control the resulting display
+/// * `formatters` - A slice of [`ArrayFormatter`]s that control the 
formatting of each column. If
+///   a formatter is [`None`], the default formatter will be used. Must be 
exactly as long as the
+///   number of fields in the record batches.
+///
+/// # Example
+///
+/// For an example, see [`ArrayFormatterFactory`].
+pub fn pretty_format_batches_with_options_and_formatters(
+    results: &[RecordBatch],
+    options: &FormatOptions,
+    formatters: Option<&dyn ArrayFormatterFactory>,

Review Comment:
   Rather than needing a parameter, did you consider adding a new field to 
`FormatOptions`?
   
   ```rust
   struct FormatOptions {
   ...
     formatter_factory: Option<&dyn ArrayFormatterFactory>,
   }
   ```
   
   That would reduce the new APIs and make it easier for existing code to use 
custom formatters (just need to update options)



##########
arrow-cast/src/pretty.rs:
##########
@@ -22,15 +22,98 @@
 //! [`RecordBatch`]: arrow_array::RecordBatch
 //! [`Array`]: arrow_array::Array
 
-use std::fmt::Display;
-
 use comfy_table::{Cell, Table};
+use std::fmt::{Display};
 
 use arrow_array::{Array, ArrayRef, RecordBatch};
-use arrow_schema::{ArrowError, SchemaRef};
+use arrow_schema::{ArrowError, Field, SchemaRef};
 
 use crate::display::{ArrayFormatter, FormatOptions};
 
+/// Allows creating a new [`ArrayFormatter`] for a given [`Array`] and an 
optional [`Field`].
+///
+/// # Example
+///
+/// The example below shows how to create a custom formatter for a custom type 
`my_money`.
+///
+/// ```rust
+/// use std::fmt::Write;
+/// use arrow_array::{Array, Int32Array, cast::AsArray};
+/// use arrow_cast::display::{ArrayFormatter, DisplayIndex, FormatOptions, 
FormatResult};
+/// use 
arrow_cast::pretty::{pretty_format_batches_with_options_and_formatters, 
ArrayFormatterFactory};
+/// use arrow_schema::{ArrowError, Field};
+///
+/// /// A custom formatter factory that can create a formatter for the special 
type `my_money`.
+/// ///
+/// /// This struct could have access to some kind of extension type registry 
that can lookup the
+/// /// correct formatter for an extension type on-demand.
+/// struct MyFormatters {}
+///
+/// impl ArrayFormatterFactory for MyFormatters {
+///     fn create_display_index<'formatter>(
+///         &self,
+///         array: &'formatter dyn Array,
+///         options: &'formatter FormatOptions<'formatter>,
+///         field: Option<&'formatter Field>,
+///     ) -> Result<Option<ArrayFormatter<'formatter>>, ArrowError> {
+///         // check if this is the money type
+///         if field
+///             .map(|f| f.extension_type_name() == Some("my_money"))
+///             .unwrap_or(false)
+///         {
+///             // We assume that my_money always is an Int32.
+///             let array = array.as_primitive();
+///             let display_index = Box::new(MyMoneyFormatter { array, options 
});
+///             return Ok(Some(ArrayFormatter::new(display_index, 
options.safe)));
+///         }
+///
+///         Ok(None) // None indicates that the default formatter should be 
used.
+///     }
+/// }
+///
+/// /// A formatter for the type `my_money` that wraps a specific array and 
has access to the

Review Comment:
   This is great -- thank you



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to