querqle 0.1.2

A small library made to perform sql queries thru the odbc-api library, and convert the results directly into data structures.
Documentation
use std::{collections::HashMap, fs::File, io::Write};



#[cfg(feature= "polars")]
use polars::prelude::*;
/// Holds the result of a query 
/// Gives the result if the query returned anything, gives None otherwise (for either empty returns
/// or queries that don't return anything such as create)
pub enum QueryResult {
    Result { rows:Vec<Vec<String>>, col_names:Vec<String>},
    None
}

impl QueryResult {
    /// Returns a hashmap if 
    /// the original query gave results. Hashmap keys column names to their column values
    /// If there were no results from the query, then it returns a None
    pub fn to_hashmap(&self) -> Option<HashMap<String, Vec<String>>> {
        let mut hashmap = HashMap::<String, Vec<String>>::new();
        match self {
            QueryResult::Result { rows, col_names } => {
                let cols = match self.rows_to_columns() {
                    Some(cols)
                    => cols,
                    None => return None

                };

                for i in 0..cols.len() {
                    let col_name = col_names.get(i)?.clone();
                    let column = rows.get(i)?.clone();
                    hashmap.insert(col_name, column);
                }
                return Some(hashmap);
            },
            QueryResult::None => return None,
        }
    }

    fn rows_to_columns(&self) -> Option<Vec<Vec<String>>> {
        let mut col_table: Vec<Vec<String>> = Vec::new();
        match self {
            QueryResult::Result { rows, col_names } => {
                for i in 0..col_names.len() {
                    let col = rows
                        .iter()
                        .map(|r| {
                            return r[i].clone();
                        })
                        .collect();
                    col_table.push(col);
                }
                return Some(col_table);
            },
            QueryResult::None => {
                return None
            }
        }
    }

    pub(crate) fn new( rows: Vec<Vec<String>>, col_names: Vec<String>) -> Self {
        if col_names.is_empty() || rows.is_empty(){
            return QueryResult::None;
        }
        QueryResult::Result{ rows: rows, col_names: col_names }
    }
    /// Converts a QueryResult result into a .csv file. A None QueryResult doesn't do anything.
    /// Will return an OK(()) as long as there isn't any problems writing to file
    pub fn to_csv(&self,file: &str) -> std::io::Result<()>{
        match self {
            QueryResult::Result { rows, col_names } => {
                let mut file = File::create(file)?;
                let column_heading = col_names.join(", ");
                file.write_all(column_heading.as_bytes())?;
                for row in rows {
                    file.write_all("\n".as_bytes())?;
                    file.write_all(row.join(", ").as_bytes())?;
                }

            },
            &QueryResult::None => return Ok(())
        }  
        Ok(())
    }
    #[cfg(feature = "polars")]
    #[cfg_attr(docsrs,doc(cfg(feature = "polars")))]
    /// Converts a QueryResult result into a polars dataframe for use in projects using polars. Returns either None if the QueryResult is empty
    /// or a PolarsResult containing the dataframe (or error) otherwise
    /// requires the polars feature
    pub fn to_polars(&self) -> Option<PolarsResult<DataFrame>> {
        match self {
            QueryResult::Result { col_names, .. } => {
                let mut series_vec: Vec<polars::prelude::Column> = Vec::new();
                let cols = match self.rows_to_columns() {
                    Some(cols)=> cols,
                    None=> return None,
                };
                for i in 0..cols.len() {
                    let col_name = col_names.get(i)?.clone();
                    let col = cols.get(i)?;
                    let s = polars::series::Series::new(col_name.into(), col.as_slice());
                    series_vec.push(s.into_column());
                }
                let df = polars::frame::DataFrame::new(series_vec);
                return Some(df);
            },
            QueryResult::None => None,
        }

    }
}