csvsql 0.1.4

SQL like engine that works on CSV file.
Documentation
use std::io::Read;
use std::{io, path::PathBuf};

use tempfile::NamedTempFile;

use crate::error::CvsSqlError;

pub(crate) trait StdinReader {
    fn path(&mut self) -> Result<PathBuf, CvsSqlError>;
}

pub(crate) fn create_stdin_reader(supported: bool) -> Box<dyn StdinReader> {
    if supported {
        let reader = io::stdin().lock();
        Box::new(StdinAsTableState::Unread(reader))
    } else {
        Box::new(UnsupportedStdinReader {})
    }
}
enum StdinAsTableState<R: Read> {
    Unread(R),
    Read(NamedTempFile),
}

impl<R: Read> StdinReader for StdinAsTableState<R> {
    fn path<'a>(&mut self) -> Result<PathBuf, CvsSqlError> {
        match self {
            Self::Read(r) => Ok(r.path().to_path_buf()),
            Self::Unread(r) => {
                let mut temporary_file = NamedTempFile::with_suffix(".csv")?;
                io::copy(r, &mut temporary_file)?;
                *self = Self::Read(temporary_file);
                self.path()
            }
        }
    }
}

struct UnsupportedStdinReader {}
impl StdinReader for UnsupportedStdinReader {
    fn path(&mut self) -> Result<PathBuf, CvsSqlError> {
        Err(CvsSqlError::StdinUnusable)
    }
}

#[cfg(test)]
mod tests {

    use std::fs;

    use super::*;

    #[test]
    fn unsupported_stdin_will_return_err() {
        let mut reader = UnsupportedStdinReader {};
        let err = reader.path().err().unwrap();
        assert!(matches!(err, CvsSqlError::StdinUnusable));
    }

    #[test]
    fn supported_stdin_will_return_same_data_always() {
        let data = "test data".as_bytes();
        let mut reader = StdinAsTableState::Unread(data);

        let path = reader.path().unwrap();

        let content = fs::read_to_string(path).unwrap();

        assert_eq!(content, "test data");
        assert!(matches!(reader, StdinAsTableState::Read(_)));

        let path = reader.path().unwrap();

        let content = fs::read_to_string(path).unwrap();

        assert_eq!(content, "test data");
        assert!(matches!(reader, StdinAsTableState::Read(_)));
    }
}