4646from cqlshlib import cql3handling , pylexotron , sslhandling , cqlshhandling , authproviderhandling
4747from cqlshlib .copyutil import ExportTask , ImportTask
4848from cqlshlib .displaying import (ANSI_RESET , BLUE , COLUMN_NAME_COLORS , CYAN ,
49- RED , WHITE , FormattedValue , colorme )
49+ RED , WHITE , FormattedValue , colorme ,
50+ TablePrinter , TabularTablePrinter , CsvTablePrinter , JsonTablePrinter )
5051from cqlshlib .formatting import (DEFAULT_DATE_FORMAT , DEFAULT_NANOTIME_FORMAT ,
5152 DEFAULT_TIMESTAMP_FORMAT , CqlType , DateTimeFormat ,
5253 format_by_type )
@@ -284,13 +285,15 @@ def __init__(self, hostname, port, config_file, color=False,
284285 connect_timeout = DEFAULT_CONNECT_TIMEOUT_SECONDS ,
285286 is_subshell = False ,
286287 auth_provider = None ,
287- disable_history = False ):
288+ disable_history = False ,
289+ mode = 'tabular' ):
288290 cmd .Cmd .__init__ (self , completekey = completekey )
289291 self .hostname = hostname
290292 self .port = port
291293 self .auth_provider = auth_provider
292294 self .username = username
293295 self .config_file = config_file
296+ self .mode = mode .lower ()
294297
295298 if isinstance (auth_provider , PlainTextAuthProvider ):
296299 self .username = auth_provider .username
@@ -329,6 +332,8 @@ def __init__(self, hostname, port, config_file, color=False,
329332 self .browser = browser
330333 self .docspath = docspath
331334 self .color = color
335+ if self .mode in ('csv' , 'json' ):
336+ self .color = False
332337
333338 self .display_nanotime_format = display_nanotime_format
334339 self .display_timestamp_format = display_timestamp_format
@@ -946,42 +951,55 @@ def perform_simple_statement(self, statement):
946951 self .print_result (result , self .get_table_meta ('system_auth' , 'generated_values' ))
947952 elif result :
948953 # CAS INSERT/UPDATE
949- self .writeresult ("" )
950- self .print_static_result (result , self .parse_for_update_meta (statement .query_string ), with_header = True , tty = self .tty )
954+ if self .mode not in ('csv' , 'json' ):
955+ self .writeresult ("" )
956+ cas_printer = TablePrinter .factory (self .mode , self )
957+ self .print_static_result (result , self .parse_for_update_meta (statement .query_string ),
958+ with_header = True , tty = self .tty ,
959+ printer = cas_printer )
960+ cas_printer .finish ()
951961 if self .elapsed_enabled :
952- self .writeresult ("(%dms elapsed)" % elapsed )
962+ elapsed_msg = "(%dms elapsed)" % elapsed
963+ if self .mode in ('csv' , 'json' ):
964+ self .printerr (elapsed_msg )
965+ else :
966+ self .writeresult (elapsed_msg )
953967 self .flush_output ()
954968 return True , future
955969
956970 def print_result (self , result , table_meta ):
957971 self .decoding_errors = []
958972
959- self .writeresult ("" )
973+ if self .mode not in ('csv' , 'json' ):
974+ self .writeresult ("" )
975+ printer = TablePrinter .factory (self .mode , self )
960976
961- def print_all (result , table_meta , tty ):
962- # Return the number of rows in total
977+ def print_all (result , table_meta , tty , printer ):
978+ machine_mode = self .mode in ('csv' , 'json' )
979+ effective_tty = tty and not machine_mode
963980 num_rows = 0
964981 is_first = True
965982 while True :
966- # Always print for the first page even it is empty
967983 if result .current_rows or is_first :
968- with_header = is_first or tty
969- self .print_static_result (result , table_meta , with_header , tty , num_rows )
984+ with_header = is_first or effective_tty
985+ self .print_static_result (result , table_meta , with_header , effective_tty ,
986+ num_rows , printer )
970987 num_rows += len (result .current_rows )
971988 if result .has_more_pages :
972- if self .shunted_query_out is None and tty :
973- # Only pause when not capturing.
989+ if self .shunted_query_out is None and effective_tty :
974990 input ("---MORE---" )
975991 result .fetch_next_page ()
976992 else :
977- if not tty :
993+ if not effective_tty and not machine_mode :
978994 self .writeresult ("" )
979995 break
980996 is_first = False
981997 return num_rows
982998
983- num_rows = print_all (result , table_meta , self .tty )
984- self .writeresult ("(%d rows)" % num_rows )
999+ num_rows = print_all (result , table_meta , self .tty , printer )
1000+ printer .finish ()
1001+ if self .mode not in ('csv' , 'json' ):
1002+ self .writeresult ("(%d rows)" % num_rows )
9851003
9861004 if self .decoding_errors :
9871005 for err in self .decoding_errors [:2 ]:
@@ -990,15 +1008,16 @@ def print_all(result, table_meta, tty):
9901008 self .writeresult ('%d more decoding errors suppressed.'
9911009 % (len (self .decoding_errors ) - 2 ), color = RED )
9921010
993- def print_static_result (self , result , table_meta , with_header , tty , row_count_offset = 0 ):
1011+ def print_static_result (self , result , table_meta , with_header , tty , row_count_offset = 0 , printer = None ):
9941012 if not result .column_names and not table_meta :
9951013 return
9961014
9971015 column_names = result .column_names or list (table_meta .columns .keys ())
9981016 formatted_names = [self .myformat_colname (name , table_meta ) for name in column_names ]
1017+
9991018 if not result .current_rows :
1000- # print header only
1001- self . print_formatted_result ( formatted_names , None , with_header = True , tty = tty )
1019+ if with_header :
1020+ printer . print_header ( formatted_names )
10021021 return
10031022
10041023 cql_types = []
@@ -1009,10 +1028,9 @@ def print_static_result(self, result, table_meta, with_header, tty, row_count_of
10091028
10101029 formatted_values = [list (map (self .myformat_value , [row [c ] for c in column_names ], cql_types )) for row in result .current_rows ]
10111030
1012- if self .expand_enabled :
1013- self .print_formatted_result_vertically (formatted_names , formatted_values , row_count_offset )
1014- else :
1015- self .print_formatted_result (formatted_names , formatted_values , with_header , tty )
1031+ if with_header :
1032+ printer .print_header (formatted_names )
1033+ printer .print_rows (formatted_names , formatted_values )
10161034
10171035 def print_formatted_result (self , formatted_names , formatted_values , with_header , tty ):
10181036 # determine column widths
@@ -2026,6 +2044,7 @@ def read_options(cmdlineargs, parser, config_file, cql_dir, environment=os.envir
20262044 argvalues .completekey = option_with_default (configs .get , 'ui' , 'completekey' ,
20272045 DEFAULT_COMPLETEKEY )
20282046 argvalues .color = option_with_default (configs .getboolean , 'ui' , 'color' )
2047+ argvalues .mode = option_with_default (configs .get , 'ui' , 'mode' , 'tabular' )
20292048 argvalues .time_format = raw_option_with_default (configs , 'ui' , 'time_format' ,
20302049 DEFAULT_TIMESTAMP_FORMAT )
20312050 argvalues .nanotime_format = raw_option_with_default (configs , 'ui' , 'nanotime_format' ,
@@ -2230,6 +2249,8 @@ def main(cmdline, pkgpath):
22302249 help = 'Force tty mode (command prompt).' )
22312250 parser .add_argument ('--disable-history' , default = False , action = 'store_true' ,
22322251 help = 'Disable saving of history (existing history will still be loaded)' )
2252+ parser .add_argument ('--mode' , choices = ['tabular' , 'csv' , 'json' ],
2253+ help = 'Specify the output format (tabular, csv, json). Default is tabular.' )
22332254
22342255 # This is a hidden option to suppress the warning when the -p/--password command line option is used.
22352256 # Power users may use this option if they know no other people has access to the system where cqlsh is run or don't care about security.
@@ -2357,6 +2378,7 @@ def main(cmdline, pkgpath):
23572378 display_double_precision = options .double_precision ,
23582379 display_timezone = timezone ,
23592380 max_trace_wait = options .max_trace_wait ,
2381+ mode = options .mode ,
23602382 ssl = options .ssl ,
23612383 single_statement = options .execute ,
23622384 request_timeout = options .request_timeout ,
0 commit comments