ddex_builder/linker/
relationship_manager.rs1use super::types::{EntityType, LinkerError};
4use indexmap::{IndexMap, IndexSet};
5
6#[derive(Debug, Clone, Default)]
8pub struct RelationshipManager {
9 registry: IndexMap<EntityType, IndexMap<String, String>>,
12
13 reverse_lookup: IndexMap<String, (EntityType, String)>,
15
16 relationships: IndexMap<String, IndexSet<String>>,
18}
19
20impl RelationshipManager {
21 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn register(&mut self, entity_type: EntityType, id: String, reference: String) {
28 self.registry
30 .entry(entity_type)
31 .or_insert_with(IndexMap::new)
32 .insert(id.clone(), reference.clone());
33
34 self.reverse_lookup.insert(reference, (entity_type, id));
36 }
37
38 pub fn get_reference(&self, entity_type: EntityType, id: &str) -> Option<String> {
40 self.registry
41 .get(&entity_type)
42 .and_then(|refs| refs.get(id))
43 .cloned()
44 }
45
46 pub fn get_entity_by_reference(&self, reference: &str) -> Option<(EntityType, String)> {
48 self.reverse_lookup.get(reference).cloned()
49 }
50
51 pub fn reference_exists(&self, reference: &str) -> bool {
53 self.reverse_lookup.contains_key(reference)
54 }
55
56 pub fn add_relationship(&mut self, from_ref: String, to_ref: String) {
58 self.relationships
59 .entry(from_ref)
60 .or_insert_with(IndexSet::new)
61 .insert(to_ref);
62 }
63
64 pub fn get_relationships(&self, reference: &str) -> Option<&IndexSet<String>> {
66 self.relationships.get(reference)
67 }
68
69 pub fn get_all(&self) -> IndexMap<EntityType, IndexMap<String, String>> {
71 self.registry.clone()
72 }
73
74 pub fn validate(&self) -> Result<(), Vec<LinkerError>> {
76 let mut errors = Vec::new();
77
78 for (from_ref, to_refs) in &self.relationships {
80 if !self.reference_exists(from_ref) {
81 errors.push(LinkerError::OrphanedReference(from_ref.clone()));
82 }
83
84 for to_ref in to_refs {
85 if !self.reference_exists(to_ref) {
86 errors.push(LinkerError::BrokenReference {
87 from: from_ref.clone(),
88 to: to_ref.clone(),
89 });
90 }
91 }
92 }
93
94 if errors.is_empty() {
95 Ok(())
96 } else {
97 Err(errors)
98 }
99 }
100
101 pub fn get_statistics(&self) -> RelationshipStatistics {
103 RelationshipStatistics {
104 total_entities: self.reverse_lookup.len(),
105 releases: self.registry.get(&EntityType::Release).map(|m| m.len()).unwrap_or(0),
106 resources: self.registry.get(&EntityType::Resource).map(|m| m.len()).unwrap_or(0),
107 parties: self.registry.get(&EntityType::Party).map(|m| m.len()).unwrap_or(0),
108 deals: self.registry.get(&EntityType::Deal).map(|m| m.len()).unwrap_or(0),
109 total_relationships: self.relationships.values().map(|s| s.len()).sum(),
110 }
111 }
112}
113
114#[derive(Debug, Clone)]
116pub struct RelationshipStatistics {
117 pub total_entities: usize,
118 pub releases: usize,
119 pub resources: usize,
120 pub parties: usize,
121 pub deals: usize,
122 pub total_relationships: usize,
123}