use crate::records::{EventRecord, SessionRecord};
use std::{fs::File, io::BufReader, path::PathBuf};
use thiserror::Error;
use uuid::Uuid;
#[derive(Debug)]
pub struct CsvSource<'a> {
sessions: &'a PathBuf,
events: &'a PathBuf,
session_id: Uuid,
}
impl<'a> CsvSource<'a> {
pub fn new(sessions: &'a PathBuf, events: &'a PathBuf, session_id: Uuid) -> Self {
Self {
sessions,
events,
session_id,
}
}
}
#[derive(Debug, Error)]
pub enum CsvParsingError {
#[error("the provided session id {0} could not be found")]
SessionNotFound(Uuid),
#[error("there were issues deserializing the session data")]
SessionDeserializationErrors(Vec<csv::Error>),
#[error("there were issues deserializing the event data")]
EventDeserializationErrors(Vec<csv::Error>),
#[error("there were issues finding the files")]
IoError(#[from] std::io::Error),
}
impl<'a> CsvSource<'a> {
pub fn get_data(&self) -> Result<(SessionRecord, Vec<EventRecord>), CsvParsingError> {
let mut session_deserialization_errors = Vec::new();
let session_record = csv::Reader::from_reader(BufReader::new(File::open(self.sessions)?))
.deserialize::<SessionRecord>()
.filter_map(|record_res| {
record_res
.map_err(|err| session_deserialization_errors.push(err))
.ok()
})
.find(|record| record.session_id == self.session_id)
.ok_or(CsvParsingError::SessionNotFound(self.session_id))?;
if !session_deserialization_errors.is_empty() {
return Err(CsvParsingError::SessionDeserializationErrors(
session_deserialization_errors,
));
}
let mut event_deserialization_errors = Vec::new();
let event_records: Vec<EventRecord> =
csv::Reader::from_reader(BufReader::new(File::open(self.events)?))
.deserialize::<EventRecord>()
.filter_map(|record_res| {
record_res
.map_err(|err| event_deserialization_errors.push(err))
.ok()
})
.filter(|record| record.session_id == self.session_id)
.collect();
if !event_deserialization_errors.is_empty() {
return Err(CsvParsingError::EventDeserializationErrors(
event_deserialization_errors,
));
}
Ok((session_record, event_records))
}
}