1use crate::model::{Triple, NamedGraph, JsonLdDocument};
4use std::collections::HashMap;
5use anyhow::Result;
6use smallvec::SmallVec;
7
8#[derive(Debug, Clone, Default)]
10pub struct GraphStore {
11 graphs: HashMap<String, NamedGraph>,
13 default_graph: NamedGraph,
15 subject_index: HashMap<String, SmallVec<[usize; 8]>>,
17 predicate_index: HashMap<String, SmallVec<[usize; 8]>>,
19 object_index: HashMap<String, SmallVec<[usize; 8]>>,
21}
22
23impl GraphStore {
24 pub fn new() -> Self {
25 Self {
26 graphs: HashMap::new(),
27 default_graph: NamedGraph {
28 name: "default".to_string(),
29 triples: Vec::new(),
30 },
31 subject_index: HashMap::new(),
32 predicate_index: HashMap::new(),
33 object_index: HashMap::new(),
34 }
35 }
36
37 pub fn add_triple(&mut self, triple: Triple) {
39 let index = self.default_graph.triples.len();
40 self.default_graph.triples.push(triple.clone());
41
42 self.subject_index.entry(triple.subject.clone()).or_insert_with(SmallVec::new).push(index);
44 self.predicate_index.entry(triple.predicate.clone()).or_insert_with(SmallVec::new).push(index);
45 self.object_index.entry(triple.object.clone()).or_insert_with(SmallVec::new).push(index);
46 }
47
48 pub fn add_triple_to_graph(&mut self, graph_name: &str, triple: Triple) {
50 self.graphs
51 .entry(graph_name.to_string())
52 .or_insert_with(|| NamedGraph {
53 name: graph_name.to_string(),
54 triples: Vec::new(),
55 })
56 .triples
57 .push(triple);
58 }
59
60 pub fn add_triples_to_graph(&mut self, graph_name: &str, triples: Vec<Triple>) {
62 self.graphs
63 .entry(graph_name.to_string())
64 .or_insert_with(|| NamedGraph {
65 name: graph_name.to_string(),
66 triples: Vec::new(),
67 })
68 .triples
69 .extend(triples);
70 }
71
72 pub fn get_default_graph(&self) -> &NamedGraph {
74 &self.default_graph
75 }
76
77 pub fn get_graph(&self, name: &str) -> Option<&NamedGraph> {
79 self.graphs.get(name)
80 }
81
82 pub fn graph_names(&self) -> Vec<String> {
84 self.graphs.keys().cloned().collect()
85 }
86
87 pub fn find_triples(&self, subject: Option<&str>, predicate: Option<&str>, object: Option<&str>) -> Vec<&Triple> {
89 let candidate_indices: SmallVec<[usize; 8]> = match (subject, predicate, object) {
91 (Some(s), Some(p), Some(o)) => {
93 self.find_exact_triple_indices(s, p, o)
94 },
95 (Some(s), None, None) => {
97 self.subject_index.get(s).cloned().unwrap_or(SmallVec::new())
98 },
99 (None, Some(p), None) => {
100 self.predicate_index.get(p).cloned().unwrap_or(SmallVec::new())
101 },
102 (None, None, Some(o)) => {
103 self.object_index.get(o).cloned().unwrap_or(SmallVec::new())
104 },
105 (Some(s), Some(p), None) => {
107 self.intersect_indices(
108 self.subject_index.get(s).map(|v| v.as_slice()).unwrap_or(&[]),
109 self.predicate_index.get(p).map(|v| v.as_slice()).unwrap_or(&[]),
110 )
111 },
112 (Some(s), None, Some(o)) => {
113 self.intersect_indices(
114 self.subject_index.get(s).map(|v| v.as_slice()).unwrap_or(&[]),
115 self.object_index.get(o).map(|v| v.as_slice()).unwrap_or(&[]),
116 )
117 },
118 (None, Some(p), Some(o)) => {
119 self.intersect_indices(
120 self.predicate_index.get(p).map(|v| v.as_slice()).unwrap_or(&[]),
121 self.object_index.get(o).map(|v| v.as_slice()).unwrap_or(&[]),
122 )
123 },
124 (None, None, None) => {
126 (0..self.default_graph.triples.len()).map(|i| i).collect()
127 }
128 };
129
130 let mut results = Vec::new();
132 for &index in &candidate_indices {
133 if let Some(triple) = self.default_graph.triples.get(index) {
134 results.push(triple);
135 }
136 }
137
138 results
139 }
140
141 fn find_exact_triple_indices(&self, subject: &str, predicate: &str, object: &str) -> SmallVec<[usize; 8]> {
143 if let Some(subject_indices) = self.subject_index.get(subject) {
144 if let Some(predicate_indices) = self.predicate_index.get(predicate) {
145 if let Some(object_indices) = self.object_index.get(object) {
146 let mut result = SmallVec::new();
148 for &idx in subject_indices {
149 if predicate_indices.contains(&idx) && object_indices.contains(&idx) {
150 result.push(idx);
151 }
152 }
153 return result;
154 }
155 }
156 }
157 SmallVec::new()
158 }
159
160 fn intersect_indices(&self, a: &[usize], b: &[usize]) -> SmallVec<[usize; 8]> {
162 let mut result = SmallVec::new();
163 let mut i = 0;
164 let mut j = 0;
165
166 while i < a.len() && j < b.len() {
167 match a[i].cmp(&b[j]) {
168 std::cmp::Ordering::Less => i += 1,
169 std::cmp::Ordering::Greater => j += 1,
170 std::cmp::Ordering::Equal => {
171 result.push(a[i]);
172 i += 1;
173 j += 1;
174 }
175 }
176 }
177
178 result
179 }
180
181 pub fn to_jsonld(&self) -> Result<JsonLdDocument> {
183 let mut graph = Vec::new();
184
185 for triple in &self.default_graph.triples {
187 let node = serde_json::json!({
188 "@id": triple.subject,
189 triple.predicate.clone(): triple.object
190 });
191 graph.push(node);
192 }
193
194 for named_graph in self.graphs.values() {
196 for triple in &named_graph.triples {
197 let node = serde_json::json!({
198 "@id": triple.subject,
199 triple.predicate.clone(): triple.object
200 });
201 graph.push(node);
202 }
203 }
204
205 Ok(JsonLdDocument {
206 context: serde_json::json!({
207 "@vocab": "https://w3id.org/security#",
208 "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
209 "rdfs": "http://www.w3.org/2000/01/rdf-schema#"
210 }),
211 graph: Some(graph),
212 data: HashMap::new(),
213 })
214 }
215
216 pub fn clear(&mut self) {
218 self.graphs.clear();
219 self.default_graph.triples.clear();
220 self.subject_index.clear();
221 self.predicate_index.clear();
222 self.object_index.clear();
223 }
224}