use crate::model_traits::{HasSchema, TableColumns, TableInfo, UniqueIdentifier};
use crate::query::include::related_query::{RelatedSetAccesser, SetDowncast};
use crate::relations::RelationshipCompare;
use crate::relations::{HasRelations, Relationship};
use crate::state::DbState;
use std::ops::Deref;
pub struct DataSet<T> {
primary: Vec<DbState<T>>,
related: Vec<Box<dyn RelatedSetAccesser + Send>>,
}
impl<T> DataSet<T> {
pub(crate) fn new(
primary: Vec<DbState<T>>,
related: Vec<Box<dyn RelatedSetAccesser + Send>>,
) -> Self {
Self { primary, related }
}
pub fn iter(&self) -> DataSetIter<'_, T> {
DataSetIter {
index: 0,
inner: self,
}
}
}
pub struct DataSetIter<'t, T> {
index: usize,
inner: &'t DataSet<T>,
}
impl<'t, T> Iterator for DataSetIter<'t, T> {
type Item = DataAccessGuard<'t, T>;
fn next(&mut self) -> Option<Self::Item> {
let obj: &DbState<T> = self.inner.primary.get(self.index)?;
self.index += 1;
Some(DataAccessGuard {
inner: obj,
sets: self.inner,
})
}
}
impl<T> DataSet<T> {
pub fn len(&self) -> usize {
self.primary.len()
}
pub fn is_empty(&self) -> bool {
self.primary.is_empty()
}
pub fn get(&self, index: usize) -> Option<DataAccessGuard<'_, T>> {
let obj = self.primary.get(index)?;
Some(DataAccessGuard {
inner: obj,
sets: self,
})
}
}
pub struct DataAccessGuard<'t, T> {
inner: &'t DbState<T>,
sets: &'t DataSet<T>,
}
impl<'t, T> DataAccessGuard<'t, T> {
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &'t T {
self.inner.as_ref()
}
}
impl<T> Deref for DataAccessGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<'t, T> DataAccessGuard<'t, T>
where
T: HasSchema,
{
pub fn get<'g, R, Ship>(
&self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
) -> Vec<&'g R>
where
'g: 't,
't: 'g,
T: 'static + HasRelations,
Ship: 'static + Relationship<T, R>,
R: HasSchema,
R: 'static + Send + Sync + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns + UniqueIdentifier,
<T as HasSchema>::Schema: TableInfo + TableColumns + UniqueIdentifier,
Ship: RelationshipCompare<T, R>,
{
let t: &T = self.inner.as_ref();
for rset in &self.sets.related {
if let Some(related_set) = rset.downcast_ref::<T, R, Ship>() {
let ship = relationship(Default::default());
if related_set.ship == ship {
let mut set = Vec::default();
for d in &related_set.data {
if ship.is_related(t, d) {
set.push(d);
}
}
return set;
}
}
}
Vec::default()
}
pub fn get_owned<'g, R, Ship>(
&self,
relationship: impl Fn(<T as HasRelations>::Relation) -> Ship,
) -> Vec<R>
where
'g: 't,
't: 'g,
T: 'static + HasRelations,
Ship: 'static + Relationship<T, R>,
R: HasSchema + ToOwned<Owned = R>,
R: HasSchema,
R: 'static + Send + Sync + HasSchema,
<R as HasSchema>::Schema: TableInfo + TableColumns + UniqueIdentifier,
<T as HasSchema>::Schema: TableInfo + TableColumns + UniqueIdentifier,
Ship: RelationshipCompare<T, R>,
{
let t: &T = self.inner.as_ref();
for rset in &self.sets.related {
if let Some(related_set) = rset.downcast_ref::<T, R, Ship>() {
let ship = relationship(Default::default());
if related_set.ship == ship {
let mut set = Vec::default();
for d in &related_set.data {
if ship.is_related(t, d) {
set.push(d.to_owned());
}
}
return set;
}
}
}
Vec::default()
}
}