query-forge 0.5.0

Run SQL queries on XLSX/XML/CSV/JSON/JSONL/Markdown/HTML/Parquet inputs and export results as text, CSV, JSONL, Markdown, XML, HTML, XLSX, or Parquet
Documentation
use std::fmt::Write as _;

use crate::QueryResult;
use crate::value::display_value;

pub fn render_text(result: &QueryResult) -> String {
    if result.columns.is_empty() {
        return String::new();
    }

    let mut column_widths = result
        .columns
        .iter()
        .map(|column| column.len())
        .collect::<Vec<_>>();
    let mut rendered_rows = Vec::with_capacity(result.rows.len());

    for row in &result.rows {
        let mut rendered_row = Vec::with_capacity(result.columns.len());
        for index in 0..result.columns.len() {
            let rendered_value = row.get(index).map(display_value).unwrap_or_default();
            column_widths[index] = column_widths[index].max(rendered_value.len());
            rendered_row.push(rendered_value);
        }
        rendered_rows.push(rendered_row);
    }

    let mut output = String::new();
    write_aligned_row(&mut output, &result.columns, &column_widths);
    output.push('\n');
    output.push_str(
        &column_widths
            .iter()
            .map(|width| "-".repeat(*width))
            .collect::<Vec<_>>()
            .join("-+-"),
    );

    for row in rendered_rows {
        output.push('\n');
        write_aligned_row(&mut output, &row, &column_widths);
    }

    output
}

fn write_aligned_row(output: &mut String, values: &[String], column_widths: &[usize]) {
    for (index, value) in values.iter().enumerate() {
        if index > 0 {
            output.push_str(" | ");
        }

        let _ = write!(output, "{value:<width$}", width = column_widths[index]);
    }
}