qleany-common 1.7.4

Shared entities, database, events, and undo/redo infrastructure for Qleany
Documentation
// Generated by Qleany v1.7.0 from common_entity_table.tera

// ═══════════════════════════════════════════════════════════════════════
// Entity WITH forward relationships — explicit struct implementation
// ═══════════════════════════════════════════════════════════════════════

use crate::database::hashmap_store::{
    HashMapStore, delete_from_backward_junction, junction_get, junction_remove, junction_set,
};
use crate::entities::Workspace;
use crate::error::RepositoryError;
use crate::types::EntityId;
use crate::{impl_relationship_methods, impl_write_relationship_methods};
use im::HashMap;
use std::sync::RwLock;

use super::workspace_repository::WorkspaceRelationshipField;
use super::workspace_repository::WorkspaceTable;
use super::workspace_repository::WorkspaceTableRO;

pub struct WorkspaceHashMapTable<'a> {
    store: &'a HashMapStore,
}

impl<'a> WorkspaceHashMapTable<'a> {
    pub fn new(store: &'a HashMapStore) -> Self {
        Self { store }
    }

    fn resolve_junction(
        &self,
        field: &WorkspaceRelationshipField,
    ) -> &RwLock<HashMap<EntityId, Vec<EntityId>>> {
        match field {
            WorkspaceRelationshipField::Entities => &self.store.jn_entity_from_workspace_entities,
            WorkspaceRelationshipField::Features => &self.store.jn_feature_from_workspace_features,
            WorkspaceRelationshipField::Global => &self.store.jn_global_from_workspace_global,
            WorkspaceRelationshipField::UserInterface => {
                &self.store.jn_user_interface_from_workspace_user_interface
            }
        }
    }

    fn hydrate(&self, entity: &mut Workspace) {
        if let Some(val) = junction_get(&self.store.jn_global_from_workspace_global, &entity.id)
            .into_iter()
            .next()
        {
            entity.global = val;
        }
        entity.entities = junction_get(&self.store.jn_entity_from_workspace_entities, &entity.id);
        entity.features = junction_get(&self.store.jn_feature_from_workspace_features, &entity.id);
        if let Some(val) = junction_get(
            &self.store.jn_user_interface_from_workspace_user_interface,
            &entity.id,
        )
        .into_iter()
        .next()
        {
            entity.user_interface = val;
        }
    }
}

impl<'a> WorkspaceTable for WorkspaceHashMapTable<'a> {
    fn create(&mut self, entity: &Workspace) -> Result<Workspace, RepositoryError> {
        self.create_multi(std::slice::from_ref(entity))
            .map(|v| v.into_iter().next().unwrap())
    }

    fn create_multi(&mut self, entities: &[Workspace]) -> Result<Vec<Workspace>, RepositoryError> {
        let mut created = Vec::with_capacity(entities.len());
        let mut workspace_map = self.store.workspaces.write().unwrap();

        for entity in entities {
            let new_entity = if entity.id == EntityId::default() {
                let id = self.store.next_id("workspace");
                Workspace {
                    id,
                    ..entity.clone()
                }
            } else {
                if workspace_map.contains_key(&entity.id) {
                    return Err(RepositoryError::DuplicateId {
                        entity: "Workspace",
                        id: entity.id,
                    });
                }
                entity.clone()
            };

            // one-to-one constraint check: ensure global is not already referenced by another workspace
            {
                let jn = self.store.jn_global_from_workspace_global.read().unwrap();
                for (&existing_id, right_ids) in jn.iter() {
                    if existing_id != new_entity.id && right_ids.contains(&new_entity.global) {
                        return Err(RepositoryError::ConstraintViolation(format!(
                            "One-to-one constraint violation: Global {} is already referenced by Workspace {}",
                            new_entity.global, existing_id
                        )));
                    }
                }
            }
            // one-to-one constraint check: ensure user_interface is not already referenced by another workspace
            {
                let jn = self
                    .store
                    .jn_user_interface_from_workspace_user_interface
                    .read()
                    .unwrap();
                for (&existing_id, right_ids) in jn.iter() {
                    if existing_id != new_entity.id
                        && right_ids.contains(&new_entity.user_interface)
                    {
                        return Err(RepositoryError::ConstraintViolation(format!(
                            "One-to-one constraint violation: UserInterface {} is already referenced by Workspace {}",
                            new_entity.user_interface, existing_id
                        )));
                    }
                }
            }

            workspace_map.insert(new_entity.id, new_entity.clone());

            junction_set(
                &self.store.jn_entity_from_workspace_entities,
                new_entity.id,
                new_entity.entities.clone(),
            );
            junction_set(
                &self.store.jn_feature_from_workspace_features,
                new_entity.id,
                new_entity.features.clone(),
            );
            junction_set(
                &self.store.jn_global_from_workspace_global,
                new_entity.id,
                vec![new_entity.global],
            );
            junction_set(
                &self.store.jn_user_interface_from_workspace_user_interface,
                new_entity.id,
                vec![new_entity.user_interface],
            );

            created.push(new_entity);
        }
        Ok(created)
    }

