ddex_builder/linker/
auto_linker.rs1use super::{EntityType, LinkerError, LinkingReport, ReferenceGenerator, RelationshipManager};
4use crate::builder::BuildRequest;
5use indexmap::IndexSet;
6
7#[derive(Debug, Clone, Default)]
9pub struct AutoLinker {
10 config: AutoLinkerConfig,
12}
13
14#[derive(Debug, Clone)]
16pub struct AutoLinkerConfig {
17 pub generate_missing_refs: bool,
19
20 pub auto_link_tracks: bool,
22
23 pub auto_link_deals: bool,
25
26 pub validate_references: bool,
28}
29
30impl Default for AutoLinkerConfig {
31 fn default() -> Self {
32 Self {
33 generate_missing_refs: true,
34 auto_link_tracks: true,
35 auto_link_deals: true,
36 validate_references: true,
37 }
38 }
39}
40
41impl AutoLinker {
42 pub fn new() -> Self {
44 Self::with_config(AutoLinkerConfig::default())
45 }
46
47 pub fn with_config(config: AutoLinkerConfig) -> Self {
49 Self { config }
50 }
51
52 pub fn process_request(
54 &self,
55 request: &mut BuildRequest,
56 generator: &mut ReferenceGenerator,
57 relationships: &mut RelationshipManager,
58 ) -> Result<LinkingReport, LinkerError> {
59 let mut report = LinkingReport::default();
60
61 for release in &mut request.releases {
63 for track in &mut release.tracks {
64 if track.resource_reference.is_none() {
65 let reference = generator.generate(EntityType::Resource);
66 track.resource_reference = Some(reference.clone());
67 relationships.register(
68 EntityType::Resource,
69 track.track_id.clone(),
70 reference,
71 );
72 report.generated_refs += 1;
73 }
74 }
75 }
76
77 for release in &mut request.releases {
79 if release.release_reference.is_none() {
81 let reference = generator.generate(EntityType::Release);
82 release.release_reference = Some(reference.clone());
83 relationships.register(
84 EntityType::Release,
85 release.release_id.clone(),
86 reference,
87 );
88 report.generated_refs += 1;
89 }
90
91 if self.config.auto_link_tracks {
93 let release_ref = release.release_reference.as_ref().unwrap();
94 let mut track_refs = IndexSet::new();
95
96 for track in &release.tracks {
97 if let Some(track_ref) = &track.resource_reference {
98 track_refs.insert(track_ref.clone());
99 relationships.add_relationship(
100 release_ref.clone(),
101 track_ref.clone(),
102 );
103 report.linked_resources += 1;
104 }
105 }
106
107 release.resource_references = Some(track_refs.into_iter().collect());
109 }
110 }
111
112 if request.header.message_sender.party_reference.is_none() {
114 let sender_ref = generator.generate(EntityType::Party);
115 request.header.message_sender.party_reference = Some(sender_ref.clone());
116 relationships.register(
117 EntityType::Party,
118 request.header.message_sender.party_id.clone().unwrap_or_default(),
119 sender_ref,
120 );
121 report.generated_refs += 1;
122 }
123
124 if request.header.message_recipient.party_reference.is_none() {
125 let recipient_ref = generator.generate(EntityType::Party);
126 request.header.message_recipient.party_reference = Some(recipient_ref.clone());
127 relationships.register(
128 EntityType::Party,
129 request.header.message_recipient.party_id.clone().unwrap_or_default(),
130 recipient_ref,
131 );
132 report.generated_refs += 1;
133 }
134
135 if self.config.auto_link_deals {
137 for deal in &mut request.deals {
138 if deal.deal_reference.is_none() {
139 let deal_ref = generator.generate(EntityType::Deal);
140 deal.deal_reference = Some(deal_ref.clone());
141 report.generated_refs += 1;
142 }
143
144 if let Some(ref deal_ref) = deal.deal_reference {
146 for release_ref in &deal.release_references {
147 relationships.add_relationship(
148 deal_ref.clone(),
149 release_ref.clone(),
150 );
151 report.linked_deals += 1;
152 }
153 }
154 }
155 }
156
157 if self.config.validate_references {
159 match relationships.validate() {
160 Ok(()) => report.validation_passed = true,
161 Err(errors) => {
162 for error in errors {
164 report.warnings.push(format!("Validation: {}", error));
165 }
166 report.validation_passed = true;
168 }
169 }
170 }
171
172 Ok(report)
173 }
174}