use std::marker::PhantomData;
use std::sync::Arc;
use indexmap::IndexMap;
use vantage_expressions::Expression;
use vantage_types::Entity;
use crate::{
pagination::Pagination, references::Reference, sorting::SortDirection,
traits::table_source::TableSource,
};
pub type ExpressionFn<T, E> =
Arc<dyn Fn(&Table<T, E>) -> Expression<<T as TableSource>::Value> + Send + Sync>;
#[derive(Clone)]
pub struct Table<T, E>
where
T: TableSource,
E: Entity<T::Value>,
{
pub(super) data_source: T,
pub(super) _phantom: PhantomData<E>,
pub(super) table_name: String,
pub(super) columns: IndexMap<String, T::Column<T::AnyType>>,
pub(super) conditions: IndexMap<i64, T::Condition>,
pub(super) next_condition_id: i64,
pub(super) order_by: IndexMap<i64, (T::Condition, SortDirection)>,
pub(super) next_order_id: i64,
pub(super) refs: Option<IndexMap<String, Arc<dyn Reference>>>,
pub(super) expressions: IndexMap<String, ExpressionFn<T, E>>,
pub(super) pagination: Option<Pagination>,
pub(super) title_field: Option<String>,
pub(super) id_field: Option<String>,
}
impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
pub fn new(table_name: impl Into<String>, data_source: T) -> Self {
Self {
data_source,
_phantom: PhantomData,
table_name: table_name.into(),
columns: IndexMap::new(),
conditions: IndexMap::new(),
next_condition_id: 1,
order_by: IndexMap::new(),
next_order_id: 1,
refs: None,
expressions: IndexMap::new(),
pagination: None,
title_field: None,
id_field: None,
}
}
pub fn into_entity<E2: Entity<T::Value>>(self) -> Table<T, E2> {
Table {
data_source: self.data_source,
_phantom: PhantomData,
table_name: self.table_name,
columns: self.columns,
conditions: self.conditions,
next_condition_id: self.next_condition_id,
order_by: self.order_by,
next_order_id: self.next_order_id,
refs: self.refs,
expressions: IndexMap::new(),
pagination: self.pagination,
title_field: self.title_field,
id_field: self.id_field,
}
}
pub fn with<F>(mut self, func: F) -> Self
where
F: FnOnce(&mut Self),
{
func(&mut self);
self
}
pub fn table_name(&self) -> &str {
&self.table_name
}
pub fn data_source(&self) -> &T {
&self.data_source
}
pub(crate) fn conditions_mut(&mut self) -> &mut IndexMap<i64, T::Condition> {
&mut self.conditions
}
pub(crate) fn next_condition_id_mut(&mut self) -> &mut i64 {
&mut self.next_condition_id
}
pub fn title_field(&self) -> Option<&T::Column<T::AnyType>> {
self.title_field
.as_ref()
.and_then(|name| self.columns.get(name))
}
pub fn id_field(&self) -> Option<&T::Column<T::AnyType>> {
self.id_field
.as_ref()
.and_then(|name| self.columns.get(name))
}
pub fn pagination(&self) -> Option<&Pagination> {
self.pagination.as_ref()
}
}
impl<T: TableSource, E: Entity<T::Value>> std::ops::Index<&str> for Table<T, E> {
type Output = T::Column<T::AnyType>;
fn index(&self, index: &str) -> &Self::Output {
&self.columns[index]
}
}
impl<T: TableSource, E: Entity<T::Value>> std::fmt::Debug for Table<T, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Table")
.field("table_name", &self.table_name)
.field("columns", &self.columns.keys().collect::<Vec<_>>())
.field("conditions_count", &self.conditions.len())
.field(
"refs_count",
&self.refs.as_ref().map(|r| r.len()).unwrap_or(0),
)
.field("expressions_count", &self.expressions.len())
.finish()
}
}