@@ -2,7 +2,8 @@ use std::fmt::Debug;
22use std:: fmt;
33use chrono:: { Duration , NaiveDate , NaiveTime , TimeZone , Utc } ;
44use scylla_cql:: frame:: value:: { CqlDate , CqlDecimal , CqlDuration , CqlTime , CqlTimestamp , CqlTimeuuid } ;
5- use tabled:: settings:: Alignment ;
5+ use tabled:: settings:: peaker:: Priority ;
6+ use tabled:: settings:: { Alignment , Width } ;
67use tabled:: { builder:: Builder , settings:: Style , settings:: themes:: Colorization , settings:: Color } ;
78
89use thiserror:: Error ;
@@ -456,10 +457,43 @@ impl QueryRowsResult {
456457 }
457458}
458459
460+ /// A utility struct for displaying rows received from the database in a [`QueryRowsResult`].
461+ ///
462+ /// This struct provides methods to configure the display settings and format the rows
463+ /// as a table for easier visualization. It supports various display settings such as
464+ /// terminal width, color usage, and formatting of different CQL value types.
465+ ///
466+ /// # Example
467+ ///
468+ /// ```rust
469+ /// # use scylla::transport::query_result::{QueryResult, QueryRowsResult, RowsDisplayer};
470+ /// # fn example(query_result: QueryResult) -> Result<(), Box<dyn std::error::Error>> {
471+ /// let rows_result = query_result.into_rows_result()?;
472+ /// let mut displayer = RowsDisplayer::new(&rows_result);
473+ /// displayer.set_terminal_width(80);
474+ /// displayer.use_color(true);
475+ /// println!("{}", displayer);
476+ /// # Ok(())
477+ /// # }
478+ /// ```
479+ ///
480+ /// # Methods
481+ ///
482+ /// - `new(query_result: &'a QueryRowsResult) -> Self`
483+ /// Creates a new `RowsDisplayer` for the given `QueryRowsResult`.
484+ ///
485+ /// - `set_terminal_width(&mut self, terminal_width: usize)`
486+ /// Sets the terminal width for wrapping the table output.
487+ ///
488+ /// - `use_color(&mut self, use_color: bool)`
489+ /// Enables or disables color in the table output.
490+ ///
491+ /// - `fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result`
492+ /// Formats the rows as a table and writes it to the given formatter.
493+
459494pub struct RowsDisplayer < ' a > {
460495 query_result : & ' a QueryRowsResult ,
461496 display_settings : RowsDisplayerSettings ,
462- terminal_width : usize ,
463497}
464498
465499impl < ' a > RowsDisplayer < ' a >
@@ -468,12 +502,15 @@ impl<'a> RowsDisplayer<'a>
468502 Self {
469503 query_result,
470504 display_settings : RowsDisplayerSettings :: new ( ) ,
471- terminal_width : 80 ,
472505 }
473506 }
474507
475508 pub fn set_terminal_width ( & mut self , terminal_width : usize ) {
476- self . terminal_width = terminal_width;
509+ self . display_settings . terminal_width = terminal_width;
510+ }
511+
512+ pub fn use_color ( & mut self , use_color : bool ) {
513+ self . display_settings . print_in_color = use_color;
477514 }
478515
479516
@@ -566,6 +603,101 @@ impl<'a> RowsDisplayer<'a>
566603
567604}
568605
606+ impl fmt:: Display for RowsDisplayer < ' _ > {
607+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
608+ let row_iter : TypedRowIterator < ' _ , ' _ , Row > = match self . query_result . rows :: < Row > ( ) {
609+ Ok ( row_iter) => row_iter,
610+ Err ( _) => return write ! ( f, "Error" ) ,
611+ } ;
612+
613+ // put columns names to the table
614+ let column_names : Vec < & str > = self . query_result . column_specs ( ) . iter ( ) . map ( |column_spec| column_spec. name ( ) ) . collect ( ) ;
615+ let mut builder: Builder = Builder :: new ( ) ;
616+ builder. push_record ( column_names) ;
617+
618+ // put rows to the table
619+ for row_result in row_iter {
620+ let row_result : Row = match row_result {
621+ Ok ( row_result) => row_result,
622+ Err ( _) => return write ! ( f, "Error" ) ,
623+ } ;
624+ let columns : Vec < std:: option:: Option < CqlValue > > = row_result. columns ;
625+ let mut row_values: Vec < Box < dyn StringConvertible > > = Vec :: new ( ) ;
626+ for item in & columns {
627+ let wrapper = self . get_item_wrapper ( item) ;
628+ row_values. push ( wrapper) ;
629+ }
630+ builder. push_record ( row_values) ;
631+ }
632+
633+ let mut table = builder. build ( ) ;
634+
635+ let mut table = table. with ( Style :: psql ( ) ) ;
636+ table = table. with ( Alignment :: right ( ) ) ;
637+ if self . display_settings . terminal_width != 0 {
638+ table = table. with ( Width :: wrap ( self . display_settings . terminal_width ) . priority ( Priority :: max ( true ) ) ) ;
639+ }
640+
641+ if self . display_settings . print_in_color {
642+ let colum_colors: Vec < Color > = self . query_result . column_specs ( ) . iter ( ) . map ( |column_spec|
643+ if * column_spec. typ ( ) == ColumnType :: Text {
644+ Color :: FG_YELLOW
645+ }
646+ else if * column_spec. typ ( ) == ColumnType :: Blob {
647+ Color :: FG_MAGENTA
648+ }
649+ else {
650+ Color :: FG_GREEN
651+ }
652+ ) . collect ( ) ;
653+
654+ table = table. with ( Colorization :: columns ( colum_colors) )
655+ . with ( Colorization :: exact ( [ Color :: FG_MAGENTA ] , tabled:: settings:: object:: Rows :: first ( ) ) ) ;
656+ }
657+
658+ write ! ( f, "{}" , table)
659+ }
660+ }
661+
662+
663+
664+ /// Settings for displaying rows in a `RowsDisplayer`.
665+ ///
666+ /// This struct holds various configuration options for formatting and displaying
667+ /// rows received from the database. It includes settings for byte display format,
668+ /// exponent display for floats and integers, precision for doubles, color usage,
669+ /// and terminal width for wrapping the table output.
670+ struct RowsDisplayerSettings {
671+ byte_displaying : ByteDisplaying , // for blobs
672+ exponent_displaying_floats : bool , // for floats
673+ exponent_displaying_integers : bool , // for integers
674+ double_precision : usize , // for doubles
675+ print_in_color : bool ,
676+ terminal_width : usize ,
677+ }
678+
679+ impl RowsDisplayerSettings {
680+ fn new ( ) -> Self { // TODO write Default trait
681+ Self {
682+ byte_displaying : ByteDisplaying :: Hex ,
683+ exponent_displaying_floats : false ,
684+ exponent_displaying_integers : false ,
685+ double_precision : 5 ,
686+ print_in_color : true ,
687+ terminal_width : 0 ,
688+ }
689+ }
690+ }
691+
692+
693+
694+ #[ derive( PartialEq ) ]
695+ enum ByteDisplaying {
696+ Ascii ,
697+ Hex ,
698+ Dec ,
699+ }
700+
569701// wrappers for scylla datatypes implementing Display
570702
571703struct WrapperDisplay < ' a , T : ' a > {
@@ -597,7 +729,6 @@ impl<'a> From<Box<dyn StringConvertible<'a>>> for String {
597729
598730impl < ' a > From < & dyn StringConvertible < ' a > > for String {
599731 fn from ( wrapper : & dyn StringConvertible < ' a > ) -> Self {
600- // println!("before &dyn StringConvertible<'a>");
601732 wrapper. into ( )
602733 }
603734}
@@ -608,7 +739,6 @@ where
608739 WrapperDisplay < ' a , T > : fmt:: Display ,
609740{
610741 fn from ( wrapper : WrapperDisplay < ' a , T > ) -> Self {
611- // println!("before WrapperDisplay<'a, T>");
612742 format ! ( "{}" , wrapper)
613743 }
614744}
@@ -847,11 +977,9 @@ impl fmt::Display for WrapperDisplay<'_, CqlDate> {
847977 // around -250000-01-01 is the limit of naive date
848978
849979 let days = self . value . 0 - magic_constant;
850- println ! ( "days: {}" , days) ;
851980 let base_date = NaiveDate :: from_ymd_opt ( -250000 , 1 , 1 ) . unwrap ( ) ;
852981
853982 // Add the number of days
854- println ! ( "days as i64: {}" , days as i64 ) ;
855983 let target_date = base_date + Duration :: days ( days as i64 ) ;
856984
857985 // Format the date
@@ -876,84 +1004,6 @@ impl fmt::Display for WrapperDisplay<'_, std::net::IpAddr> {
8761004}
8771005
8781006
879-
880-
881- impl fmt:: Display for RowsDisplayer < ' _ > {
882- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
883- let row_iter : TypedRowIterator < ' _ , ' _ , Row > = match self . query_result . rows :: < Row > ( ) {
884- Ok ( row_iter) => row_iter,
885- Err ( _) => return write ! ( f, "Error" ) ,
886- } ;
887-
888- // put columns names to the table
889- let column_names : Vec < & str > = self . query_result . column_specs ( ) . iter ( ) . map ( |column_spec| column_spec. name ( ) ) . collect ( ) ;
890- let mut builder: Builder = Builder :: new ( ) ;
891- builder. push_record ( column_names) ;
892-
893- // put rows to the table
894- for row_result in row_iter {
895- // println!("row");
896- let row_result : Row = match row_result {
897- Ok ( row_result) => row_result,
898- Err ( _) => return write ! ( f, "Error" ) ,
899- } ;
900- let columns : Vec < std:: option:: Option < CqlValue > > = row_result. columns ;
901- let mut row_values: Vec < Box < dyn StringConvertible > > = Vec :: new ( ) ;
902- for item in & columns {
903- let wrapper = self . get_item_wrapper ( item) ;
904- row_values. push ( wrapper) ;
905- }
906- builder. push_record ( row_values) ;
907- }
908-
909- // write table to the formatter
910- let mut table = builder. build ( ) ;
911- table. with ( Style :: psql ( ) )
912- // Width::wrap(self.terminal_width).priority(Priority::max(true)),
913- . with ( Colorization :: columns ( [ Color :: FG_GREEN ] ) )
914- . with ( Colorization :: exact ( [ Color :: FG_MAGENTA ] , tabled:: settings:: object:: Rows :: first ( ) ) )
915- . with ( Alignment :: right ( ) ) ;
916-
917- write ! ( f, "{}" , table)
918- }
919- }
920-
921- struct RowsDisplayerSettings {
922- byte_displaying : ByteDisplaying , // for blobs
923- exponent_displaying_floats : bool , // for floats
924- exponent_displaying_integers : bool , // for integers
925- double_precision : usize , // for doubles
926- }
927-
928- impl RowsDisplayerSettings {
929- fn new ( ) -> Self { // TODO write Default trait
930- Self {
931- byte_displaying : ByteDisplaying :: Hex ,
932- exponent_displaying_floats : false ,
933- exponent_displaying_integers : false ,
934- double_precision : 5 ,
935- }
936- }
937-
938- fn set_byte_displaying ( & mut self , byte_displaying : ByteDisplaying ) {
939- self . byte_displaying = byte_displaying;
940- }
941-
942- fn set_exponent_displaying_floats ( & mut self , exponent_displaying_floats : bool ) {
943- self . exponent_displaying_floats = exponent_displaying_floats;
944- }
945-
946- fn set_exponent_displaying_integers ( & mut self , exponent_displaying_integers : bool ) {
947- self . exponent_displaying_integers = exponent_displaying_integers;
948- }
949- }
950-
951- #[ derive( PartialEq ) ]
952- enum ByteDisplaying {
953- Ascii ,
954- Hex ,
955- Dec ,
956- }
9571007/// An error returned by [`QueryResult::into_rows_result`]
9581008///
9591009/// The `ResultNotRows` variant contains original [`QueryResult`],
0 commit comments