ddex_parser/transform/
resolve.rs

1// core/src/transform/resolve.rs
2//! Reference resolution
3
4use ddex_core::models::graph::{Deal, ERNMessage, Party, Release, Resource};
5use std::collections::HashMap;
6
7pub struct ReferenceResolver {
8    party_map: HashMap<String, Party>,
9    resource_map: HashMap<String, Resource>,
10    release_map: HashMap<String, Release>,
11    deal_map: HashMap<String, Deal>,
12}
13
14impl Default for ReferenceResolver {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl ReferenceResolver {
21    pub fn new() -> Self {
22        Self {
23            party_map: HashMap::new(),
24            resource_map: HashMap::new(),
25            release_map: HashMap::new(),
26            deal_map: HashMap::new(),
27        }
28    }
29
30    pub fn build_maps(&mut self, message: &ERNMessage) {
31        // Build party map
32        for party in &message.parties {
33            if let Some(id) = party.party_id.first() {
34                self.party_map.insert(id.value.clone(), party.clone());
35            }
36        }
37
38        // Build resource map
39        for resource in &message.resources {
40            self.resource_map
41                .insert(resource.resource_reference.clone(), resource.clone());
42        }
43
44        // Build release map
45        for release in &message.releases {
46            self.release_map
47                .insert(release.release_reference.clone(), release.clone());
48        }
49
50        // Build deal map
51        for (idx, deal) in message.deals.iter().enumerate() {
52            let key = deal
53                .deal_reference
54                .clone()
55                .unwrap_or_else(|| format!("deal_{}", idx));
56            self.deal_map.insert(key, deal.clone());
57        }
58    }
59
60    pub fn resolve_party_reference(&self, reference: &str) -> Option<&Party> {
61        self.party_map.get(reference)
62    }
63
64    pub fn resolve_resource_reference(&self, reference: &str) -> Option<&Resource> {
65        self.resource_map.get(reference)
66    }
67
68    pub fn resolve_release_reference(&self, reference: &str) -> Option<&Release> {
69        self.release_map.get(reference)
70    }
71
72    pub fn validate_references(&self, message: &ERNMessage) -> Vec<UnresolvedReference> {
73        let mut unresolved = Vec::new();
74
75        // Check release resource references
76        for release in &message.releases {
77            for rref in &release.release_resource_reference_list {
78                if !self.resource_map.contains_key(&rref.resource_reference) {
79                    unresolved.push(UnresolvedReference {
80                        reference_type: "Resource".to_string(),
81                        reference_value: rref.resource_reference.clone(),
82                        location: format!(
83                            "Release/{}/ResourceReference",
84                            release.release_reference
85                        ),
86                    });
87                }
88            }
89        }
90
91        // Check deal release references
92        for (idx, deal) in message.deals.iter().enumerate() {
93            for release_ref in &deal.deal_release_reference {
94                if !self.release_map.contains_key(release_ref as &str) {
95                    unresolved.push(UnresolvedReference {
96                        reference_type: "Release".to_string(),
97                        reference_value: release_ref.clone(),
98                        location: format!("Deal[{}]/ReleaseReference", idx),
99                    });
100                }
101            }
102        }
103
104        unresolved
105    }
106}
107
108#[derive(Debug, Clone)]
109pub struct UnresolvedReference {
110    pub reference_type: String,
111    pub reference_value: String,
112    pub location: String,
113}