1use super::{
10 graphid_label_id, BTreeSet, Edge, EdgeId, GraphLabelInfo, GraphLabelRegistry, GraphStore as _,
11 GraphStoreError, GraphStoreResult, LabelKind, MemoryGraphStore, Partition, Vertex, VertexId,
12};
13
14impl MemoryGraphStore {
15 pub fn new() -> Self {
16 Self {
17 next_vertex_id: 1,
18 next_edge_id: 1,
19 ..Self::default()
20 }
21 }
22
23 #[cfg(test)]
24 pub(crate) fn remove_edge_record_for_corruption_test(&mut self, edge_id: EdgeId) {
25 self.edges.remove(&edge_id);
26 }
27
28 #[cfg(test)]
29 pub(super) fn remove_vertex_record_for_corruption_test(&mut self, vertex_id: VertexId) {
30 self.vertices.remove(&vertex_id);
31 }
32
33 pub(super) fn require_partition_mut(&mut self, name: &str) -> GraphStoreResult<&mut Partition> {
34 self.graphs
35 .get_mut(name)
36 .ok_or_else(|| GraphStoreError::UnknownGraph(name.to_string()))
37 }
38
39 pub(super) fn require_partition(&self, name: &str) -> GraphStoreResult<&Partition> {
40 self.graphs
41 .get(name)
42 .ok_or_else(|| GraphStoreError::UnknownGraph(name.to_string()))
43 }
44
45 pub(super) fn require_query_vertex(
46 &self,
47 partition: &Partition,
48 vertex_id: VertexId,
49 graph: &str,
50 ) -> GraphStoreResult<()> {
51 if !partition.vertex_ids.contains(&vertex_id) {
52 return Err(GraphStoreError::InvalidQuery(format!(
53 "vertex {vertex_id} is not a member of graph {graph:?}"
54 )));
55 }
56 self.require_partition_vertex(partition, vertex_id, graph)
57 .map(|_| ())
58 }
59
60 pub(super) fn require_partition_vertex<'a>(
61 &'a self,
62 partition: &Partition,
63 vertex_id: VertexId,
64 graph: &str,
65 ) -> GraphStoreResult<&'a Vertex> {
66 if !partition.vertex_ids.contains(&vertex_id) {
67 return Err(GraphStoreError::CorruptGraph(format!(
68 "graph {graph:?} references vertex {vertex_id} outside its membership set"
69 )));
70 }
71 self.vertices.get(&vertex_id).ok_or_else(|| {
72 GraphStoreError::CorruptGraph(format!(
73 "graph {graph:?} references missing vertex {vertex_id}"
74 ))
75 })
76 }
77
78 pub(super) fn require_partition_edge<'a>(
79 &'a self,
80 partition: &Partition,
81 edge_id: EdgeId,
82 graph: &str,
83 ) -> GraphStoreResult<&'a Edge> {
84 if !partition.edge_ids.contains(&edge_id) {
85 return Err(GraphStoreError::CorruptGraph(format!(
86 "graph {graph:?} adjacency references edge {edge_id} outside its membership set"
87 )));
88 }
89 let edge = self.edges.get(&edge_id).ok_or_else(|| {
90 GraphStoreError::CorruptGraph(format!(
91 "graph {graph:?} references missing edge {edge_id}"
92 ))
93 })?;
94 self.require_edge_endpoint(partition, edge.source_id, graph)?;
95 self.require_edge_endpoint(partition, edge.target_id, graph)?;
96 Ok(edge)
97 }
98
99 pub(super) fn require_edge_endpoint(
100 &self,
101 partition: &Partition,
102 vertex_id: VertexId,
103 graph: &str,
104 ) -> GraphStoreResult<()> {
105 if partition.vertex_ids.contains(&vertex_id) && self.vertices.contains_key(&vertex_id) {
106 return Ok(());
107 }
108 let label_id = graphid_label_id(vertex_id);
109 if self
110 .label_registry(graph)
111 .dropped_label_ids
112 .contains(&label_id)
113 {
114 return Ok(());
115 }
116 Err(GraphStoreError::CorruptGraph(format!(
117 "graph {graph:?} edge references missing vertex {vertex_id}"
118 )))
119 }
120
121 pub(super) fn ensure_partition(&mut self, name: &str) {
122 if !self.graphs.contains_key(name) {
123 self.graphs.insert(name.to_string(), Partition::default());
124 }
125 }
126
127 pub(super) fn release_vertex_if_orphan(&mut self, vertex_id: VertexId) {
128 let still_referenced = self
129 .vertex_membership
130 .get(&vertex_id)
131 .is_some_and(|set| !set.is_empty());
132 if !still_referenced {
133 self.vertices.remove(&vertex_id);
134 self.vertex_membership.remove(&vertex_id);
135 }
136 }
137
138 pub(super) fn release_edge_if_orphan(&mut self, edge_id: EdgeId) {
139 let still_referenced = self
140 .edge_membership
141 .get(&edge_id)
142 .is_some_and(|set| !set.is_empty());
143 if !still_referenced {
144 self.edges.remove(&edge_id);
145 self.edge_membership.remove(&edge_id);
146 }
147 }
148
149 pub(super) fn populate_graph_from_ids(
150 &mut self,
151 vertex_ids: &BTreeSet<VertexId>,
152 edge_ids: &BTreeSet<EdgeId>,
153 target: &str,
154 ) -> GraphStoreResult<()> {
155 let vertices = vertex_ids
156 .iter()
157 .map(|id| {
158 self.vertices.get(id).cloned().ok_or_else(|| {
159 GraphStoreError::CorruptGraph(format!(
160 "graph membership references missing vertex {id}"
161 ))
162 })
163 })
164 .collect::<GraphStoreResult<Vec<_>>>()?;
165 let edges = edge_ids
166 .iter()
167 .map(|id| {
168 self.edges.get(id).cloned().ok_or_else(|| {
169 GraphStoreError::CorruptGraph(format!(
170 "graph membership references missing edge {id}"
171 ))
172 })
173 })
174 .collect::<GraphStoreResult<Vec<_>>>()?;
175
176 self.ensure_partition(target);
177 for vertex in vertices {
178 let id = vertex.vertex_id;
179 self.require_partition_mut(target)?.add_vertex(&vertex);
180 self.vertex_membership
181 .entry(id)
182 .or_default()
183 .insert(target.to_string());
184 }
185 for edge in edges {
186 let id = edge.edge_id;
187 self.require_partition_mut(target)?.add_edge(&edge);
188 self.edge_membership
189 .entry(id)
190 .or_default()
191 .insert(target.to_string());
192 }
193 Ok(())
194 }
195
196 pub fn insert_raw_vertex(&mut self, vertex: Vertex) -> GraphStoreResult<()> {
200 let next = if vertex.vertex_id >= self.next_vertex_id {
201 vertex.vertex_id.checked_add(1).ok_or_else(|| {
202 GraphStoreError::IdExhausted("raw vertex id counter overflow".into())
203 })?
204 } else {
205 self.next_vertex_id
206 };
207 self.vertices.insert(vertex.vertex_id, vertex);
208 self.next_vertex_id = next;
209 Ok(())
210 }
211
212 pub fn insert_raw_edge(&mut self, edge: Edge) -> GraphStoreResult<()> {
216 let next = if edge.edge_id >= self.next_edge_id {
217 edge.edge_id.checked_add(1).ok_or_else(|| {
218 GraphStoreError::IdExhausted("raw edge id counter overflow".into())
219 })?
220 } else {
221 self.next_edge_id
222 };
223 self.edges.insert(edge.edge_id, edge);
224 self.next_edge_id = next;
225 Ok(())
226 }
227
228 pub fn attach_vertex(&mut self, vertex_id: VertexId, graph: &str) -> GraphStoreResult<()> {
231 let vertex = self.vertices.get(&vertex_id).cloned().ok_or_else(|| {
232 GraphStoreError::CorruptGraph(format!("cannot attach missing vertex {vertex_id}"))
233 })?;
234 let part = self.require_partition_mut(graph)?;
235 part.add_vertex(&vertex);
236 self.vertex_membership
237 .entry(vertex_id)
238 .or_default()
239 .insert(graph.to_string());
240 Ok(())
241 }
242
243 pub fn attach_edge(&mut self, edge_id: EdgeId, graph: &str) -> GraphStoreResult<()> {
244 let edge = self.edges.get(&edge_id).cloned().ok_or_else(|| {
247 GraphStoreError::CorruptGraph(format!("cannot attach missing edge {edge_id}"))
248 })?;
249 let partition = self.require_partition(graph)?;
250 self.require_edge_endpoint(partition, edge.source_id, graph)?;
251 self.require_edge_endpoint(partition, edge.target_id, graph)?;
252 let part = self.require_partition_mut(graph)?;
253 part.add_edge(&edge);
254 self.edge_membership
255 .entry(edge_id)
256 .or_default()
257 .insert(graph.to_string());
258 Ok(())
259 }
260
261 pub fn out_edge_ids_for_graph(&self, graph: &str) -> GraphStoreResult<BTreeSet<EdgeId>> {
264 Ok(self.require_partition(graph)?.edge_ids.clone())
265 }
266
267 fn remove_vertex_preserving_incident_edges(
268 &mut self,
269 vertex_id: VertexId,
270 graph: &str,
271 ) -> GraphStoreResult<()> {
272 let partition = self.require_partition_mut(graph)?;
273 if !partition.vertex_ids.remove(&vertex_id) {
274 return Ok(());
275 }
276 for ids in partition.vertex_label_index.values_mut() {
277 ids.remove(&vertex_id);
278 }
279 if let Some(memberships) = self.vertex_membership.get_mut(&vertex_id) {
280 memberships.remove(graph);
281 }
282 self.release_vertex_if_orphan(vertex_id);
283 Ok(())
284 }
285
286 pub fn label_registry(&self, graph: &str) -> GraphLabelRegistry {
289 self.label_registries
290 .get(graph)
291 .cloned()
292 .unwrap_or_default()
293 }
294
295 pub fn import_label_registry(&mut self, graph: &str, registry: &GraphLabelRegistry) {
299 self.label_registries
300 .entry(graph.to_string())
301 .or_default()
302 .merge(registry);
303 }
304
305 pub fn rebuild_label_registry_from_ids(&mut self, graph: &str) {
309 let mut observations: Vec<(String, u64, LabelKind)> = Vec::new();
310 if let Some(part) = self.graphs.get(graph) {
311 for vid in &part.vertex_ids {
312 if let Some(vertex) = self.vertices.get(vid) {
313 observations.push((vertex.label.clone(), vertex.vertex_id, LabelKind::Vertex));
314 }
315 }
316 for eid in &part.edge_ids {
317 if let Some(edge) = self.edges.get(eid) {
318 observations.push((edge.label.clone(), edge.edge_id, LabelKind::Edge));
319 }
320 }
321 }
322 let registry = self.label_registries.entry(graph.to_string()).or_default();
323 for (label, id, kind) in observations {
324 registry.observe(&label, id, kind);
325 }
326 }
327
328 pub fn graph_labels(&self, graph: &str) -> GraphStoreResult<Vec<GraphLabelInfo>> {
330 self.require_partition(graph)?;
331 Ok(self.label_registry(graph).labels())
332 }
333
334 pub fn graph_label_kind(
337 &self,
338 graph: &str,
339 label: &str,
340 ) -> GraphStoreResult<Option<LabelKind>> {
341 self.require_partition(graph)?;
342 Ok(self.label_registry(graph).label_kind(label))
343 }
344
345 pub fn create_label(
350 &mut self,
351 graph: &str,
352 label: &str,
353 kind: LabelKind,
354 ) -> GraphStoreResult<Option<u32>> {
355 self.require_partition(graph)?;
356 let mut candidate = self.label_registry(graph);
357 let id = candidate.register_label(label, kind)?;
358 if id.is_some() {
359 self.label_registries.insert(graph.to_string(), candidate);
360 }
361 Ok(id)
362 }
363
364 pub fn drop_label(
372 &mut self,
373 graph: &str,
374 label: &str,
375 ) -> GraphStoreResult<Option<(u32, LabelKind)>> {
376 self.require_partition(graph)?;
377 let registry = self.label_registry(graph);
378 let Some(kind) = registry.label_kind(label) else {
379 return Ok(None);
380 };
381 let id = if label == kind.default_label_name() {
382 if let Some(dependent) = registry
383 .labels
384 .keys()
385 .find(|candidate| registry.label_kind(candidate) == Some(kind))
386 {
387 return Err(GraphStoreError::InvalidMutation(format!(
388 "cannot drop default label {label} while label {dependent} depends on it"
389 )));
390 }
391 kind.default_label_id()
392 } else {
393 registry.labels.get(label).copied().ok_or_else(|| {
394 GraphStoreError::CorruptGraph(format!(
395 "graph {graph:?} label {label:?} has no registry id"
396 ))
397 })?
398 };
399 match kind {
400 LabelKind::Vertex => {
401 let vertex_ids = if id == kind.default_label_id() {
402 self.require_partition(graph)?
403 .vertex_ids
404 .iter()
405 .copied()
406 .filter(|vertex_id| graphid_label_id(*vertex_id) == id)
407 .collect()
408 } else {
409 self.vertex_ids_by_label(label, graph)?
410 };
411 for vertex_id in vertex_ids {
412 self.remove_vertex_preserving_incident_edges(vertex_id, graph)?;
413 }
414 }
415 LabelKind::Edge => {
416 let edge_ids = if id == kind.default_label_id() {
417 self.require_partition(graph)?
418 .edge_ids
419 .iter()
420 .copied()
421 .filter(|edge_id| graphid_label_id(*edge_id) == id)
422 .collect()
423 } else {
424 self.edge_ids_by_label(label, graph)?
425 };
426 for edge_id in edge_ids {
427 self.remove_edge(edge_id, graph)?;
428 }
429 }
430 }
431 self.label_registries
432 .entry(graph.to_string())
433 .or_default()
434 .remove_label(label);
435 Ok(Some((id, kind)))
436 }
437
438 pub fn rename_graph(&mut self, from: &str, to: &str) -> GraphStoreResult<()> {
442 if from == to {
443 return Ok(());
444 }
445 if self.graphs.contains_key(to) {
446 return Err(GraphStoreError::InvalidMutation(format!(
447 "graph {to:?} already exists"
448 )));
449 }
450 let partition = self
451 .graphs
452 .remove(from)
453 .ok_or_else(|| GraphStoreError::UnknownGraph(from.to_string()))?;
454 for vertex_id in &partition.vertex_ids {
455 if let Some(set) = self.vertex_membership.get_mut(vertex_id) {
456 if set.remove(from) {
457 set.insert(to.to_string());
458 }
459 }
460 }
461 for edge_id in &partition.edge_ids {
462 if let Some(set) = self.edge_membership.get_mut(edge_id) {
463 if set.remove(from) {
464 set.insert(to.to_string());
465 }
466 }
467 }
468 self.graphs.insert(to.to_string(), partition);
469 if let Some(registry) = self.label_registries.remove(from) {
470 self.label_registries.insert(to.to_string(), registry);
471 }
472 Ok(())
473 }
474}