diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/mod.rs | 1 | ||||
-rw-r--r-- | src/cmd/sql.rs | 77 |
2 files changed, 78 insertions, 0 deletions
diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index d086d5b..a25e955 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -1 +1,2 @@ +pub mod sql; pub mod sync; diff --git a/src/cmd/sql.rs b/src/cmd/sql.rs new file mode 100644 index 0000000..ae398b5 --- /dev/null +++ b/src/cmd/sql.rs @@ -0,0 +1,77 @@ +use db; +use paths; + +pub fn run(query: &str, tsv: bool) -> failure::Fallible<()> { + let db = db::DB::new(&paths::db_path()?)?; + + let rows_cell = std::cell::Cell::new(Some(vec![])); + let cols = db.query(query, |row| { + let display_row: Vec<String> = (0..row.column_count()) + .map(|i| row.get_raw(i)) + .map(|v| format_value(&v)) + .collect(); + let mut rows = rows_cell.replace(None).unwrap(); + rows.push(display_row); + rows_cell.replace(Some(rows)); + })?; + + let rows = rows_cell.into_inner().unwrap(); + + if tsv { + print_tsv(&rows); + } + else { + print_table(&cols, &rows); + } + + Ok(()) +} + +fn print_table(cols: &[String], rows: &[Vec<String>]) { + let widths = column_widths(&cols, &rows); + + print_row(&widths, &cols); + let border: Vec<String> = widths.iter().map(|l| "-".repeat(*l)).collect(); + println!("{}", &border.join("-+-")); + + for row in rows { + print_row(&widths, &row); + } +} + +fn print_tsv(rows: &[Vec<String>]) { + for row in rows { + println!("{}", row.join("\t")); + } +} + +fn format_value(v: &rusqlite::types::ValueRef) -> String { + match v { + rusqlite::types::ValueRef::Null => "null".to_string(), + rusqlite::types::ValueRef::Integer(i) => format!("{}", i), + rusqlite::types::ValueRef::Real(f) => format!("{}", f), + rusqlite::types::ValueRef::Text(s) => format!("{}", s), + rusqlite::types::ValueRef::Blob(b) => format!("{:?}", b), + } +} + +fn column_widths(cols: &[String], rows: &[Vec<String>]) -> Vec<usize> { + let mut max_widths: Vec<usize> = cols.iter().map(|s| s.len()).collect(); + for row in rows { + for (i, col) in row.iter().enumerate() { + if col.len() > max_widths[i] { + max_widths[i] = col.len(); + } + } + } + max_widths +} + +fn print_row(widths: &[usize], row: &[String]) { + let fixed_width_row: Vec<String> = row + .iter() + .zip(widths.iter()) + .map(|(s, width)| format!("{:width$}", s, width=width)) + .collect(); + println!("{}", &fixed_width_row.join(" | ")); +} |