use ascii_table::{AsciiTable, Column, Align};
use structopt::StructOpt;
use std::path::PathBuf;
mod athena;
mod error;
use error::Error;
type Result<T> = std::result::Result<T, error::Error>;
#[derive(StructOpt)]
#[structopt(name = "athenacli")]
struct Config {
#[structopt(short = "r", long = "region", env = "AWS_REGION")]
region: String,
#[structopt(short = "d", long = "database")]
database: String,
#[structopt(short = "b", long = "results")]
pub result_bucket: String,
#[structopt(short = "w", long = "workgroup")]
pub workgroup: Option<String>,
#[structopt(short = "c", long = "command")]
command: Option<String>,
#[structopt(short = "f", long = "file")]
file: Option<PathBuf>,
#[structopt(short = "v", parse(from_occurrences))]
verbose: u64,
}
pub async fn run() -> Result<()> {
let args = Config::from_args();
let log_level = match args.verbose {
0 => "info",
1 => "debug",
_ => "trace"
};
let filter = tracing_subscriber::filter::EnvFilter::try_from_env("ATHENACLI_LOG")
.unwrap_or_else(|_| tracing_subscriber::filter::EnvFilter::new(format!("athenacli={}", log_level)))
.add_directive(tracing_subscriber::filter::LevelFilter::WARN.into());
let subscriber = tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(filter)
.finish();
tracing::subscriber::set_global_default(subscriber)
.expect("setting tracing default failed");
if args.command.is_some() && args.file.is_some() {
tracing::error!("cannot specify both --command and --file!");
std::process::exit(1);
}
if args.command.is_none() && args.file.is_none() {
tracing::error!("must specify either --command or --file!");
std::process::exit(1);
}
let query = match args.file {
Some(ref path) if !path.exists() => {
tracing::error!(path = %path.display(), "input file does not exist");
std::process::exit(1);
},
Some(ref path) => {
let contents = std::fs::read_to_string(path)?;
contents
},
None => args.command.unwrap(),
};
let athena = athena::Athena::new(&args.region, &args.database, &args.result_bucket, args.workgroup.clone())?;
tracing::debug!(
region = %args.region,
database = %args.database,
results_bucket = %args.result_bucket,
workgroup = ?args.workgroup,
"executing query"
);
match athena.query(&query).await {
Ok(result) => {
tracing::info!(
rows = %result.rows,
data_scanned = %result.data_scanned(),
execution_time = %result.total_time(),
"query complete"
);
if result.rows == 0 { return Ok(()); }
let mut table = AsciiTable::default();
for (idx, col) in result.columns.iter().enumerate() {
table.columns.insert(idx, Column {
header: col.into(),
align: Align::Left,
..Default::default()
});
}
table.print(result.data);
Ok(())
},
Err(error) => {
tracing::error!(%error, "error running query");
Err(error)
}
}
}