diff --git a/src/lib.rs b/src/lib.rs index c2896ed..3365096 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -468,7 +468,7 @@ impl Range { // search bounds let row_start = cells.first().unwrap().pos.0; let row_end = cells.last().unwrap().pos.0; - let mut col_start = std::u32::MAX; + let mut col_start = u32::MAX; let mut col_end = 0; for c in cells.iter().map(|c| c.pos.1) { if c < col_start { @@ -957,6 +957,12 @@ impl Table { } } +impl From> for Range { + fn from(table: Table) -> Range { + table.data + } +} + /// A helper function to deserialize cell values as `i64`, /// useful when cells may also contain invalid values (i.e. strings). /// It applies the [`as_i64`] method to the cell value, and returns diff --git a/src/xlsx/mod.rs b/src/xlsx/mod.rs index 452dcaa..8c7cae4 100644 --- a/src/xlsx/mod.rs +++ b/src/xlsx/mod.rs @@ -680,6 +680,32 @@ impl Xlsx { Ok(()) } + #[inline] + fn get_table_meta(&self, table_name: &str) -> Result { + let match_table_meta = self + .tables + .as_ref() + .expect("Tables must be loaded before they are referenced") + .iter() + .find(|(table, ..)| table == table_name) + .ok_or_else(|| XlsxError::TableNotFound(table_name.into()))?; + + let name = match_table_meta.0.to_owned(); + let sheet_name = match_table_meta.1.clone(); + let columns = match_table_meta.2.clone(); + let dimensions = Dimensions { + start: match_table_meta.3.start, + end: match_table_meta.3.end, + }; + + Ok(TableMetadata { + name, + sheet_name, + columns, + dimensions, + }) + } + /// Load the merged regions pub fn load_merged_regions(&mut self) -> Result<(), XlsxError> { if self.merged_regions.is_none() { @@ -735,23 +761,39 @@ impl Xlsx { .collect() } - /// Get the table by name + /// Get the table by name (owned) // TODO: If retrieving multiple tables from a single sheet, get tables by sheet will be more efficient pub fn table_by_name(&mut self, table_name: &str) -> Result, XlsxError> { - let match_table_meta = self - .tables - .as_ref() - .expect("Tables must be loaded before they are referenced") - .iter() - .find(|(table, ..)| table == table_name) - .ok_or_else(|| XlsxError::TableNotFound(table_name.into()))?; - let name = match_table_meta.0.to_owned(); - let sheet_name = match_table_meta.1.clone(); - let columns = match_table_meta.2.clone(); - let start_dim = match_table_meta.3.start; - let end_dim = match_table_meta.3.end; + let TableMetadata { + name, + sheet_name, + columns, + dimensions, + } = self.get_table_meta(table_name)?; + let Dimensions { start, end } = dimensions; let range = self.worksheet_range(&sheet_name)?; - let tbl_rng = range.range(start_dim, end_dim); + let tbl_rng = range.range(start, end); + + Ok(Table { + name, + sheet_name, + columns, + data: tbl_rng, + }) + } + + /// Get the table by name (ref) + pub fn table_by_name_ref(&mut self, table_name: &str) -> Result, XlsxError> { + let TableMetadata { + name, + sheet_name, + columns, + dimensions, + } = self.get_table_meta(table_name)?; + let Dimensions { start, end } = dimensions; + let range = self.worksheet_range_ref(&sheet_name)?; + let tbl_rng = range.range(start, end); + Ok(Table { name, sheet_name, @@ -810,6 +852,13 @@ impl Xlsx { } } +struct TableMetadata { + name: String, + sheet_name: String, + columns: Vec, + dimensions: Dimensions, +} + struct InnerTableMetadata { display_name: String, ref_cells: String, diff --git a/tests/test.rs b/tests/test.rs index 460af0d..0c0da6b 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -584,6 +584,109 @@ fn table() { assert_eq!(data.get((0, 1)), Some(&Float(12.5))); assert_eq!(data.get((1, 1)), Some(&Float(64.0))); xls.worksheet_range_at(0).unwrap().unwrap(); + + // Check if owned data works + let owned_data: Range = table.into(); + + assert_eq!( + owned_data.get((0, 0)), + Some(&String("something".to_owned())) + ); + assert_eq!(owned_data.get((1, 0)), Some(&String("else".to_owned()))); + assert_eq!(owned_data.get((0, 1)), Some(&Float(12.5))); + assert_eq!(owned_data.get((1, 1)), Some(&Float(64.0))); +} + +#[test] +fn table_by_ref() { + let mut xls: Xlsx<_> = wb("temperature-table.xlsx"); + xls.load_tables().unwrap(); + let table_names = xls.table_names(); + assert_eq!(table_names[0], "Temperature"); + assert_eq!(table_names[1], "OtherTable"); + let table = xls + .table_by_name_ref("Temperature") + .expect("Parsing table's sheet should not error"); + assert_eq!(table.name(), "Temperature"); + assert_eq!(table.columns()[0], "label"); + assert_eq!(table.columns()[1], "value"); + let data = table.data(); + assert_eq!( + data.get((0, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("celsius") + ); + assert_eq!( + data.get((1, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("fahrenheit") + ); + assert_eq!( + data.get((0, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(22.2222) + ); + assert_eq!( + data.get((1, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(72.0) + ); + // Check the second table + let table = xls + .table_by_name_ref("OtherTable") + .expect("Parsing table's sheet should not error"); + assert_eq!(table.name(), "OtherTable"); + assert_eq!(table.columns()[0], "label2"); + assert_eq!(table.columns()[1], "value2"); + let data = table.data(); + assert_eq!( + data.get((0, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("something") + ); + assert_eq!( + data.get((1, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("else") + ); + assert_eq!( + data.get((0, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(12.5) + ); + assert_eq!( + data.get((1, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(64.0) + ); + + // Check if owned data works + let owned_data: Range = table.into(); + + assert_eq!( + owned_data + .get((0, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("something") + ); + assert_eq!( + owned_data + .get((1, 0)) + .expect("Could not get data from table ref."), + &DataRef::SharedString("else") + ); + assert_eq!( + owned_data + .get((0, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(12.5) + ); + assert_eq!( + owned_data + .get((1, 1)) + .expect("Could not get data from table ref."), + &DataRef::Float(64.0) + ); } #[test]