use crate::entity::{EntityState, IEntityType};
use crate::error::LrefResult;
use crate::provider::IDatabaseProvider;
use crate::query::{IQueryable, QueryBuilder};
use std::sync::Arc;
pub trait IDbSet<T: IEntityType>: IQueryable<T> + Send + Sync {
fn add(&mut self, entity: T);
fn remove_all(&mut self);
fn remove_at(&mut self, index: usize) -> LrefResult<()>;
fn attach(&mut self, entity: T);
fn added_entities(&self) -> Vec<&T>;
fn modified_entities(&self) -> Vec<&T>;
fn deleted_entities(&self) -> Vec<&T>;
fn entries_with_state(&self) -> Vec<(&T, EntityState)>;
fn clear_entries(&mut self);
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
}
pub struct DbSet<T: IEntityType> {
pub(crate) entries: Vec<TrackedEntry<T>>,
table_name: String,
provider: Option<Arc<dyn IDatabaseProvider>>,
}
pub struct TrackedEntry<T: IEntityType> {
pub entity: T,
pub state: EntityState,
}
impl<T: IEntityType> DbSet<T> {
pub fn new(table_name: impl Into<String>) -> Self {
Self {
entries: Vec::new(),
table_name: table_name.into(),
provider: None,
}
}
pub fn with_provider(
table_name: impl Into<String>,
provider: Arc<dyn IDatabaseProvider>,
) -> Self {
Self {
entries: Vec::new(),
table_name: table_name.into(),
provider: Some(provider),
}
}
pub fn set_provider(&mut self, provider: Arc<dyn IDatabaseProvider>) {
self.provider = Some(provider);
}
pub fn add(&mut self, entity: T) {
IDbSet::add(self, entity);
}
pub fn remove_all(&mut self) {
IDbSet::remove_all(self);
}
pub fn remove_at(&mut self, index: usize) -> LrefResult<()> {
IDbSet::remove_at(self, index)
}
pub fn clear_entries(&mut self) {
IDbSet::clear_entries(self);
}
pub fn len(&self) -> usize {
IDbSet::len(self)
}
pub fn is_empty(&self) -> bool {
IDbSet::is_empty(self)
}
pub fn query(&self) -> QueryBuilder<T> {
IQueryable::query(self)
}
pub fn attach(&mut self, entity: T) {
IDbSet::attach(self, entity);
}
pub fn tracked_entries(&self) -> impl Iterator<Item = &T> {
self.entries.iter().map(|e| &e.entity)
}
pub fn tracked_entries_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.entries.iter_mut().map(|e| &mut e.entity)
}
pub fn retain(&mut self, f: impl FnMut(&TrackedEntry<T>) -> bool) {
self.entries.retain(f);
}
}
impl<T: IEntityType> IQueryable<T> for DbSet<T> {
fn query(&self) -> QueryBuilder<T> {
match &self.provider {
Some(p) => QueryBuilder::with_provider(&self.table_name, p.clone()),
None => QueryBuilder::new(&self.table_name),
}
}
}
impl<T: IEntityType> IDbSet<T> for DbSet<T> {
fn add(&mut self, entity: T) {
self.entries.push(TrackedEntry {
entity,
state: EntityState::Added,
});
}
fn remove_all(&mut self) {
for entry in &mut self.entries {
entry.state = EntityState::Deleted;
}
}
fn remove_at(&mut self, index: usize) -> LrefResult<()> {
if let Some(entry) = self.entries.get_mut(index) {
entry.state = EntityState::Deleted;
Ok(())
} else {
Err(crate::error::LrefError::NotFound(
"Entity not found at the given index".to_string(),
))
}
}
fn attach(&mut self, entity: T) {
self.entries.push(TrackedEntry {
entity,
state: EntityState::Unchanged,
});
}
fn added_entities(&self) -> Vec<&T> {
self.entries
.iter()
.filter(|e| e.state == EntityState::Added)
.map(|e| &e.entity)
.collect()
}
fn modified_entities(&self) -> Vec<&T> {
self.entries
.iter()
.filter(|e| e.state == EntityState::Modified)
.map(|e| &e.entity)
.collect()
}
fn deleted_entities(&self) -> Vec<&T> {
self.entries
.iter()
.filter(|e| e.state == EntityState::Deleted)
.map(|e| &e.entity)
.collect()
}
fn entries_with_state(&self) -> Vec<(&T, EntityState)> {
self.entries.iter().map(|e| (&e.entity, e.state)).collect()
}
fn clear_entries(&mut self) {
self.entries.clear();
}
fn len(&self) -> usize {
self.entries.len()
}
fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}