query-forge 0.2.0

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

use anyhow::{Result, anyhow, bail};

use crate::cli::QueryCommand;

pub(crate) fn load_query(cmd: &QueryCommand) -> Result<String> {
    if let Some(sql) = &cmd.sql {
        return Ok(sql.clone());
    }

    if let Some(query_path) = &cmd.query_file {
        return fs::read_to_string(query_path)
            .map_err(Into::into)
            .map(|content| content.trim().to_owned());
    }

    bail!("provide either --sql or --query-file")
}

pub(crate) fn parse_query_params(entries: &[String]) -> Result<Vec<query_forge::QueryParam>> {
    entries
        .iter()
        .map(|entry| {
            let (name, value) = entry
                .split_once('=')
                .ok_or_else(|| anyhow!("invalid --param '{entry}', expected NAME=VALUE"))?;

            if name.trim().is_empty() {
                bail!("invalid --param '{entry}', parameter name cannot be empty");
            }

            Ok(query_forge::QueryParam {
                name: name.trim().to_owned(),
                value: parse_param_value(value.trim()),
            })
        })
        .collect()
}

fn parse_param_value(raw_value: &str) -> query_forge::QueryValue {
    if raw_value.eq_ignore_ascii_case("null") {
        return query_forge::QueryValue::Null;
    }

    if raw_value.eq_ignore_ascii_case("true") {
        return query_forge::QueryValue::Integer(1);
    }

    if raw_value.eq_ignore_ascii_case("false") {
        return query_forge::QueryValue::Integer(0);
    }

    if let Ok(integer) = raw_value.parse::<i64>() {
        return query_forge::QueryValue::Integer(integer);
    }

    if let Ok(real) = raw_value.parse::<f64>() {
        return query_forge::QueryValue::Real(real);
    }

    query_forge::QueryValue::Text(raw_value.to_owned())
}

#[cfg(test)]
mod tests {
    use super::parse_query_params;

    #[test]
    fn parses_query_params() {
        let entries = vec![
            "wbs=IEV092500011.2.2.4".to_owned(),
            "min=10".to_owned(),
            "enabled=true".to_owned(),
        ];

        let params = parse_query_params(&entries).expect("valid params");

        assert_eq!(params.len(), 3);
        assert_eq!(params[0].name, "wbs");
        assert_eq!(params[1].name, "min");
        assert_eq!(params[2].name, "enabled");
    }
}