1use crate::{ExpandedDocument, FlattenedDocument, IndexedNode, IndexedObject, Object, flattened::UnorderedFlattenedDocument};
3use contextual::WithContext;
4use rdfx::{
5 LocalGenerator,
6 vocabulary::{Vocabulary, VocabularyMut},
7};
8use std::{collections::HashSet, hash::Hash};
9
10mod environment;
11mod node_map;
12
13pub use environment::Environment;
14pub use node_map::*;
15
16pub type FlattenResult<I, B> = Result<FlattenedDocument<I, B>, NodeMapError<I, B>>;
18
19pub type FlattenUnorderedResult<I, B> = Result<UnorderedFlattenedDocument<I, B>, NodeMapError<I, B>>;
21
22pub trait Flatten<I, B> {
24 fn flatten_with<V, G: LocalGenerator>(self, vocabulary: &mut V, generator: G, ordered: bool) -> FlattenResult<I, B>
31 where
32 V: Vocabulary<Iri = I, BlankId = B> + VocabularyMut;
33
34 fn flatten_unordered_with<V, G: LocalGenerator>(self, vocabulary: &mut V, generator: G) -> FlattenUnorderedResult<I, B>
41 where
42 V: Vocabulary<Iri = I, BlankId = B> + VocabularyMut;
43
44 fn flatten<G: LocalGenerator>(self, generator: G, ordered: bool) -> FlattenResult<I, B>
50 where
51 (): Vocabulary<Iri = I, BlankId = B>,
52 Self: Sized,
53 {
54 self.flatten_with(rdfx::vocabulary::no_vocabulary_mut(), generator, ordered)
55 }
56
57 fn flatten_unordered<G: LocalGenerator>(self, generator: G) -> FlattenUnorderedResult<I, B>
63 where
64 (): Vocabulary<Iri = I, BlankId = B>,
65 Self: Sized,
66 {
67 self.flatten_unordered_with(rdfx::vocabulary::no_vocabulary_mut(), generator)
68 }
69}
70
71impl<I: Clone + Eq + Hash, B: Clone + Eq + Hash> Flatten<I, B> for ExpandedDocument<I, B> {
72 fn flatten_with<V, G: LocalGenerator>(self, vocabulary: &mut V, generator: G, ordered: bool) -> FlattenResult<I, B>
73 where
74 V: Vocabulary<Iri = I, BlankId = B> + VocabularyMut,
75 {
76 Ok(self.generate_node_map_with(vocabulary, generator)?.flatten_with(vocabulary, ordered))
77 }
78
79 fn flatten_unordered_with<V, G: LocalGenerator>(self, vocabulary: &mut V, generator: G) -> FlattenUnorderedResult<I, B>
80 where
81 V: Vocabulary<Iri = I, BlankId = B> + VocabularyMut,
82 {
83 Ok(self.generate_node_map_with(vocabulary, generator)?.flatten_unordered())
84 }
85}
86
87fn filter_graph<T, B>(node: IndexedNode<T, B>) -> Option<IndexedNode<T, B>> {
88 if node.index().is_none() && node.is_empty() { None } else { Some(node) }
89}
90
91fn filter_sub_graph<T, B>(mut node: IndexedNode<T, B>) -> Option<IndexedObject<T, B>> {
92 if node.index().is_none() && node.properties().is_empty() {
93 None
94 } else {
95 node.set_graph_entry(None);
96 node.set_included(None);
97 node.set_reverse_properties(None);
98 Some(node.map_inner(Object::node))
99 }
100}
101
102impl<T: Clone + Eq + Hash, B: Clone + Eq + Hash> NodeMap<T, B> {
103 #[must_use]
106 pub fn flatten(self, ordered: bool) -> FlattenedDocument<T, B>
107 where
108 (): Vocabulary<Iri = T, BlankId = B>,
109 {
110 self.flatten_with(&(), ordered)
111 }
112
113 pub fn flatten_with<V>(self, vocabulary: &V, ordered: bool) -> FlattenedDocument<T, B>
116 where
117 V: Vocabulary<Iri = T, BlankId = B>,
118 {
119 let (mut default_graph, named_graphs) = self.into_parts();
120
121 let named_graphs: Vec<_> = if ordered {
122 let mut decorated: Vec<_> = named_graphs
123 .into_iter()
124 .map(|entry| (entry.0.with(vocabulary).as_str().to_string(), entry))
125 .collect();
126 decorated.sort_by(|a, b| a.0.cmp(&b.0));
127 decorated.into_iter().map(|(_, entry)| entry).collect()
128 } else {
129 named_graphs.into_iter().collect()
130 };
131
132 for (graph_id, graph) in named_graphs {
133 let Ok(entry) = default_graph.declare_node(graph_id, None) else {
136 continue;
137 };
138 let nodes: Vec<_> = if ordered {
139 let mut decorated: Vec<_> = graph
140 .into_nodes()
141 .map(|n| {
142 let key = n.id.as_ref().map(|id| id.with(vocabulary).as_str().to_string()).unwrap_or_default();
145 (key, n)
146 })
147 .collect();
148 decorated.sort_by(|a, b| a.0.cmp(&b.0));
149 decorated.into_iter().map(|(_, n)| n).collect()
150 } else {
151 graph.into_nodes().collect()
152 };
153 entry.set_graph_entry(Some(nodes.into_iter().filter_map(filter_sub_graph).collect()));
154 }
155
156 let nodes: Vec<_> = if ordered {
157 let mut decorated: Vec<_> = default_graph
158 .into_nodes()
159 .filter_map(filter_graph)
160 .map(|n| {
161 let key = n.id.as_ref().map(|id| id.with(vocabulary).as_str().to_string()).unwrap_or_default();
164 (key, n)
165 })
166 .collect();
167 decorated.sort_by(|a, b| a.0.cmp(&b.0));
168 decorated.into_iter().map(|(_, n)| n).collect()
169 } else {
170 default_graph.into_nodes().filter_map(filter_graph).collect()
171 };
172
173 nodes
174 }
175
176 pub fn flatten_unordered(self) -> HashSet<IndexedNode<T, B>> {
178 let (mut default_graph, named_graphs) = self.into_parts();
179
180 for (graph_id, graph) in named_graphs {
181 let Ok(entry) = default_graph.declare_node(graph_id, None) else {
184 continue;
185 };
186 entry.set_graph_entry(Some(graph.into_nodes().filter_map(filter_sub_graph).collect()));
187 }
188
189 default_graph.into_nodes().filter_map(filter_graph).collect()
190 }
191}