@@ -33,6 +33,14 @@ pub fn cli() -> clap::Command {
3333 . arg ( common_args:: confirmed ( ) )
3434 . arg ( common_args:: anonymous ( ) )
3535 . arg ( common_args:: server ( ) . help ( "The nickname, host name or URL of the server hosting the database" ) )
36+ . arg (
37+ Arg :: new ( "format" )
38+ . long ( "format" )
39+ . default_value ( "text" )
40+ . required ( false )
41+ . value_parser ( clap:: value_parser!( Format ) )
42+ . help ( "Output format for the SQL results" ) ,
43+ )
3644 . arg ( common_args:: yes ( ) )
3745 . arg (
3846 Arg :: new ( "no_config" )
@@ -42,6 +50,25 @@ pub fn cli() -> clap::Command {
4250 )
4351}
4452
53+ #[ derive( Clone , Copy , PartialEq ) ]
54+ pub ( crate ) enum Format {
55+ Text ,
56+ Json ,
57+ }
58+
59+ impl clap:: ValueEnum for Format {
60+ fn value_variants < ' a > ( ) -> & ' a [ Self ] {
61+ & [ Self :: Text , Self :: Json ]
62+ }
63+
64+ fn to_possible_value ( & self ) -> Option < clap:: builder:: PossibleValue > {
65+ match self {
66+ Self :: Text => Some ( clap:: builder:: PossibleValue :: new ( "text" ) . aliases ( [ "default" , "txt" ] ) ) ,
67+ Self :: Json => Some ( clap:: builder:: PossibleValue :: new ( "json" ) ) ,
68+ }
69+ }
70+ }
71+
4572pub ( crate ) async fn parse_req (
4673 mut config : Config ,
4774 args : & ArgMatches ,
@@ -143,7 +170,12 @@ fn print_stmt_result(
143170 Ok ( ( ) )
144171}
145172
146- pub ( crate ) async fn run_sql ( builder : RequestBuilder , sql : & str , with_stats : bool ) -> Result < ( ) , anyhow:: Error > {
173+ pub ( crate ) async fn run_sql (
174+ builder : RequestBuilder ,
175+ sql : & str ,
176+ with_stats : bool ,
177+ format : Format ,
178+ ) -> Result < ( ) , anyhow:: Error > {
147179 let now = Instant :: now ( ) ;
148180
149181 let json = builder
@@ -155,6 +187,11 @@ pub(crate) async fn run_sql(builder: RequestBuilder, sql: &str, with_stats: bool
155187 . text ( )
156188 . await ?;
157189
190+ if format == Format :: Json {
191+ println ! ( "{json}" ) ;
192+ return Ok ( ( ) ) ;
193+ }
194+
158195 let stmt_result_json: Vec < SqlStmtResult > = serde_json:: from_str ( & json) . context ( "malformed sql response" ) ?;
159196
160197 let mut out = String :: new ( ) ;
@@ -182,6 +219,7 @@ pub async fn exec(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error
182219 eprintln ! ( "{UNSTABLE_WARNING}\n " ) ;
183220 let interactive = args. get_one :: < bool > ( "interactive" ) . unwrap_or ( & false ) ;
184221 let no_config = args. get_flag ( "no_config" ) ;
222+ let format = * args. get_one :: < Format > ( "format" ) . unwrap ( ) ;
185223 let raw_parts: Vec < String > = args
186224 . get_many :: < String > ( "sql_parts" )
187225 . map ( |vals| vals. cloned ( ) . collect ( ) )
@@ -201,7 +239,7 @@ pub async fn exec(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error
201239 ) ?;
202240 let con = parse_req ( config, args, & resolved. database , resolved. server . as_deref ( ) ) . await ?;
203241
204- crate :: repl:: exec ( con) . await ?;
242+ crate :: repl:: exec ( con, format ) . await ?;
205243 } else {
206244 let resolved = resolve_optional_database_parts (
207245 & raw_parts,
@@ -243,7 +281,7 @@ pub async fn exec(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error
243281 api = api. query ( & [ ( "confirmed" , if confirmed { "true" } else { "false" } ) ] ) ;
244282 }
245283
246- run_sql ( api, & query, false ) . await ?;
284+ run_sql ( api, & query, false , format ) . await ?;
247285 }
248286 Ok ( ( ) )
249287}
0 commit comments