1use super::Environment;
2use crate::{object, ExpandedDocument, Id, Indexed, IndexedNode, IndexedObject, Node, Object};
3use educe::Educe;
4use indexmap::IndexSet;
5use rdf_types::{
6 vocabulary::{BlankIdVocabulary, IriVocabulary},
7 Generator, Vocabulary,
8};
9use std::collections::HashMap;
10use std::hash::Hash;
11
12#[derive(Clone, Debug, thiserror::Error)]
16#[error("Index `{defined_index}` conflicts with index `{conflicting_index}`")]
17pub struct ConflictingIndexes<T, B> {
18 pub node_id: Id<T, B>,
19 pub defined_index: String,
20 pub conflicting_index: String,
21}
22
23pub type Parts<T, B> = (NodeMapGraph<T, B>, HashMap<Id<T, B>, NodeMapGraph<T, B>>);
24
25#[derive(Educe)]
27#[educe(Default)]
28pub struct NodeMap<T, B> {
29 graphs: HashMap<Id<T, B>, NodeMapGraph<T, B>>,
30 default_graph: NodeMapGraph<T, B>,
31}
32
33impl<T, B> NodeMap<T, B> {
34 pub fn new() -> Self {
35 Self {
36 graphs: HashMap::new(),
37 default_graph: NodeMapGraph::new(),
38 }
39 }
40
41 pub fn into_parts(self) -> Parts<T, B> {
42 (self.default_graph, self.graphs)
43 }
44
45 pub fn iter(&self) -> Iter<T, B> {
46 Iter {
47 default_graph: Some(&self.default_graph),
48 graphs: self.graphs.iter(),
49 }
50 }
51
52 pub fn iter_named(&self) -> std::collections::hash_map::Iter<Id<T, B>, NodeMapGraph<T, B>> {
53 self.graphs.iter()
54 }
55}
56
57impl<T: Eq + Hash, B: Eq + Hash> NodeMap<T, B> {
58 pub fn graph(&self, id: Option<&Id<T, B>>) -> Option<&NodeMapGraph<T, B>> {
59 match id {
60 Some(id) => self.graphs.get(id),
61 None => Some(&self.default_graph),
62 }
63 }
64
65 pub fn graph_mut(&mut self, id: Option<&Id<T, B>>) -> Option<&mut NodeMapGraph<T, B>> {
66 match id {
67 Some(id) => self.graphs.get_mut(id),
68 None => Some(&mut self.default_graph),
69 }
70 }
71
72 pub fn declare_graph(&mut self, id: Id<T, B>) {
73 if let std::collections::hash_map::Entry::Vacant(entry) = self.graphs.entry(id) {
74 entry.insert(NodeMapGraph::new());
75 }
76 }
77
78 pub fn merge(self) -> NodeMapGraph<T, B>
82 where
83 T: Clone,
84 B: Clone,
85 {
86 let mut result = self.default_graph;
87
88 for (_, graph) in self.graphs {
89 result.merge_with(graph)
90 }
91
92 result
93 }
94}
95
96pub struct Iter<'a, T, B> {
97 default_graph: Option<&'a NodeMapGraph<T, B>>,
98 graphs: std::collections::hash_map::Iter<'a, Id<T, B>, NodeMapGraph<T, B>>,
99}
100
101impl<'a, T, B> Iterator for Iter<'a, T, B> {
102 type Item = (Option<&'a Id<T, B>>, &'a NodeMapGraph<T, B>);
103
104 fn next(&mut self) -> Option<Self::Item> {
105 match self.default_graph.take() {
106 Some(default_graph) => Some((None, default_graph)),
107 None => self.graphs.next().map(|(id, graph)| (Some(id), graph)),
108 }
109 }
110}
111
112impl<'a, T, B> IntoIterator for &'a NodeMap<T, B> {
113 type Item = (Option<&'a Id<T, B>>, &'a NodeMapGraph<T, B>);
114 type IntoIter = Iter<'a, T, B>;
115
116 fn into_iter(self) -> Self::IntoIter {
117 self.iter()
118 }
119}
120
121pub struct IntoIter<T, B> {
122 default_graph: Option<NodeMapGraph<T, B>>,
123 graphs: std::collections::hash_map::IntoIter<Id<T, B>, NodeMapGraph<T, B>>,
124}
125
126impl<T, B> Iterator for IntoIter<T, B> {
127 type Item = (Option<Id<T, B>>, NodeMapGraph<T, B>);
128
129 fn next(&mut self) -> Option<Self::Item> {
130 match self.default_graph.take() {
131 Some(default_graph) => Some((None, default_graph)),
132 None => self.graphs.next().map(|(id, graph)| (Some(id), graph)),
133 }
134 }
135}
136
137impl<T, B> IntoIterator for NodeMap<T, B> {
138 type Item = (Option<Id<T, B>>, NodeMapGraph<T, B>);
139 type IntoIter = IntoIter<T, B>;
140
141 fn into_iter(self) -> Self::IntoIter {
142 IntoIter {
143 default_graph: Some(self.default_graph),
144 graphs: self.graphs.into_iter(),
145 }
146 }
147}
148
149#[derive(Educe)]
150#[educe(Default)]
151pub struct NodeMapGraph<T, B> {
152 nodes: HashMap<Id<T, B>, IndexedNode<T, B>>,
153}
154
155impl<T, B> NodeMapGraph<T, B> {
156 pub fn new() -> Self {
157 Self {
158 nodes: HashMap::new(),
159 }
160 }
161}
162
163pub type DeclareNodeResult<'a, T, B> =
164 Result<&'a mut Indexed<Node<T, B>>, ConflictingIndexes<T, B>>;
165
166impl<T: Eq + Hash, B: Eq + Hash> NodeMapGraph<T, B> {
167 pub fn contains(&self, id: &Id<T, B>) -> bool {
168 self.nodes.contains_key(id)
169 }
170
171 pub fn get(&self, id: &Id<T, B>) -> Option<&IndexedNode<T, B>> {
172 self.nodes.get(id)
173 }
174
175 pub fn get_mut(&mut self, id: &Id<T, B>) -> Option<&mut IndexedNode<T, B>> {
176 self.nodes.get_mut(id)
177 }
178
179 pub fn declare_node(&mut self, id: Id<T, B>, index: Option<&str>) -> DeclareNodeResult<T, B>
180 where
181 T: Clone,
182 B: Clone,
183 {
184 if let Some(entry) = self.nodes.get_mut(&id) {
185 match (entry.index(), index) {
186 (Some(entry_index), Some(index)) => {
187 if entry_index != index {
188 return Err(ConflictingIndexes {
189 node_id: id,
190 defined_index: entry_index.to_string(),
191 conflicting_index: index.to_string(),
192 });
193 }
194 }
195 (None, Some(index)) => entry.set_index(Some(index.to_owned())),
196 _ => (),
197 }
198 } else {
199 self.nodes.insert(
200 id.clone(),
201 Indexed::new(Node::with_id(id.clone()), index.map(ToOwned::to_owned)),
202 );
203 }
204
205 Ok(self.nodes.get_mut(&id).unwrap())
206 }
207
208 pub fn merge_with(&mut self, other: Self)
212 where
213 T: Clone,
214 B: Clone,
215 {
216 for (_, node) in other {
217 self.merge_node(node)
218 }
219 }
220
221 pub fn merge_node(&mut self, node: IndexedNode<T, B>)
230 where
231 T: Clone,
232 B: Clone,
233 {
234 let (node, index) = node.into_parts();
235
236 if let Some(id) = &node.id {
237 if let Some(entry) = self.nodes.get_mut(id) {
238 if let Some(index) = index {
239 entry.set_index(Some(index))
240 }
241 } else {
242 self.nodes
243 .insert(id.clone(), Indexed::new(Node::with_id(id.clone()), index));
244 }
245
246 let flat_node = self.nodes.get_mut(id).unwrap();
247
248 if let Some(types) = node.types {
249 flat_node.types_mut_or_default().extend(types);
250 }
251
252 flat_node.set_graph_entry(node.graph);
253 flat_node.set_included(node.included);
254 flat_node.properties_mut().extend_unique(node.properties);
255
256 if let Some(props) = node.reverse_properties {
257 flat_node
258 .reverse_properties_or_default()
259 .extend_unique(props);
260 }
261 }
262 }
263
264 pub fn nodes(&self) -> NodeMapGraphNodes<T, B> {
265 self.nodes.values()
266 }
267
268 pub fn into_nodes(self) -> IntoNodeMapGraphNodes<T, B> {
269 self.nodes.into_values()
270 }
271}
272
273pub type NodeMapGraphNodes<'a, T, B> =
274 std::collections::hash_map::Values<'a, Id<T, B>, IndexedNode<T, B>>;
275pub type IntoNodeMapGraphNodes<T, B> =
276 std::collections::hash_map::IntoValues<Id<T, B>, IndexedNode<T, B>>;
277
278impl<T, B> IntoIterator for NodeMapGraph<T, B> {
279 type Item = (Id<T, B>, IndexedNode<T, B>);
280 type IntoIter = std::collections::hash_map::IntoIter<Id<T, B>, IndexedNode<T, B>>;
281
282 fn into_iter(self) -> Self::IntoIter {
283 self.nodes.into_iter()
284 }
285}
286
287impl<'a, T, B> IntoIterator for &'a NodeMapGraph<T, B> {
288 type Item = (&'a Id<T, B>, &'a IndexedNode<T, B>);
289 type IntoIter = std::collections::hash_map::Iter<'a, Id<T, B>, IndexedNode<T, B>>;
290
291 fn into_iter(self) -> Self::IntoIter {
292 self.nodes.iter()
293 }
294}
295
296impl<T: Clone + Eq + Hash, B: Clone + Eq + Hash> ExpandedDocument<T, B> {
297 pub fn generate_node_map_with<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
298 &self,
299 vocabulary: &mut V,
300 generator: G,
301 ) -> Result<NodeMap<T, B>, ConflictingIndexes<T, B>> {
302 let mut node_map: NodeMap<T, B> = NodeMap::new();
303 let mut env: Environment<V, G> = Environment::new(vocabulary, generator);
304 for object in self {
305 extend_node_map(&mut env, &mut node_map, object, None)?;
306 }
307 Ok(node_map)
308 }
309}
310
311pub type ExtendNodeMapResult<V> = Result<
312 IndexedObject<<V as IriVocabulary>::Iri, <V as BlankIdVocabulary>::BlankId>,
313 ConflictingIndexes<<V as IriVocabulary>::Iri, <V as BlankIdVocabulary>::BlankId>,
314>;
315
316fn extend_node_map<N: Vocabulary, G: Generator<N>>(
318 env: &mut Environment<N, G>,
319 node_map: &mut NodeMap<N::Iri, N::BlankId>,
320 element: &IndexedObject<N::Iri, N::BlankId>,
321 active_graph: Option<&Id<N::Iri, N::BlankId>>,
322) -> ExtendNodeMapResult<N>
323where
324 N::Iri: Clone + Eq + Hash,
325 N::BlankId: Clone + Eq + Hash,
326{
327 match element.inner() {
328 Object::Value(value) => {
329 let flat_value = value.clone();
330 Ok(Indexed::new(
331 Object::Value(flat_value),
332 element.index().map(ToOwned::to_owned),
333 ))
334 }
335 Object::List(list) => {
336 let mut flat_list = Vec::new();
337
338 for item in list {
339 flat_list.push(extend_node_map(env, node_map, item, active_graph)?);
340 }
341
342 Ok(Indexed::new(
343 Object::List(object::List::new(flat_list)),
344 element.index().map(ToOwned::to_owned),
345 ))
346 }
347 Object::Node(node) => {
348 let flat_node =
349 extend_node_map_from_node(env, node_map, node, element.index(), active_graph)?;
350 Ok(flat_node.map_inner(Object::node))
351 }
352 }
353}
354
355type ExtendNodeMapFromNodeResult<T, B> = Result<Indexed<Node<T, B>>, ConflictingIndexes<T, B>>;
356
357fn extend_node_map_from_node<N: Vocabulary, G: Generator<N>>(
358 env: &mut Environment<N, G>,
359 node_map: &mut NodeMap<N::Iri, N::BlankId>,
360 node: &Node<N::Iri, N::BlankId>,
361 index: Option<&str>,
362 active_graph: Option<&Id<N::Iri, N::BlankId>>,
363) -> ExtendNodeMapFromNodeResult<N::Iri, N::BlankId>
364where
365 N::Iri: Clone + Eq + Hash,
366 N::BlankId: Clone + Eq + Hash,
367{
368 let id = env.assign_node_id(node.id.as_ref());
369
370 {
371 let flat_node = node_map
372 .graph_mut(active_graph)
373 .unwrap()
374 .declare_node(id.clone(), index)?;
375
376 if let Some(entry) = node.types.as_deref() {
377 flat_node.types = Some(
378 entry
379 .iter()
380 .map(|ty| env.assign_node_id(Some(ty)))
381 .collect(),
382 );
383 }
384 }
385
386 if let Some(graph_entry) = node.graph_entry() {
387 node_map.declare_graph(id.clone());
388
389 let mut flat_graph = IndexSet::new();
390 for object in graph_entry.iter() {
391 let flat_object = extend_node_map(env, node_map, object, Some(&id))?;
392 flat_graph.insert(flat_object);
393 }
394
395 let flat_node = node_map
396 .graph_mut(active_graph)
397 .unwrap()
398 .get_mut(&id)
399 .unwrap();
400 match flat_node.graph_entry_mut() {
401 Some(graph) => graph.extend(flat_graph),
402 None => flat_node.set_graph_entry(Some(flat_graph)),
403 }
404 }
405
406 if let Some(included_entry) = node.included_entry() {
407 for inode in included_entry {
408 extend_node_map_from_node(env, node_map, inode.inner(), inode.index(), active_graph)?;
409 }
410 }
411
412 for (property, objects) in node.properties() {
413 let mut flat_objects = Vec::new();
414 for object in objects {
415 let flat_object = extend_node_map(env, node_map, object, active_graph)?;
416 flat_objects.push(flat_object);
417 }
418 node_map
419 .graph_mut(active_graph)
420 .unwrap()
421 .get_mut(&id)
422 .unwrap()
423 .properties_mut()
424 .insert_all_unique(property.clone(), flat_objects)
425 }
426
427 if let Some(reverse_properties) = node.reverse_properties_entry() {
428 for (property, nodes) in reverse_properties.iter() {
429 for subject in nodes {
430 let flat_subject = extend_node_map_from_node(
431 env,
432 node_map,
433 subject.inner(),
434 subject.index(),
435 active_graph,
436 )?;
437
438 let subject_id = flat_subject.id.as_ref().unwrap();
439
440 let flat_subject = node_map
441 .graph_mut(active_graph)
442 .unwrap()
443 .get_mut(subject_id)
444 .unwrap();
445
446 flat_subject.properties_mut().insert_unique(
447 property.clone(),
448 Indexed::none(Object::node(Node::with_id(id.clone()))),
449 )
450 }
451
452 }
472 }
473
474 Ok(Indexed::new(Node::with_id(id), None))
475}