use crate::models::{Cell, Column, Row};
use crate::types::Result;
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
type ColumnNameToId<'a> = HashMap<&'a str, u64>;
type ColumnIdToName<'a> = HashMap<u64, &'a str>;
type ColumnNameToCell<'a> = HashMap<&'a str, &'a Cell>;
pub struct ColumnMapper<'a> {
pub name_to_id: ColumnNameToId<'a>,
pub id_to_name: ColumnIdToName<'a>,
}
impl<'a> ColumnMapper<'a> {
pub fn new(columns: &'a [Column]) -> Self {
let (name_to_id, id_to_name) = Self::get_mappings(columns);
Self {
name_to_id,
id_to_name,
}
}
fn get_mappings(columns: &'a [Column]) -> (ColumnNameToId, ColumnIdToName) {
let num_columns = columns.len();
if num_columns == 0 {
panic!("No column data for the Row - please ensure you call `get_row_with_column_data()` *or* \
pass `RowIncludeFlags::Columns` as an `include` argument to `get_row_with_params()`")
}
let mut name_to_id: ColumnNameToId<'a> = HashMap::with_capacity(num_columns);
let mut id_to_name: ColumnIdToName<'a> = HashMap::with_capacity(num_columns);
for c in columns {
let title = &c.title;
name_to_id.insert(title, c.id);
id_to_name.insert(c.id, title);
}
(name_to_id, id_to_name)
}
}
pub struct CellGetter<'a> {
column_name_to_id: &'a ColumnNameToId<'a>,
id_to_column_name: &'a ColumnIdToName<'a>,
}
impl<'a> CellGetter<'a> {
pub fn new(columns: &'a ColumnMapper<'a>) -> Self {
Self {
column_name_to_id: &columns.name_to_id,
id_to_column_name: &columns.id_to_name,
}
}
pub fn from_mapper(columns: &'a ColumnMapper<'a>) -> Self {
Self::new(columns)
}
pub fn by_name<'b>(&'a self, row: &'a Row, name: &'b str) -> Result<&Cell> {
match self.column_name_to_id.get(name) {
Some(&col_id) => row.get_cell_by_id(col_id),
None => Err(Box::from(Error::new(
ErrorKind::InvalidInput,
format!("A column named `{}` was not found in the Sheet", name),
))),
}
}
pub fn by_id(&'a self, row: &'a Row, column_id: u64) -> Result<&Cell> {
row.get_cell_by_id(column_id)
}
pub fn name_to_cell(&'a self, row: &'a Row) -> ColumnNameToCell<'a> {
let mut col_name_to_cell: ColumnNameToCell<'a> = HashMap::with_capacity(row.cells.len());
for cell in &row.cells {
if let Some(&col_name) = self.id_to_column_name.get(&cell.column_id) {
col_name_to_cell.insert(col_name, cell);
}
}
col_name_to_cell
}
}