    fn get(&self, id: &EntityId) -> Result<Option<Workspace>, RepositoryError> {
        let workspace_map = self.store.workspaces.read().unwrap();
        match workspace_map.get(id) {
            Some(entity) => {
                let mut e = entity.clone();
                drop(workspace_map);
                self.hydrate(&mut e);
                Ok(Some(e))
            }
            None => Ok(None),
        }
    }

    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Workspace>>, RepositoryError> {
        let mut result = Vec::with_capacity(ids.len());
        for id in ids {
            result.push(self.get(id)?);
        }
        Ok(result)
    }

    fn get_all(&self) -> Result<Vec<Workspace>, RepositoryError> {
        let workspace_map = self.store.workspaces.read().unwrap();
        let entries: Vec<Workspace> = workspace_map.values().cloned().collect();
        drop(workspace_map);
        let mut result = Vec::with_capacity(entries.len());
        for mut entity in entries {
            self.hydrate(&mut entity);
            result.push(entity);
        }
        Ok(result)
    }

    fn update(&mut self, entity: &Workspace) -> Result<Workspace, RepositoryError> {
        self.update_multi(std::slice::from_ref(entity))
            .map(|v| v.into_iter().next().unwrap())
    }

    // Scalar-only update: writes entity data but does NOT touch junction tables.
    fn update_multi(&mut self, entities: &[Workspace]) -> Result<Vec<Workspace>, RepositoryError> {
        let mut workspace_map = self.store.workspaces.write().unwrap();
        for entity in entities {
            workspace_map.insert(entity.id, entity.clone());
        }
        drop(workspace_map);
        let ids: Vec<EntityId> = entities.iter().map(|e| e.id).collect();
        let result = self.get_multi(&ids)?;
        Ok(result.into_iter().flatten().collect())
    }

    fn update_with_relationships(
        &mut self,
        entity: &Workspace,
    ) -> Result<Workspace, 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: &[Workspace],
    ) -> Result<Vec<Workspace>, RepositoryError> {
        let mut workspace_map = self.store.workspaces.write().unwrap();
        for entity in entities {
            // one-to-one constraint check: ensure global is not already referenced by another workspace
            {
                let jn = self.store.jn_global_from_workspace_global.read().unwrap();
                for (&existing_id, right_ids) in jn.iter() {
                    if existing_id != entity.id && right_ids.contains(&entity.global) {
                        return Err(RepositoryError::ConstraintViolation(format!(
                            "One-to-one constraint violation: Global {} is already referenced by Workspace {}",
                            entity.global, existing_id
                        )));
                    }
                }
            }
            // one-to-one constraint check: ensure user_interface is not already referenced by another workspace
            {
                let jn = self
                    .store
                    .jn_user_interface_from_workspace_user_interface
                    .read()
                    .unwrap();
                for (&existing_id, right_ids) in jn.iter() {
                    if existing_id != entity.id && right_ids.contains(&entity.user_interface) {
                        return Err(RepositoryError::ConstraintViolation(format!(
                            "One-to-one constraint violation: UserInterface {} is already referenced by Workspace {}",
                            entity.user_interface, existing_id
                        )));
                    }
                }
            }
            workspace_map.insert(entity.id, entity.clone());

            junction_set(
                &self.store.jn_global_from_workspace_global,
                entity.id,
                vec![entity.global],
            );
            junction_set(
                &self.store.jn_entity_from_workspace_entities,
                entity.id,
                entity.entities.clone(),
            );
            junction_set(
                &self.store.jn_feature_from_workspace_features,
                entity.id,
                entity.features.clone(),
            );
            junction_set(
                &self.store.jn_user_interface_from_workspace_user_interface,
                entity.id,
                vec![entity.user_interface],
            );
        }
        drop(workspace_map);
        let ids: Vec<EntityId> = entities.iter().map(|e| e.id).collect();
        let result = self.get_multi(&ids)?;
        Ok(result.into_iter().flatten().collect())
    }

    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 mut workspace_map = self.store.workspaces.write().unwrap();
        for id in ids {
            workspace_map.remove(id);

            // Remove forward junction entries

            junction_remove(&self.store.jn_global_from_workspace_global, id);
            junction_remove(&self.store.jn_entity_from_workspace_entities, id);
            junction_remove(&self.store.jn_feature_from_workspace_features, id);
            junction_remove(
                &self.store.jn_user_interface_from_workspace_user_interface,
                id,
            );

            // Clean up backward references (uses the owning entity's forward junction)

            delete_from_backward_junction(&self.store.jn_workspace_from_root_workspace, id);
        }
        Ok(())
    }

    impl_write_relationship_methods!(WorkspaceHashMapTable<'a>, WorkspaceRelationshipField);
}

