odbc_common/
print_table.rs

1use anyhow::anyhow;
2use nu_protocol::Config;
3use nu_table::Table;
4use nu_table::{Alignments, StyledString, TableTheme, TextStyle};
5use odbc_api::buffers::TextRowSet;
6use odbc_api::Cursor;
7use std::collections::HashMap;
8
9pub trait Print: Sized {
10    fn print_all_tables(self) -> anyhow::Result<()> {
11        let p = self.table_string()?;
12        debug!("\n{}", p);
13        Ok(())
14    }
15
16    fn convert_table(self) -> anyhow::Result<Table>;
17
18    fn table_string(self) -> anyhow::Result<String> {
19        let table = self.convert_table()?;
20        let cfg = Config::default();
21        let styles = HashMap::default();
22        let alignments = Alignments::default();
23
24        let p = table
25            .draw_table(&cfg, &styles, alignments, usize::MAX)
26            .ok_or_else(|| anyhow!("convert table to string error"))?;
27        Ok(p)
28    }
29}
30
31const BATCH_SIZE: usize = 128;
32
33/// Print Cursor output to table.E.g:
34/// ```bash
35/// > run you code...
36/// ╭────┬────────────┬────────────────────────────┬────────────────────────────╮
37/// │ id │   name     │         created_at         │         updated_at         │
38/// ├────┼────────────┼────────────────────────────┼────────────────────────────┤
39/// │ 1  │   hallo    │ 2022-08-24 15:50:36.000000 │ 2022-08-24 15:50:36.000000 │
40/// ╰────┴────────────┴────────────────────────────┴────────────────────────────╯
41// ```
42///
43impl<T> Print for T
44where
45    T: Cursor,
46{
47    fn convert_table(mut self) -> anyhow::Result<Table> {
48        let headers: Vec<StyledString> = self
49            .column_names()?
50            .collect::<Result<Vec<String>, _>>()?
51            .into_iter()
52            .map(|x| StyledString::new(x, TextStyle::default_header()))
53            .collect();
54
55        // Use schema in cursor to initialize a text buffer large enough to hold the largest
56        // possible strings for each column up to an upper limit of 4KiB.
57        let mut buffers = TextRowSet::for_cursor(BATCH_SIZE, &mut self, Some(4096))?;
58        // Bind the buffer to the cursor. It is now being filled with every call to fetch.
59        let mut row_set_cursor = self.bind_buffer(&mut buffers)?;
60        let mut rows = vec![];
61        // Iterate over batches
62        while let Some(batch) = row_set_cursor.fetch()? {
63            // Within a batch, iterate over every row
64            for row_index in 0..batch.num_rows() {
65                // Within a row iterate over every column
66                let row_data = (0..batch.num_cols())
67                    .map(|col_index| batch.at(col_index, row_index).unwrap_or(&[]))
68                    .into_iter()
69                    .map(|x| String::from_utf8_lossy(x).to_string())
70                    .map(|x| StyledString::new(x, TextStyle::basic_left()))
71                    .collect();
72                rows.push(row_data);
73            }
74        }
75        let table = Table::new(headers, rows, TableTheme::rounded());
76
77        Ok(table)
78    }
79}