mod column;
mod header;
mod row;
use tracing::{debug, instrument};
use crate::RealmFileError;
use crate::array::Array;
use crate::column::Column;
use crate::error::TableError;
pub(crate) use crate::table::column::ColumnAttributes;
use crate::table::header::TableHeader;
pub use crate::table::row::Row;
use crate::value::Value;
#[derive(Debug)]
#[allow(unused)]
pub struct Table {
header: TableHeader,
table_number: usize,
}
impl Table {
#[instrument(level = "debug")]
pub(crate) fn build(array: Array, table_number: usize) -> crate::RealmResult<Self> {
let header_array = array.get_node(0)?.unwrap();
let data_array = array.get_node(1)?.unwrap();
Self::build_from(&header_array, data_array, table_number)
}
#[instrument(level = "debug")]
pub(crate) fn build_from(
header_array: &Array,
data_array: Array,
table_number: usize,
) -> crate::RealmResult<Self> {
let header = TableHeader::build(header_array, &data_array)?;
let result = Self {
header,
table_number,
};
debug!("data: {:?}", result);
Ok(result)
}
}
impl Table {
pub fn get_table_number(&self) -> usize {
self.table_number
}
pub fn get_column_specs(&self) -> &[Box<dyn Column>] {
self.header.get_columns()
}
pub fn get_column_spec(&self, column_number: usize) -> Option<&dyn Column> {
self.header.get_column(column_number)
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
pub fn row_count(&self) -> crate::RealmResult<usize> {
let first_column =
self.header
.get_column(0)
.ok_or_else(|| RealmFileError::InvalidRealmFile {
reason: "No column at index 0: can't load row count".to_string(),
})?;
first_column.count()
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
pub fn get_row<'a>(&'a self, row_number: usize) -> crate::RealmResult<Row<'a>> {
let values = self.load_row(row_number)?;
Ok(Row::new(
values,
self.header
.get_columns()
.iter()
.filter_map(|c| c.name())
.map(|n| n.into())
.collect(),
))
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
fn load_row(&self, row_number: usize) -> crate::RealmResult<Vec<Value>> {
let column_count = self.header.column_count();
let mut values = Vec::with_capacity(column_count);
for column_number in 0..column_count {
tracing::info!("loading column {column_number} for row {row_number}");
values.push(self.load_column(column_number, row_number)?);
}
Ok(values)
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
pub fn find_row_number_from_indexed_column(
&self,
indexed_column_name: &str,
value: &Value,
) -> crate::TableResult<Option<usize>> {
let column_spec = self
.header
.get_columns()
.iter()
.find(|col| col.name() == Some(indexed_column_name))
.ok_or_else(|| TableError::ColumnNotFound {
name: indexed_column_name.to_string(),
})?;
if !column_spec.is_indexed() {
return Err(TableError::ColumnNotIndexed {
name: indexed_column_name.to_string(),
});
}
let result = column_spec.get_row_number_by_index(value)?;
Ok(result)
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
pub fn find_row_from_indexed_column<'a>(
&'a self,
indexed_column_name: &str,
value: &Value,
) -> crate::TableResult<Option<Row<'a>>> {
let Some(row_number) =
self.find_row_number_from_indexed_column(indexed_column_name, value)?
else {
return Ok(None);
};
let row = self.get_row(row_number)?;
Ok(Some(row))
}
#[instrument(level = "debug", skip(self), fields(header = ?self.header))]
pub fn get_rows<'a>(&'a self) -> crate::RealmResult<Vec<Row<'a>>> {
let row_count = self.row_count()?;
let mut rows = Vec::with_capacity(row_count);
for i in 0..row_count {
rows.push(self.get_row(i)?);
}
Ok(rows)
}
#[instrument(level = "debug", skip(self))]
fn load_column(&self, column_number: usize, row_number: usize) -> crate::RealmResult<Value> {
let column_spec = self
.header
.get_column(column_number)
.unwrap_or_else(|| panic!("Invalid column number {column_number}"));
let value = column_spec.get(row_number)?;
debug!(
"Loaded column {column_number} at row {row_number}: {:?}",
value
);
Ok(value)
}
}