use crate::database::Store;
use crate::entities::Frame;
use crate::error::RepositoryError;
use crate::types::EntityId;
use std::collections::HashMap as StdHashMap;
use super::frame_repository::FrameRelationshipField;
use super::frame_repository::FrameTable;
use super::frame_repository::FrameTableRO;
fn read_field(frame: &Frame, field: &FrameRelationshipField) -> Vec<EntityId> {
match field {
FrameRelationshipField::Blocks => frame.blocks.clone(),
FrameRelationshipField::ParentFrame => frame.parent_frame.into_iter().collect(),
FrameRelationshipField::Table => frame.table.into_iter().collect(),
}
}
fn write_field(frame: &mut Frame, field: &FrameRelationshipField, ids: Vec<EntityId>) {
match field {
FrameRelationshipField::Blocks => frame.blocks = ids,
FrameRelationshipField::ParentFrame => frame.parent_frame = ids.first().copied(),
FrameRelationshipField::Table => frame.table = ids.first().copied(),
}
}
pub struct FrameHashMapTable<'a> {
store: &'a Store,
}
impl<'a> FrameHashMapTable<'a> {
pub fn new(store: &'a Store) -> Self {
Self { store }
}
}
impl<'a> FrameTable for FrameHashMapTable<'a> {
fn create(&mut self, entity: &Frame) -> Result<Frame, RepositoryError> {
self.create_multi(std::slice::from_ref(entity))
.map(|v| v.into_iter().next().unwrap())
}
fn create_multi(&mut self, entities: &[Frame]) -> Result<Vec<Frame>, RepositoryError> {
let mut created = Vec::with_capacity(entities.len());
let mut frame_map = self.store.frames.write().unwrap();
for entity in entities {
let new_entity = if entity.id == EntityId::default() {
let id = self.store.next_id("frame");
Frame {
id,
..entity.clone()
}
} else {
if frame_map.contains_key(&entity.id) {
return Err(RepositoryError::DuplicateId {
entity: "Frame",
id: entity.id,
});
}
entity.clone()
};
frame_map.insert(new_entity.id, new_entity.clone());
created.push(new_entity);
}
Ok(created)
}
fn get(&self, id: &EntityId) -> Result<Option<Frame>, RepositoryError> {
Ok(self.store.frames.read().unwrap().get(id).cloned())
}
fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError> {
let map = self.store.frames.read().unwrap();
Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
}
fn get_all(&self) -> Result<Vec<Frame>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.values()
.cloned()
.collect())
}
fn update(&mut self, entity: &Frame) -> Result<Frame, RepositoryError> {
self.update_multi(std::slice::from_ref(entity))
.map(|v| v.into_iter().next().unwrap())
}
fn update_multi(&mut self, entities: &[Frame]) -> Result<Vec<Frame>, RepositoryError> {
let mut frame_map = self.store.frames.write().unwrap();
let mut result = Vec::with_capacity(entities.len());
for entity in entities {
let mut to_write = entity.clone();
if let Some(existing) = frame_map.get(&entity.id) {
to_write.parent_frame = existing.parent_frame;
to_write.blocks = existing.blocks.clone();
to_write.table = existing.table;
}
frame_map.insert(entity.id, to_write.clone());
result.push(to_write);
}
Ok(result)
}
fn update_with_relationships(&mut self, entity: &Frame) -> Result<Frame, RepositoryError> {
self.update_with_relationships_multi(std::slice::from_ref(entity))
.map(|v| v.into_iter().next().unwrap())
}
fn update_with_relationships_multi(
&mut self,
entities: &[Frame],
) -> Result<Vec<Frame>, RepositoryError> {
let mut frame_map = self.store.frames.write().unwrap();
let mut result = Vec::with_capacity(entities.len());
for entity in entities {
frame_map.insert(entity.id, entity.clone());
result.push(entity.clone());
}
Ok(result)
}
fn remove(&mut self, id: &EntityId) -> Result<(), RepositoryError> {
self.remove_multi(std::slice::from_ref(id))
}
fn remove_multi(&mut self, ids: &[EntityId]) -> Result<(), RepositoryError> {
let removed: std::collections::HashSet<EntityId> = ids.iter().copied().collect();
{
let mut frame_map = self.store.frames.write().unwrap();
for id in ids {
frame_map.remove(id);
}
}
{
let mut frame_map = self.store.frames.write().unwrap();
let updates: Vec<(EntityId, Frame)> = frame_map
.iter()
.filter_map(|(fid, f)| {
f.parent_frame.filter(|p| removed.contains(p)).map(|_| {
let mut updated = f.clone();
updated.parent_frame = None;
(*fid, updated)
})
})
.collect();
for (fid, f) in updates {
frame_map.insert(fid, f);
}
}
{
let mut doc_map = self.store.documents.write().unwrap();
let updates: Vec<(EntityId, crate::entities::Document)> = doc_map
.iter()
.filter_map(|(did, d)| {
if d.frames.iter().any(|fid| removed.contains(fid)) {
let mut updated = d.clone();
updated.frames.retain(|fid| !removed.contains(fid));
Some((*did, updated))
} else {
None
}
})
.collect();
for (did, d) in updates {
doc_map.insert(did, d);
}
}
{
let mut cell_map = self.store.table_cells.write().unwrap();
let updates: Vec<(EntityId, crate::entities::TableCell)> = cell_map
.iter()
.filter_map(|(cid, c)| {
c.cell_frame.filter(|f| removed.contains(f)).map(|_| {
let mut updated = c.clone();
updated.cell_frame = None;
(*cid, updated)
})
})
.collect();
for (cid, c) in updates {
cell_map.insert(cid, c);
}
}
Ok(())
}
fn get_relationship(
&self,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<Vec<EntityId>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| read_field(f, field))
.unwrap_or_default())
}
fn get_relationship_many(
&self,
ids: &[EntityId],
field: &FrameRelationshipField,
) -> Result<StdHashMap<EntityId, Vec<EntityId>>, RepositoryError> {
let map = self.store.frames.read().unwrap();
let mut out = StdHashMap::new();
for id in ids {
out.insert(
*id,
map.get(id)
.map(|f| read_field(f, field))
.unwrap_or_default(),
);
}
Ok(out)
}
fn get_relationship_count(
&self,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<usize, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| read_field(f, field).len())
.unwrap_or(0))
}
fn get_relationship_in_range(
&self,
id: &EntityId,
field: &FrameRelationshipField,
offset: usize,
limit: usize,
) -> Result<Vec<EntityId>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| {
read_field(f, field)
.into_iter()
.skip(offset)
.take(limit)
.collect()
})
.unwrap_or_default())
}
fn get_relationships_from_right_ids(
&self,
field: &FrameRelationshipField,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
let map = self.store.frames.read().unwrap();
let mut out = Vec::new();
for (id, frame) in map.iter() {
let list = read_field(frame, field);
if right_ids.iter().any(|rid| list.contains(rid)) {
out.push((*id, list));
}
}
Ok(out)
}
fn set_relationship_multi(
&mut self,
field: &FrameRelationshipField,
relationships: Vec<(EntityId, Vec<EntityId>)>,
) -> Result<(), RepositoryError> {
let mut map = self.store.frames.write().unwrap();
for (id, ids) in relationships {
if let Some(frame) = map.get_mut(&id) {
write_field(frame, field, ids);
}
}
Ok(())
}
fn set_relationship(
&mut self,
id: &EntityId,
field: &FrameRelationshipField,
right_ids: &[EntityId],
) -> Result<(), RepositoryError> {
let mut map = self.store.frames.write().unwrap();
if let Some(frame) = map.get_mut(id) {
write_field(frame, field, right_ids.to_vec());
}
Ok(())
}
fn move_relationship_ids(
&mut self,
id: &EntityId,
field: &FrameRelationshipField,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>, RepositoryError> {
let mut map = self.store.frames.write().unwrap();
let Some(frame) = map.get_mut(id) else {
return Ok(Vec::new());
};
let current = read_field(frame, field);
let moved = reorder(current, ids_to_move, new_index);
write_field(frame, field, moved.clone());
Ok(moved)
}
}
pub struct FrameHashMapTableRO<'a> {
store: &'a Store,
}
impl<'a> FrameHashMapTableRO<'a> {
pub fn new(store: &'a Store) -> Self {
Self { store }
}
}
impl<'a> FrameTableRO for FrameHashMapTableRO<'a> {
fn get(&self, id: &EntityId) -> Result<Option<Frame>, RepositoryError> {
Ok(self.store.frames.read().unwrap().get(id).cloned())
}
fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Frame>>, RepositoryError> {
let map = self.store.frames.read().unwrap();
Ok(ids.iter().map(|id| map.get(id).cloned()).collect())
}
fn get_all(&self) -> Result<Vec<Frame>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.values()
.cloned()
.collect())
}
fn get_relationship(
&self,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<Vec<EntityId>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| read_field(f, field))
.unwrap_or_default())
}
fn get_relationship_many(
&self,
ids: &[EntityId],
field: &FrameRelationshipField,
) -> Result<StdHashMap<EntityId, Vec<EntityId>>, RepositoryError> {
let map = self.store.frames.read().unwrap();
let mut out = StdHashMap::new();
for id in ids {
out.insert(
*id,
map.get(id)
.map(|f| read_field(f, field))
.unwrap_or_default(),
);
}
Ok(out)
}
fn get_relationship_count(
&self,
id: &EntityId,
field: &FrameRelationshipField,
) -> Result<usize, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| read_field(f, field).len())
.unwrap_or(0))
}
fn get_relationship_in_range(
&self,
id: &EntityId,
field: &FrameRelationshipField,
offset: usize,
limit: usize,
) -> Result<Vec<EntityId>, RepositoryError> {
Ok(self
.store
.frames
.read()
.unwrap()
.get(id)
.map(|f| {
read_field(f, field)
.into_iter()
.skip(offset)
.take(limit)
.collect()
})
.unwrap_or_default())
}
fn get_relationships_from_right_ids(
&self,
field: &FrameRelationshipField,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>, RepositoryError> {
let map = self.store.frames.read().unwrap();
let mut out = Vec::new();
for (id, frame) in map.iter() {
let list = read_field(frame, field);
if right_ids.iter().any(|rid| list.contains(rid)) {
out.push((*id, list));
}
}
Ok(out)
}
}
fn reorder(current: Vec<EntityId>, ids_to_move: &[EntityId], new_index: i32) -> Vec<EntityId> {
if ids_to_move.is_empty() {
return current;
}
let move_set: std::collections::HashSet<EntityId> = ids_to_move.iter().copied().collect();
let mut remaining: Vec<EntityId> = current
.into_iter()
.filter(|eid| !move_set.contains(eid))
.collect();
let insert_pos = if new_index < 0 || (new_index as usize) > remaining.len() {
remaining.len()
} else {
new_index as usize
};
for (i, &eid) in ids_to_move.iter().enumerate() {
remaining.insert(insert_pos + i, eid);
}
remaining
}