pub struct WorkspaceHashMapTableRO<'a> {
    store: &'a HashMapStore,
}

impl<'a> WorkspaceHashMapTableRO<'a> {
    pub fn new(store: &'a HashMapStore) -> Self {
        Self { store }
    }

    fn resolve_junction(
        &self,
        field: &WorkspaceRelationshipField,
    ) -> &RwLock<HashMap<EntityId, Vec<EntityId>>> {
        match field {
            WorkspaceRelationshipField::Entities => &self.store.jn_entity_from_workspace_entities,
            WorkspaceRelationshipField::Features => &self.store.jn_feature_from_workspace_features,
            WorkspaceRelationshipField::Global => &self.store.jn_global_from_workspace_global,
            WorkspaceRelationshipField::UserInterface => {
                &self.store.jn_user_interface_from_workspace_user_interface
            }
        }
    }

    fn hydrate(&self, entity: &mut Workspace) {
        if let Some(val) = junction_get(&self.store.jn_global_from_workspace_global, &entity.id)
            .into_iter()
            .next()
        {
            entity.global = val;
        }
        entity.entities = junction_get(&self.store.jn_entity_from_workspace_entities, &entity.id);
        entity.features = junction_get(&self.store.jn_feature_from_workspace_features, &entity.id);
        if let Some(val) = junction_get(
            &self.store.jn_user_interface_from_workspace_user_interface,
            &entity.id,
        )
        .into_iter()
        .next()
        {
            entity.user_interface = val;
        }
    }
}

impl<'a> WorkspaceTableRO for WorkspaceHashMapTableRO<'a> {
    fn get(&self, id: &EntityId) -> Result<Option<Workspace>, RepositoryError> {
        let workspace_map = self.store.workspaces.read().unwrap();
        match workspace_map.get(id) {
            Some(entity) => {
                let mut e = entity.clone();
                drop(workspace_map);
                self.hydrate(&mut e);
                Ok(Some(e))
            }
            None => Ok(None),
        }
    }

    fn get_multi(&self, ids: &[EntityId]) -> Result<Vec<Option<Workspace>>, RepositoryError> {
        let mut result = Vec::with_capacity(ids.len());
        for id in ids {
            result.push(self.get(id)?);
        }
        Ok(result)
    }

    fn get_all(&self) -> Result<Vec<Workspace>, RepositoryError> {
        let workspace_map = self.store.workspaces.read().unwrap();
        let entries: Vec<Workspace> = workspace_map.values().cloned().collect();
        drop(workspace_map);
        let mut result = Vec::with_capacity(entries.len());
        for mut entity in entries {
            self.hydrate(&mut entity);
            result.push(entity);
        }
        Ok(result)
    }

    impl_relationship_methods!(WorkspaceHashMapTableRO<'a>, WorkspaceRelationshipField);
}