sql2xlsx 0.1.0

Export SQL query to excel file
Documentation
use clap::{Args, Parser, Subcommand};
use serde::Deserialize;
use sql2xlsx::Query;
use std::error::Error;
use std::path::PathBuf;
use std::{env, fs};

#[derive(Parser, Debug)]
#[command(author, version, about)]
#[command(propagate_version = true)]
struct Cli {
    #[arg(long)]
    db: Option<String>,
    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand, Debug)]
enum Commands {
    File(FromFile),
    Sql(FromSql),
}

#[derive(Args, Debug)]
struct FromFile {
    #[arg(long)]
    name: String,
}

impl FromFile {
    fn into_from_sql(self) -> Result<FromSql, Box<dyn Error>> {
        let file_content = fs::read_to_string(&self.name).map_err(|err| {
            eprintln!("Read file {} err: {:?}", &self.name, err);
            err
        })?;

        toml::from_str(&file_content).map_err(|err| {
            eprintln!("Deserialize file {} err: {:?}", &self.name, err);
            err.into()
        })
    }
}

#[derive(Args, Debug, Deserialize)]
struct FromSql {
    #[arg(long)]
    header: String,
    #[arg(long)]
    sql: String,
    #[arg(long)]
    out: PathBuf,
}

impl FromSql {
    fn into_query(self, db_url: String) -> Query {
        Query::new(db_url.to_string(), self.sql, self.header, self.out)
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    if dotenvy::dotenv().is_err() {
        println!("NO .env file found");
    }

    let cli = Cli::parse();

    let db_url = match cli.db.or_else(|| env::var("DATABASE_URL").ok()) {
        Some(db) => db,
        None => {
            eprintln!("NO DB_URL");
            return Ok(());
        }
    };

    let from_sql = match cli.command {
        Commands::File(from_file) => from_file.into_from_sql()?,
        Commands::Sql(from_sql) => from_sql,
    };

    let query = from_sql.into_query(db_url);
    query.execute()
}