1use super::{
4 Assertion, AssertionKey, AssertionSource, Carrier, DocumentId, Fact, GraphName, MetadataError,
5 ObjectTerm, SourceRecord,
6};
7use crate::node_address::NodeUri;
8use std::collections::{BTreeMap, BTreeSet};
9
10#[derive(Debug, Default)]
33pub struct GraphIndex {
34 facts: Vec<Fact>,
35 assertions: Vec<Assertion>,
36 fact_ids: BTreeMap<String, usize>,
37 assertion_ids: BTreeMap<String, usize>,
38 outgoing: BTreeMap<String, BTreeSet<usize>>,
39 incoming: BTreeMap<String, BTreeSet<usize>>,
40 outgoing_predicate: BTreeMap<(String, String), BTreeSet<usize>>,
41 fact_assertions: BTreeMap<String, BTreeSet<usize>>,
42}
43
44#[derive(Debug, thiserror::Error)]
46pub enum GraphMapError<E> {
47 #[error("node URI binding failed: {0}")]
48 Map(E),
49 #[error(transparent)]
50 Model(#[from] MetadataError),
51}
52
53impl GraphIndex {
54 pub fn new() -> Self {
56 Self::default()
57 }
58
59 pub fn insert(&mut self, assertion: Assertion) -> Result<(), MetadataError> {
65 if !matches!(assertion.key().fact().graph(), GraphName::Default) {
66 return Err(MetadataError::NamedGraphUnsupported);
67 }
68 let assertion_identity = assertion.key().identity();
69 if let Some(&index) = self.assertion_ids.get(&assertion_identity) {
70 self.assertions[index].merge_sources(&assertion)?;
71 return Ok(());
72 }
73
74 let fact = assertion.key().fact();
75 let fact_identity = fact.identity();
76 if !self.fact_ids.contains_key(&fact_identity) {
77 let index = self.facts.len();
78 self.fact_ids.insert(fact_identity.clone(), index);
79 let subject = fact.subject().to_string();
80 let predicate = fact.predicate().to_string();
81 self.outgoing
82 .entry(subject.clone())
83 .or_default()
84 .insert(index);
85 self.outgoing_predicate
86 .entry((subject, predicate))
87 .or_default()
88 .insert(index);
89 if let ObjectTerm::NodeRef(uri) = fact.object() {
90 self.incoming
91 .entry(uri.to_string())
92 .or_default()
93 .insert(index);
94 }
95 self.facts.push(fact.clone());
96 }
97 let assertion_index = self.assertions.len();
98 self.assertion_ids
99 .insert(assertion_identity, assertion_index);
100 self.fact_assertions
101 .entry(fact_identity)
102 .or_default()
103 .insert(assertion_index);
104 self.assertions.push(assertion);
105 Ok(())
106 }
107
108 pub fn facts(&self) -> &[Fact] {
110 &self.facts
111 }
112
113 pub fn assertions(&self) -> &[Assertion] {
115 &self.assertions
116 }
117
118 pub fn try_map_node_uris<E>(
123 &self,
124 mut map: impl FnMut(&NodeUri) -> Result<NodeUri, E>,
125 ) -> Result<Self, GraphMapError<E>> {
126 let mut output = Self::new();
127 for assertion in &self.assertions {
128 let fact = assertion.key().fact();
129 let object = match fact.object() {
130 ObjectTerm::NodeRef(uri) => {
131 ObjectTerm::NodeRef(map(uri).map_err(GraphMapError::Map)?)
132 }
133 ObjectTerm::Value(value) => match value.datatype() {
134 Some(datatype) => ObjectTerm::typed_json(
135 value.value().clone(),
136 map(datatype).map_err(GraphMapError::Map)?,
137 ),
138 None => ObjectTerm::value(value.value().clone()),
139 },
140 };
141 let graph = match fact.graph() {
142 GraphName::Default => GraphName::Default,
143 GraphName::Named(uri) => GraphName::Named(map(uri).map_err(GraphMapError::Map)?),
144 };
145 let mapped_fact = Fact::new(
146 map(fact.subject()).map_err(GraphMapError::Map)?,
147 map(fact.predicate()).map_err(GraphMapError::Map)?,
148 object,
149 graph,
150 );
151 let carrier = match assertion.key().carrier() {
152 Carrier::AttributesFacts(uri) => {
153 Carrier::AttributesFacts(map(uri).map_err(GraphMapError::Map)?)
154 }
155 Carrier::AnnotationsFacts(uri) => {
156 Carrier::AnnotationsFacts(map(uri).map_err(GraphMapError::Map)?)
157 }
158 Carrier::DocumentGraph => Carrier::DocumentGraph,
159 Carrier::Sidecar {
160 target,
161 entry_point,
162 } => Carrier::Sidecar {
163 target: map(target).map_err(GraphMapError::Map)?,
164 entry_point: map(entry_point).map_err(GraphMapError::Map)?,
165 },
166 };
167 let key = AssertionKey::new(assertion.key().owner().clone(), carrier, mapped_fact)
168 .map_err(GraphMapError::Model)?;
169 output
170 .insert(assertion.clone().with_key(key))
171 .map_err(GraphMapError::Model)?;
172 }
173 Ok(output)
174 }
175
176 pub fn apply_source_records(
181 &mut self,
182 owner: &DocumentId,
183 records: &[SourceRecord],
184 ) -> Result<(), MetadataError> {
185 let mut seen = BTreeSet::new();
186 let mut matches = Vec::with_capacity(records.len());
187 for record in records {
188 if record.selector().owner() != owner {
189 return Err(MetadataError::SourceSelectorOwnerMismatch(Box::new(
190 record.selector().clone(),
191 )));
192 }
193 if matches!(record.selector().carrier(), Carrier::Sidecar { .. }) {
194 return Err(MetadataError::SourceSelectorCarrierUnsupported(Box::new(
195 record.selector().clone(),
196 )));
197 }
198 let identity = record.selector().identity();
199 if !seen.insert(identity.clone()) {
200 return Err(MetadataError::DuplicateSourceSelector(Box::new(
201 record.selector().clone(),
202 )));
203 }
204 let Some(&index) = self.assertion_ids.get(&identity) else {
205 return Err(MetadataError::UnmatchedSourceSelector(Box::new(
206 record.selector().clone(),
207 )));
208 };
209 matches.push((index, record.sources()));
210 }
211 for (index, sources) in matches {
212 self.assertions[index].set_source_override(sources.to_vec())?;
213 }
214 Ok(())
215 }
216
217 pub fn rewrite_assertion(
222 &mut self,
223 old: &AssertionKey,
224 replacement: Fact,
225 ) -> Result<(), MetadataError> {
226 let Some(&index) = self.assertion_ids.get(&old.identity()) else {
227 return Err(MetadataError::AssertionNotFound);
228 };
229 let key = AssertionKey::new(old.owner().clone(), old.carrier().clone(), replacement)?;
230 if key.identity() != old.identity() && self.assertion_ids.contains_key(&key.identity()) {
231 return Err(MetadataError::AssertionCollision(Box::new(key)));
232 }
233 let mut assertions = self.assertions.clone();
234 assertions[index] = assertions[index].clone().with_key(key);
235 *self = Self::from_assertions(assertions)?;
236 Ok(())
237 }
238
239 pub fn remove_source_from_owner(
245 &mut self,
246 owner: &DocumentId,
247 source: &AssertionSource,
248 ) -> Result<usize, MetadataError> {
249 if self.assertions.iter().any(|assertion| {
250 assertion.key().owner() == owner && assertion.source_override().is_none()
251 }) {
252 return Err(MetadataError::UnknownSourceOwnership);
253 }
254 let mut removed = 0;
255 let assertions = self
256 .assertions
257 .iter()
258 .filter_map(|assertion| {
259 if assertion.key().owner() != owner || !assertion.sources().contains(source) {
260 return Some(assertion.clone());
261 }
262 removed += 1;
263 let remaining = assertion
264 .sources()
265 .into_iter()
266 .filter(|candidate| candidate != source)
267 .collect::<Vec<_>>();
268 if remaining.is_empty() {
269 None
270 } else {
271 let mut next = assertion.clone();
272 next.set_source_override(remaining)
273 .expect("removing one known source keeps valid owner sources");
274 Some(next)
275 }
276 })
277 .collect();
278 *self = Self::from_assertions(assertions)?;
279 Ok(removed)
280 }
281
282 fn from_assertions(assertions: Vec<Assertion>) -> Result<Self, MetadataError> {
283 let mut graph = Self::new();
284 for assertion in assertions {
285 graph.insert(assertion)?;
286 }
287 Ok(graph)
288 }
289
290 pub fn assertions_for_fact(&self, fact: &Fact) -> Vec<&Assertion> {
292 self.fact_assertions
293 .get(&fact.identity())
294 .into_iter()
295 .flat_map(|ids| ids.iter())
296 .map(|&index| &self.assertions[index])
297 .collect()
298 }
299
300 pub fn outgoing(&self, subject: &NodeUri) -> Vec<&Fact> {
302 self.get(self.outgoing.get(&subject.to_string()))
303 }
304
305 pub fn outgoing_with_predicate(&self, subject: &NodeUri, predicate: &NodeUri) -> Vec<&Fact> {
307 self.get(
308 self.outgoing_predicate
309 .get(&(subject.to_string(), predicate.to_string())),
310 )
311 }
312
313 pub fn incoming(&self, object: &NodeUri) -> Vec<&Fact> {
317 self.get(self.incoming.get(&object.to_string()))
318 }
319
320 fn get(&self, ids: Option<&BTreeSet<usize>>) -> Vec<&Fact> {
321 ids.into_iter()
322 .flat_map(|ids| ids.iter())
323 .map(|&index| &self.facts[index])
324 .collect()
325 }
326}