@@ -9,13 +9,45 @@ use datafusion_variant::{
99 VariantToJsonUdf ,
1010} ;
1111use flate2:: read:: GzDecoder ;
12- use rustyline:: DefaultEditor ;
1312use rustyline:: error:: ReadlineError ;
13+ use rustyline:: validate:: { ValidationContext , ValidationResult , Validator } ;
14+ use rustyline:: { Completer , Config , Editor , Helper , Highlighter , Hinter } ;
1415use std:: fs:: File ;
1516use std:: io:: { self , BufRead , BufReader , Write } ;
1617use std:: sync:: Arc ;
1718use std:: time:: Instant ;
1819
20+ /// Helper for rustyline that provides multi-line SQL query support
21+ #[ derive( Helper , Completer , Highlighter , Hinter , Default ) ]
22+ struct SqlHelper ;
23+
24+ impl Validator for SqlHelper {
25+ fn validate ( & self , ctx : & mut ValidationContext ) -> rustyline:: Result < ValidationResult > {
26+ let input = ctx. input ( ) ;
27+
28+ // Check if query is complete (ends with semicolon)
29+ if is_complete_query ( input) {
30+ Ok ( ValidationResult :: Valid ( None ) )
31+ } else {
32+ Ok ( ValidationResult :: Incomplete )
33+ }
34+ }
35+ }
36+
37+ fn is_complete_query ( input : & str ) -> bool {
38+ let trimmed = input. trim ( ) ;
39+
40+ if trimmed. is_empty ( ) {
41+ return true ;
42+ }
43+
44+ if trimmed == "quit" || trimmed == "q" {
45+ return true ;
46+ }
47+
48+ trimmed. ends_with ( ';' )
49+ }
50+
1951#[ tokio:: main]
2052async fn main ( ) -> Result < ( ) > {
2153 // todo: we can let users pass in arbitrary files to load
@@ -97,9 +129,14 @@ async fn main() -> Result<()> {
97129 } ;
98130
99131 println ! ( "interactive query mode. type 'q' or 'quit' or ctrl+c to exit" ) ;
100- println ! ( "Available table: bsky (json_data: Utf8)\n " ) ;
132+ println ! ( "Available table: bsky (json_data: Utf8)" ) ;
133+ println ! ( "Tip: Press Enter without ';' to continue query on next line\n " ) ;
134+
135+ let config = Config :: builder ( ) . auto_add_history ( true ) . build ( ) ;
136+ let helper = SqlHelper :: default ( ) ;
101137
102- let mut rl = DefaultEditor :: new ( ) ?;
138+ let mut rl = Editor :: with_config ( config) ?;
139+ rl. set_helper ( Some ( helper) ) ;
103140
104141 loop {
105142 let readline = rl. readline ( "> " ) ;
@@ -117,8 +154,6 @@ async fn main() -> Result<()> {
117154 break ;
118155 }
119156
120- rl. add_history_entry ( & line) ?;
121-
122157 if let Err ( e) = run_query ( & ctx, query) . await {
123158 eprintln ! ( "\x1b [31;1merror:\x1b [0m {}" , e) ;
124159 }
0 commit comments