1use std::io::Write;
2
3use arrow_array::RecordBatch;
4use arrow_schema::SchemaRef;
5use comfy_table::{Table, presets};
6
7use crate::Result;
8use crate::cli::BinaryFormat;
9use crate::output::{RowWriter, value};
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum TableStyle {
13 Pretty,
14 Plain,
15}
16
17pub struct TableRowWriter<W: Write> {
24 writer: W,
25 binary_format: BinaryFormat,
26 table_style: TableStyle,
27 schema: Option<SchemaRef>,
28 rows: Vec<Vec<String>>,
29}
30
31impl<W: Write> TableRowWriter<W> {
32 pub fn new(writer: W, binary_format: BinaryFormat, table_style: TableStyle) -> Self {
33 Self {
34 writer,
35 binary_format,
36 table_style,
37 schema: None,
38 rows: Vec::new(),
39 }
40 }
41}
42
43impl<W: Write> RowWriter for TableRowWriter<W> {
44 fn start(&mut self, schema: &SchemaRef) -> Result<()> {
45 self.schema = Some(schema.clone());
46 Ok(())
47 }
48
49 fn write_batch(&mut self, batch: &RecordBatch) -> Result<()> {
50 let rows = (0..batch.num_rows())
51 .map(|row| {
52 batch
53 .columns()
54 .iter()
55 .map(|column| value::table_cell(column.as_ref(), row, self.binary_format))
56 .collect::<Result<Vec<_>>>()
57 })
58 .collect::<Result<Vec<_>>>()?;
59 self.rows.extend(rows);
60 Ok(())
61 }
62
63 fn finish(&mut self) -> Result<()> {
64 let schema = self
65 .schema
66 .as_ref()
67 .expect("start() must be called before finish()");
68
69 let mut table = Table::new();
70 let preset = match self.table_style {
73 TableStyle::Plain => presets::ASCII_FULL,
74 TableStyle::Pretty => presets::UTF8_FULL,
75 };
76 table.load_preset(preset);
77
78 let headers: Vec<&str> = schema.fields().iter().map(|f| f.name().as_str()).collect();
79 table.set_header(headers);
80
81 table.add_rows(self.rows.drain(..));
82
83 writeln!(self.writer, "{table}")?;
84 self.writer.flush()?;
85 Ok(())
86 }
87}