ddex_builder/linker/
auto_linker.rs1use super::{EntityType, LinkingError, 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, LinkingError> {
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(EntityType::Resource, track.track_id.clone(), reference);
68 report.generated_refs += 1;
69 }
70 }
71 }
72
73 for release in &mut request.releases {
75 if release.release_reference.is_none() {
77 let reference = generator.generate(EntityType::Release);
78 release.release_reference = Some(reference.clone());
79 relationships.register(EntityType::Release, release.release_id.clone(), reference);
80 report.generated_refs += 1;
81 }
82
83 if self.config.auto_link_tracks {
85 let release_ref = release.release_reference.as_ref().unwrap();
86 let mut track_refs = IndexSet::new();
87
88 for track in &release.tracks {
89 if let Some(track_ref) = &track.resource_reference {
90 track_refs.insert(track_ref.clone());
91 relationships.add_relationship(release_ref.clone(), track_ref.clone());
92 report.linked_resources += 1;
93 }
94 }
95
96 release.resource_references = Some(track_refs.into_iter().collect());
98 }
99 }
100
101 if request.header.message_sender.party_reference.is_none() {
103 let sender_ref = generator.generate(EntityType::Party);
104 request.header.message_sender.party_reference = Some(sender_ref.clone());
105 relationships.register(
106 EntityType::Party,
107 request
108 .header
109 .message_sender
110 .party_id
111 .clone()
112 .unwrap_or_default(),
113 sender_ref,
114 );
115 report.generated_refs += 1;
116 }
117
118 if request.header.message_recipient.party_reference.is_none() {
119 let recipient_ref = generator.generate(EntityType::Party);
120 request.header.message_recipient.party_reference = Some(recipient_ref.clone());
121 relationships.register(
122 EntityType::Party,
123 request
124 .header
125 .message_recipient
126 .party_id
127 .clone()
128 .unwrap_or_default(),
129 recipient_ref,
130 );
131 report.generated_refs += 1;
132 }
133
134 if self.config.auto_link_deals {
136 for deal in &mut request.deals {
137 if deal.deal_reference.is_none() {
138 let deal_ref = generator.generate(EntityType::Deal);
139 deal.deal_reference = Some(deal_ref.clone());
140 report.generated_refs += 1;
141 }
142
143 if let Some(ref deal_ref) = deal.deal_reference {
145 for release_ref in &deal.release_references {
146 relationships.add_relationship(deal_ref.clone(), release_ref.clone());
147 report.linked_deals += 1;
148 }
149 }
150 }
151 }
152
153 if self.config.validate_references {
155 match relationships.validate() {
156 Ok(()) => report.validation_passed = true,
157 Err(errors) => {
158 for error in errors {
160 report.warnings.push(format!("Validation: {}", error));
161 }
162 report.validation_passed = true;
164 }
165 }
166 }
167
168 Ok(report)
169 }
170}