|  | 
| 15 | 15 | // specific language governing permissions and limitations | 
| 16 | 16 | // under the License. | 
| 17 | 17 | 
 | 
| 18 |  | -use clap::{crate_version, App, Arg}; | 
|  | 18 | +use clap::Parser; | 
| 19 | 19 | use datafusion::error::Result; | 
| 20 | 20 | use datafusion::execution::context::ExecutionConfig; | 
| 21 | 21 | use datafusion_cli::{ | 
| 22 |  | -    context::Context, | 
| 23 |  | -    exec, | 
| 24 |  | -    print_format::{all_print_formats, PrintFormat}, | 
| 25 |  | -    print_options::PrintOptions, | 
|  | 22 | +    context::Context, exec, print_format::PrintFormat, print_options::PrintOptions, | 
| 26 | 23 |     DATAFUSION_CLI_VERSION, | 
| 27 | 24 | }; | 
| 28 | 25 | use std::env; | 
| 29 | 26 | use std::fs::File; | 
| 30 | 27 | use std::io::BufReader; | 
| 31 | 28 | use std::path::Path; | 
| 32 | 29 | 
 | 
|  | 30 | +#[derive(Debug, Parser, PartialEq)] | 
|  | 31 | +#[clap(author, version, about, long_about= None)] | 
|  | 32 | +struct Args { | 
|  | 33 | +    #[clap( | 
|  | 34 | +        short = 'p', | 
|  | 35 | +        long, | 
|  | 36 | +        help = "Path to your data, default to current directory", | 
|  | 37 | +        validator(is_valid_data_dir) | 
|  | 38 | +    )] | 
|  | 39 | +    data_path: Option<String>, | 
|  | 40 | + | 
|  | 41 | +    #[clap( | 
|  | 42 | +        short = 'c', | 
|  | 43 | +        long, | 
|  | 44 | +        help = "The batch size of each query, or use DataFusion default", | 
|  | 45 | +        validator(is_valid_batch_size) | 
|  | 46 | +    )] | 
|  | 47 | +    batch_size: Option<usize>, | 
|  | 48 | + | 
|  | 49 | +    #[clap( | 
|  | 50 | +        short, | 
|  | 51 | +        long, | 
|  | 52 | +        multiple_values = true, | 
|  | 53 | +        help = "Execute commands from file(s), then exit", | 
|  | 54 | +        validator(is_valid_file) | 
|  | 55 | +    )] | 
|  | 56 | +    file: Vec<String>, | 
|  | 57 | + | 
|  | 58 | +    #[clap(long, arg_enum, default_value_t = PrintFormat::Table)] | 
|  | 59 | +    format: PrintFormat, | 
|  | 60 | + | 
|  | 61 | +    #[clap(long, help = "Ballista scheduler host")] | 
|  | 62 | +    host: Option<String>, | 
|  | 63 | + | 
|  | 64 | +    #[clap(long, help = "Ballista scheduler port")] | 
|  | 65 | +    port: Option<u16>, | 
|  | 66 | + | 
|  | 67 | +    #[clap( | 
|  | 68 | +        short, | 
|  | 69 | +        long, | 
|  | 70 | +        help = "Reduce printing other than the results and work quietly" | 
|  | 71 | +    )] | 
|  | 72 | +    quiet: bool, | 
|  | 73 | +} | 
|  | 74 | + | 
| 33 | 75 | #[tokio::main] | 
| 34 | 76 | pub async fn main() -> Result<()> { | 
| 35 |  | -    let matches = App::new("DataFusion") | 
| 36 |  | -        .version(crate_version!()) | 
| 37 |  | -        .about( | 
| 38 |  | -            "DataFusion is an in-memory query engine that uses Apache Arrow \ | 
| 39 |  | -             as the memory model. It supports executing SQL queries against CSV and \ | 
| 40 |  | -             Parquet files as well as querying directly against in-memory data.", | 
| 41 |  | -        ) | 
| 42 |  | -        .arg( | 
| 43 |  | -            Arg::new("data-path") | 
| 44 |  | -                .help("Path to your data, default to current directory") | 
| 45 |  | -                .short('p') | 
| 46 |  | -                .long("data-path") | 
| 47 |  | -                .validator(is_valid_data_dir) | 
| 48 |  | -                .takes_value(true), | 
| 49 |  | -        ) | 
| 50 |  | -        .arg( | 
| 51 |  | -            Arg::new("batch-size") | 
| 52 |  | -                .help("The batch size of each query, or use DataFusion default") | 
| 53 |  | -                .short('c') | 
| 54 |  | -                .long("batch-size") | 
| 55 |  | -                .validator(is_valid_batch_size) | 
| 56 |  | -                .takes_value(true), | 
| 57 |  | -        ) | 
| 58 |  | -        .arg( | 
| 59 |  | -            Arg::new("file") | 
| 60 |  | -                .help("Execute commands from file(s), then exit") | 
| 61 |  | -                .short('f') | 
| 62 |  | -                .long("file") | 
| 63 |  | -                .multiple_occurrences(true) | 
| 64 |  | -                .validator(is_valid_file) | 
| 65 |  | -                .takes_value(true), | 
| 66 |  | -        ) | 
| 67 |  | -        .arg( | 
| 68 |  | -            Arg::new("format") | 
| 69 |  | -                .help("Output format") | 
| 70 |  | -                .long("format") | 
| 71 |  | -                .default_value("table") | 
| 72 |  | -                .possible_values( | 
| 73 |  | -                    &all_print_formats() | 
| 74 |  | -                        .iter() | 
| 75 |  | -                        .map(|format| format.to_string()) | 
| 76 |  | -                        .collect::<Vec<_>>() | 
| 77 |  | -                        .iter() | 
| 78 |  | -                        .map(|i| i.as_str()) | 
| 79 |  | -                        .collect::<Vec<_>>(), | 
| 80 |  | -                ) | 
| 81 |  | -                .takes_value(true), | 
| 82 |  | -        ) | 
| 83 |  | -        .arg( | 
| 84 |  | -            Arg::new("host") | 
| 85 |  | -                .help("Ballista scheduler host") | 
| 86 |  | -                .long("host") | 
| 87 |  | -                .takes_value(true), | 
| 88 |  | -        ) | 
| 89 |  | -        .arg( | 
| 90 |  | -            Arg::new("port") | 
| 91 |  | -                .help("Ballista scheduler port") | 
| 92 |  | -                .long("port") | 
| 93 |  | -                .takes_value(true), | 
| 94 |  | -        ) | 
| 95 |  | -        .arg( | 
| 96 |  | -            Arg::new("quiet") | 
| 97 |  | -                .help("Reduce printing other than the results and work quietly") | 
| 98 |  | -                .short('q') | 
| 99 |  | -                .long("quiet") | 
| 100 |  | -                .takes_value(false), | 
| 101 |  | -        ) | 
| 102 |  | -        .get_matches(); | 
| 103 |  | - | 
| 104 |  | -    let quiet = matches.is_present("quiet"); | 
| 105 |  | - | 
| 106 |  | -    if !quiet { | 
| 107 |  | -        println!("DataFusion CLI v{}\n", DATAFUSION_CLI_VERSION); | 
| 108 |  | -    } | 
|  | 77 | +    let args = Args::parse(); | 
| 109 | 78 | 
 | 
| 110 |  | -    let host = matches.value_of("host"); | 
| 111 |  | -    let port = matches | 
| 112 |  | -        .value_of("port") | 
| 113 |  | -        .and_then(|port| port.parse::<u16>().ok()); | 
|  | 79 | +    if !args.quiet { | 
|  | 80 | +        println!("DataFusion CLI v{}", DATAFUSION_CLI_VERSION); | 
|  | 81 | +    } | 
| 114 | 82 | 
 | 
| 115 |  | -    if let Some(path) = matches.value_of("data-path") { | 
|  | 83 | +    if let Some(ref path) = args.data_path { | 
| 116 | 84 |         let p = Path::new(path); | 
| 117 | 85 |         env::set_current_dir(&p).unwrap(); | 
| 118 | 86 |     }; | 
| 119 | 87 | 
 | 
| 120 | 88 |     let mut execution_config = ExecutionConfig::new().with_information_schema(true); | 
| 121 | 89 | 
 | 
| 122 |  | -    if let Some(batch_size) = matches | 
| 123 |  | -        .value_of("batch-size") | 
| 124 |  | -        .and_then(|size| size.parse::<usize>().ok()) | 
| 125 |  | -    { | 
|  | 90 | +    if let Some(batch_size) = args.batch_size { | 
| 126 | 91 |         execution_config = execution_config.with_batch_size(batch_size); | 
| 127 | 92 |     }; | 
| 128 | 93 | 
 | 
| 129 |  | -    let mut ctx: Context = match (host, port) { | 
| 130 |  | -        (Some(h), Some(p)) => Context::new_remote(h, p)?, | 
|  | 94 | +    let mut ctx: Context = match (args.host, args.port) { | 
|  | 95 | +        (Some(ref h), Some(p)) => Context::new_remote(h, p)?, | 
| 131 | 96 |         _ => Context::new_local(&execution_config), | 
| 132 | 97 |     }; | 
| 133 | 98 | 
 | 
| 134 |  | -    let format = matches | 
| 135 |  | -        .value_of("format") | 
| 136 |  | -        .expect("No format is specified") | 
| 137 |  | -        .parse::<PrintFormat>() | 
| 138 |  | -        .expect("Invalid format"); | 
| 139 |  | - | 
| 140 |  | -    let mut print_options = PrintOptions { format, quiet }; | 
|  | 99 | +    let mut print_options = PrintOptions { | 
|  | 100 | +        format: args.format, | 
|  | 101 | +        quiet: args.quiet, | 
|  | 102 | +    }; | 
| 141 | 103 | 
 | 
| 142 |  | -    if let Some(file_paths) = matches.values_of("file") { | 
| 143 |  | -        let files = file_paths | 
|  | 104 | +    let files = args.file; | 
|  | 105 | +    if !files.is_empty() { | 
|  | 106 | +        let files = files | 
|  | 107 | +            .into_iter() | 
| 144 | 108 |             .map(|file_path| File::open(file_path).unwrap()) | 
| 145 | 109 |             .collect::<Vec<_>>(); | 
| 146 | 110 |         for file in files { | 
|  | 
0 commit comments