json_ld_core/flattening/
node_map.rs

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/// Conflicting indexes error.
13///
14/// Raised when a single node is declared with two different indexes.
15#[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/// Node identifier to node definition map.
26#[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	/// Merge all the graphs into a single `NodeMapGraph`.
79	///
80	/// The order in which graphs are merged is not defined.
81	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	/// Merge this graph with `other`.
209	///
210	/// This calls [`merge_node`](Self::merge_node) with every node of `other`.
211	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	/// Merge the given `node` into the graph.
222	///
223	/// The `node` must has an identifier, or this function will have no effect.
224	/// If there is already a node with the same identifier:
225	/// - The index of `node`, if any, overrides the previously existing index.
226	/// - The list of `node` types is concatenated after the preexisting types.
227	/// - The graph and imported values are overridden.
228	/// - Properties and reverse properties are merged.
229	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
316/// Extends the `NodeMap` with the given `element` of an expanded JSON-LD document.
317fn 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			// let mut flat_nodes = Vec::new();
453			// for node in nodes {
454			// 	let flat_node = extend_node_map_from_node(
455			// 		env,
456			// 		node_map,
457			// 		node.inner(),
458			// 		node.index(),
459			// 		active_graph,
460			// 	)?;
461			// 	flat_nodes.push(flat_node);
462			// }
463
464			// node_map
465			// 	.graph_mut(active_graph)
466			// 	.unwrap()
467			// 	.get_mut(&id)
468			// 	.unwrap()
469			// 	.reverse_properties_mut()
470			// 	.insert_all_unique(property.clone(), flat_nodes)
471		}
472	}
473
474	Ok(Indexed::new(Node::with_id(id), None))
475}