use crate::{QueryResult, QueryValue};
use crate::value::display_value;
pub fn write_text<W: std::io::Write + ?Sized>(
result: &QueryResult,
writer: &mut W,
) -> std::io::Result<()> {
if result.columns.is_empty() {
return Ok(());
}
let mut column_widths = result
.columns
.iter()
.map(|column| column.len())
.collect::<Vec<_>>();
for row in &result.rows {
for index in 0..result.columns.len() {
let width = row.get(index).map(display_width).unwrap_or_default();
column_widths[index] = column_widths[index].max(width);
}
}
write_aligned_row(writer, &result.columns, &column_widths)?;
writer.write_all(b"\n")?;
for (index, width) in column_widths.iter().enumerate() {
if index > 0 {
writer.write_all(b"-+-")?;
}
writer.write_all("-".repeat(*width).as_bytes())?;
}
for row in &result.rows {
writer.write_all(b"\n")?;
write_aligned_result_row(writer, row, result.columns.len(), &column_widths)?;
}
Ok(())
}
fn display_width(value: &QueryValue) -> usize {
match value {
QueryValue::Null => 0,
QueryValue::Integer(value) => value.to_string().len(),
QueryValue::Real(value) => value.to_string().len(),
QueryValue::Text(value) => value.len(),
}
}
pub fn render_text(result: &QueryResult) -> String {
let mut output = Vec::new();
write_text(result, &mut output).expect("writing to memory cannot fail");
String::from_utf8(output).expect("table output should always be valid UTF-8")
}
fn write_aligned_row<W: std::io::Write + ?Sized>(
output: &mut W,
values: &[String],
column_widths: &[usize],
) -> std::io::Result<()> {
for (index, value) in values.iter().enumerate() {
if index > 0 {
output.write_all(b" | ")?;
}
write!(output, "{value:<width$}", width = column_widths[index])?;
}
Ok(())
}
fn write_aligned_result_row<W: std::io::Write + ?Sized>(
output: &mut W,
row: &[crate::QueryValue],
column_count: usize,
column_widths: &[usize],
) -> std::io::Result<()> {
for (index, width) in column_widths.iter().enumerate().take(column_count) {
if index > 0 {
output.write_all(b" | ")?;
}
let rendered_value = row.get(index).map(display_value).unwrap_or_default();
write!(output, "{rendered_value:<width$}")?;
}
Ok(())
}