use super::types::{EntityType, LinkingError};
use indexmap::{IndexMap, IndexSet};
#[derive(Debug, Clone, Default)]
pub struct RelationshipManager {
registry: IndexMap<EntityType, IndexMap<String, String>>,
reverse_lookup: IndexMap<String, (EntityType, String)>,
relationships: IndexMap<String, IndexSet<String>>,
}
impl RelationshipManager {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, entity_type: EntityType, id: String, reference: String) {
self.registry
.entry(entity_type)
.or_insert_with(IndexMap::new)
.insert(id.clone(), reference.clone());
self.reverse_lookup.insert(reference, (entity_type, id));
}
pub fn get_reference(&self, entity_type: EntityType, id: &str) -> Option<String> {
self.registry
.get(&entity_type)
.and_then(|refs| refs.get(id))
.cloned()
}
pub fn get_entity_by_reference(&self, reference: &str) -> Option<(EntityType, String)> {
self.reverse_lookup.get(reference).cloned()
}
pub fn reference_exists(&self, reference: &str) -> bool {
self.reverse_lookup.contains_key(reference)
}
pub fn add_relationship(&mut self, from_ref: String, to_ref: String) {
self.relationships
.entry(from_ref)
.or_insert_with(IndexSet::new)
.insert(to_ref);
}
pub fn get_relationships(&self, reference: &str) -> Option<&IndexSet<String>> {
self.relationships.get(reference)
}
pub fn get_all(&self) -> IndexMap<EntityType, IndexMap<String, String>> {
self.registry.clone()
}
pub fn validate(&self) -> Result<(), Vec<LinkingError>> {
let mut errors = Vec::new();
for (from_ref, to_refs) in &self.relationships {
if !self.reference_exists(from_ref) {
errors.push(LinkingError::OrphanedReference(from_ref.clone()));
}
for to_ref in to_refs {
if !self.reference_exists(to_ref) {
errors.push(LinkingError::BrokenReference {
from: from_ref.clone(),
to: to_ref.clone(),
});
}
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
pub fn get_statistics(&self) -> RelationshipStatistics {
RelationshipStatistics {
total_entities: self.reverse_lookup.len(),
releases: self
.registry
.get(&EntityType::Release)
.map(|m| m.len())
.unwrap_or(0),
resources: self
.registry
.get(&EntityType::Resource)
.map(|m| m.len())
.unwrap_or(0),
parties: self
.registry
.get(&EntityType::Party)
.map(|m| m.len())
.unwrap_or(0),
deals: self
.registry
.get(&EntityType::Deal)
.map(|m| m.len())
.unwrap_or(0),
total_relationships: self.relationships.values().map(|s| s.len()).sum(),
}
}
}
#[derive(Debug, Clone)]
pub struct RelationshipStatistics {
pub total_entities: usize,
pub releases: usize,
pub resources: usize,
pub parties: usize,
pub deals: usize,
pub total_relationships: usize,
}