proof_of_sql/base/database/
owned_table.rsuse super::OwnedColumn;
use crate::base::{map::IndexMap, scalar::Scalar};
use proof_of_sql_parser::Identifier;
use snafu::Snafu;
#[derive(Snafu, Debug, PartialEq, Eq)]
pub enum OwnedTableError {
#[snafu(display("Columns have different lengths"))]
ColumnLengthMismatch,
}
#[derive(Debug, Clone, Eq)]
pub struct OwnedTable<S: Scalar> {
table: IndexMap<Identifier, OwnedColumn<S>>,
}
impl<S: Scalar> OwnedTable<S> {
pub fn try_new(table: IndexMap<Identifier, OwnedColumn<S>>) -> Result<Self, OwnedTableError> {
if table.is_empty() {
return Ok(Self { table });
}
let num_rows = table[0].len();
if table.values().any(|column| column.len() != num_rows) {
Err(OwnedTableError::ColumnLengthMismatch)
} else {
Ok(Self { table })
}
}
pub fn try_from_iter<T: IntoIterator<Item = (Identifier, OwnedColumn<S>)>>(
iter: T,
) -> Result<Self, OwnedTableError> {
Self::try_new(IndexMap::from_iter(iter))
}
#[must_use]
pub fn num_columns(&self) -> usize {
self.table.len()
}
#[must_use]
pub fn num_rows(&self) -> usize {
if self.table.is_empty() {
0
} else {
self.table[0].len()
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.table.is_empty()
}
#[must_use]
pub fn into_inner(self) -> IndexMap<Identifier, OwnedColumn<S>> {
self.table
}
#[must_use]
pub fn inner_table(&self) -> &IndexMap<Identifier, OwnedColumn<S>> {
&self.table
}
pub fn column_names(&self) -> impl Iterator<Item = &Identifier> {
self.table.keys()
}
}
impl<S: Scalar> PartialEq for OwnedTable<S> {
fn eq(&self, other: &Self) -> bool {
self.table == other.table
&& self
.table
.keys()
.zip(other.table.keys())
.all(|(a, b)| a == b)
}
}
#[cfg(test)]
impl<S: Scalar> core::ops::Index<&str> for OwnedTable<S> {
type Output = OwnedColumn<S>;
fn index(&self, index: &str) -> &Self::Output {
self.table
.get(&index.parse::<Identifier>().unwrap())
.unwrap()
}
}