Skip to main content

query_forge/output/formats/
text.rs

1use crate::{QueryResult, QueryValue};
2use crate::value::display_value;
3
4pub fn write_text<W: std::io::Write + ?Sized>(
5    result: &QueryResult,
6    writer: &mut W,
7) -> std::io::Result<()> {
8    if result.columns.is_empty() {
9        return Ok(());
10    }
11
12    let mut column_widths = result
13        .columns
14        .iter()
15        .map(|column| column.len())
16        .collect::<Vec<_>>();
17
18    for row in &result.rows {
19        for index in 0..result.columns.len() {
20            let width = row.get(index).map(display_width).unwrap_or_default();
21            column_widths[index] = column_widths[index].max(width);
22        }
23    }
24
25    write_aligned_row(writer, &result.columns, &column_widths)?;
26    writer.write_all(b"\n")?;
27
28    for (index, width) in column_widths.iter().enumerate() {
29        if index > 0 {
30            writer.write_all(b"-+-")?;
31        }
32        writer.write_all("-".repeat(*width).as_bytes())?;
33    }
34
35    for row in &result.rows {
36        writer.write_all(b"\n")?;
37        write_aligned_result_row(writer, row, result.columns.len(), &column_widths)?;
38    }
39
40    Ok(())
41}
42
43fn display_width(value: &QueryValue) -> usize {
44    match value {
45        QueryValue::Null => 0,
46        QueryValue::Integer(value) => value.to_string().len(),
47        QueryValue::Real(value) => value.to_string().len(),
48        QueryValue::Text(value) => value.len(),
49    }
50}
51
52pub fn render_text(result: &QueryResult) -> String {
53    let mut output = Vec::new();
54    write_text(result, &mut output).expect("writing to memory cannot fail");
55    String::from_utf8(output).expect("table output should always be valid UTF-8")
56}
57
58fn write_aligned_row<W: std::io::Write + ?Sized>(
59    output: &mut W,
60    values: &[String],
61    column_widths: &[usize],
62) -> std::io::Result<()> {
63    for (index, value) in values.iter().enumerate() {
64        if index > 0 {
65            output.write_all(b" | ")?;
66        }
67
68        write!(output, "{value:<width$}", width = column_widths[index])?;
69    }
70
71    Ok(())
72}
73
74fn write_aligned_result_row<W: std::io::Write + ?Sized>(
75    output: &mut W,
76    row: &[crate::QueryValue],
77    column_count: usize,
78    column_widths: &[usize],
79) -> std::io::Result<()> {
80    for (index, width) in column_widths.iter().enumerate().take(column_count) {
81        if index > 0 {
82            output.write_all(b" | ")?;
83        }
84
85        let rendered_value = row.get(index).map(display_value).unwrap_or_default();
86        write!(output, "{rendered_value:<width$}")?;
87    }
88
89    Ok(())
90}