1use crate::models::{Cell, CellValue, Column, IndexResult, Row, Sheet};
4use crate::types::Result;
5
6use std::collections::HashMap;
7use std::io::{Error, ErrorKind};
8
9pub type ColumnNameToId<'a> = HashMap<&'a str, u64>;
11pub type ColumnIdToName<'a> = HashMap<u64, &'a str>;
12pub type ColumnNameToCell<'a> = HashMap<&'a str, &'a Cell>;
13
14pub struct ColumnMapper<'a> {
18 pub name_to_id: ColumnNameToId<'a>,
23 pub id_to_name: ColumnIdToName<'a>,
28}
29
30impl<'a> From<&'a Sheet> for ColumnMapper<'a> {
31 fn from(sheet_ref: &'a Sheet) -> Self {
32 Self::new(&sheet_ref.columns)
33 }
34}
35
36impl<'a> From<&'a Row> for ColumnMapper<'a> {
37 fn from(row_ref: &'a Row) -> Self {
38 Self::new(&row_ref.columns)
39 }
40}
41
42impl<'a> From<&'a IndexResult<Column>> for ColumnMapper<'a> {
43 fn from(index_ref: &'a IndexResult<Column>) -> Self {
44 Self::new(&index_ref.data)
45 }
46}
47
48impl<'a> ColumnMapper<'a> {
49 pub fn new(columns: &'a [Column]) -> Self {
51 let (name_to_id, id_to_name) = Self::get_mappings(columns);
52
53 Self {
54 name_to_id,
55 id_to_name,
56 }
57 }
58
59 fn get_mappings(columns: &'a [Column]) -> (ColumnNameToId, ColumnIdToName) {
61 let num_columns = columns.len();
62 if num_columns == 0 {
63 panic!("No column data for the Row - please ensure you call `get_row_with_column_data()` *or* \
65 pass `RowIncludeFlags::Columns` as an `include` argument to `get_row_with_params()`")
66 }
67
68 let mut name_to_id: ColumnNameToId<'a> = HashMap::with_capacity(num_columns);
69 let mut id_to_name: ColumnIdToName<'a> = HashMap::with_capacity(num_columns);
70
71 for c in columns {
72 let title = &c.title;
73
74 name_to_id.insert(title, c.id);
75 id_to_name.insert(c.id, title);
76 }
77
78 (name_to_id, id_to_name)
79 }
80}
81
82pub struct CellGetter<'a> {
86 column_name_to_id: &'a ColumnNameToId<'a>,
87 id_to_column_name: &'a ColumnIdToName<'a>,
88}
89
90impl<'a> CellGetter<'a> {
91 pub fn new(columns: &'a ColumnMapper<'a>) -> Self {
93 Self {
94 column_name_to_id: &columns.name_to_id,
95 id_to_column_name: &columns.id_to_name,
96 }
97 }
98
99 pub fn from_mapper(columns: &'a ColumnMapper<'a>) -> Self {
101 Self::new(columns)
102 }
103
104 pub fn by_name<'b>(&'a self, row: &'a Row, name: &'b str) -> Result<&Cell> {
123 match self.column_name_to_id.get(name) {
124 Some(&col_id) => row.get_cell_by_id(col_id),
125 None => Err(Box::from(Error::new(
126 ErrorKind::InvalidInput,
127 format!("A column named `{}` was not found in the Sheet", name),
128 ))),
129 }
130 }
131
132 pub fn by_id(&'a self, row: &'a Row, column_id: u64) -> Result<&Cell> {
134 row.get_cell_by_id(column_id)
135 }
136
137 pub fn name_to_cell(&'a self, row: &'a Row) -> ColumnNameToCell<'a> {
142 let mut col_name_to_cell: ColumnNameToCell<'a> = HashMap::with_capacity(row.cells.len());
143
144 for cell in &row.cells {
145 if let Some(&col_name) = self.id_to_column_name.get(&cell.column_id) {
146 col_name_to_cell.insert(col_name, cell);
147 }
148 }
149
150 col_name_to_cell
151 }
152}
153
154pub struct RowGetter<'a> {
162 pub rows: &'a [Row],
164 pub column_name_to_id: &'a ColumnNameToId<'a>,
169}
170
171impl<'a> RowGetter<'a> {
172 pub fn new(rows: &'a [Row], columns: &'a ColumnMapper<'a>) -> RowGetter<'a> {
174 Self {
175 rows,
176 column_name_to_id: &columns.name_to_id,
177 }
178 }
179
180 pub fn where_eq<V: Into<CellValue>>(
183 &'a self,
184 column_name: &'a str,
185 value: V,
186 ) -> Result<RowFinder<'a>> {
187 RowFinder::new(
188 self.rows,
189 self.column_name_to_id,
190 column_name,
191 value.into(),
192 Comp::EQ,
193 )
194 }
195
196 pub fn where_eq_by_id<V: Into<CellValue>>(&'a self, column_id: u64, value: V) -> RowFinder<'a> {
199 RowFinder::new_by_id(self.rows, column_id, value.into(), Comp::EQ)
200 }
201
202 pub fn where_ne<V: Into<CellValue>>(
205 &'a self,
206 column_name: &'a str,
207 value: V,
208 ) -> Result<RowFinder<'a>> {
209 RowFinder::new(
210 self.rows,
211 self.column_name_to_id,
212 column_name,
213 value.into(),
214 Comp::NE,
215 )
216 }
217
218 pub fn where_ne_by_id<V: Into<CellValue>>(&'a self, column_id: u64, value: V) -> RowFinder<'a> {
221 RowFinder::new_by_id(self.rows, column_id, value.into(), Comp::NE)
222 }
223}
224
225pub enum Comp {
227 EQ,
228 NE,
229}
230
231impl Comp {
232 pub fn get_cell_comparator<'a>(&'a self) -> fn(&'a CellValue, &'a CellValue) -> bool {
235 match self {
236 Comp::EQ => |v1: &'a CellValue, v2: &'a CellValue| v1 == v2,
237 Comp::NE => |v1: &'a CellValue, v2: &'a CellValue| v1 != v2,
238 }
239 }
240}
241
242pub struct RowFinder<'a> {
250 pub rows: &'a [Row],
252 column_id: u64,
254 value: CellValue,
256 cmp: Comp,
258}
259
260impl<'a> RowFinder<'a> {
261 pub fn new(
268 rows: &'a [Row],
269 column_name_to_id: &'a ColumnNameToId<'a>,
270 column_name: &'a str,
271 value: CellValue,
272 cmp: Comp,
273 ) -> Result<Self> {
274 let column_id = match column_name_to_id.get(column_name) {
275 Some(&v) => v,
276 None => {
277 return Err(Box::from(Error::new(
278 ErrorKind::NotFound,
279 format!(
280 "The column name `{}` does not exist in the sheet",
281 column_name
282 ),
283 )));
284 }
285 };
286
287 Ok(Self::new_by_id(rows, column_id, value, cmp))
288 }
289
290 pub fn new_by_id(rows: &'a [Row], column_id: u64, value: CellValue, cmp: Comp) -> Self {
292 Self {
293 rows,
294 column_id,
295 value,
296 cmp,
297 }
298 }
299
300 pub fn first<'b>(&'b self) -> Result<&'a Row> {
302 let cmp = self.cmp.get_cell_comparator();
303
304 return match self.rows.iter().find(|row| {
305 if let Ok(cell) = row.get_cell_by_id(self.column_id) {
306 matches!(&cell.value, Some(cv) if cmp(&self.value, cv))
307 } else {
308 false
309 }
310 }) {
311 Some(row) => Ok(row),
312 None => Err(Box::from(Error::new(
313 ErrorKind::NotFound,
314 "No matching row for the condition",
315 ))),
316 };
317 }
318
319 pub fn find_all<'b>(&'b self) -> Result<Vec<&'a Row>> {
321 let cmp = self.cmp.get_cell_comparator();
322
323 Ok(self
324 .rows
325 .iter()
326 .filter(|row| {
327 if let Ok(cell) = row.get_cell_by_id(self.column_id) {
328 matches!(&cell.value, Some(cv) if cmp(&self.value, cv))
329 } else {
330 false
331 }
332 })
333 .collect::<Vec<_>>())
334 }
335}