pattern_core/graph/
standard.rs1use std::collections::HashMap;
8
9use crate::graph::graph_classifier::{canonical_classifier, GraphValue};
10use crate::graph::graph_query::GraphQuery;
11use crate::graph::graph_view::GraphView;
12use crate::pattern::Pattern;
13use crate::pattern_graph::PatternGraph;
14use crate::subject::{Subject, Symbol};
15
16pub struct StandardGraph {
38 inner: PatternGraph<(), Subject>,
39}
40
41impl StandardGraph {
42 pub fn new() -> Self {
44 StandardGraph {
45 inner: PatternGraph::empty(),
46 }
47 }
48
49 pub fn add_node(&mut self, subject: Subject) -> &mut Self {
58 let id = subject.identity.clone();
59 let pattern = Pattern::point(subject);
60 self.inner.pg_nodes.insert(id, pattern);
61 self
62 }
63
64 pub fn add_relationship(
74 &mut self,
75 subject: Subject,
76 source: &Subject,
77 target: &Subject,
78 ) -> &mut Self {
79 let source_pattern = self.get_or_create_placeholder_node(&source.identity);
80 let target_pattern = self.get_or_create_placeholder_node(&target.identity);
81
82 let id = subject.identity.clone();
83 let pattern = Pattern::pattern(subject, vec![source_pattern, target_pattern]);
84 self.inner.pg_relationships.insert(id, pattern);
85 self
86 }
87
88 pub fn add_walk(&mut self, subject: Subject, relationships: &[Subject]) -> &mut Self {
97 let rel_patterns: Vec<Pattern<Subject>> = relationships
98 .iter()
99 .map(|rel| self.get_or_create_placeholder_relationship(&rel.identity))
100 .collect();
101
102 let id = subject.identity.clone();
103 let pattern = Pattern::pattern(subject, rel_patterns);
104 self.inner.pg_walks.insert(id, pattern);
105 self
106 }
107
108 pub fn add_annotation(&mut self, subject: Subject, element: &Subject) -> &mut Self {
116 let element_id = &element.identity;
117 let element_pattern = if let Some(existing) = self.find_element(element_id) {
118 existing
119 } else {
120 let placeholder = Self::make_placeholder_node(element_id);
122 self.inner
123 .pg_nodes
124 .insert(element_id.clone(), placeholder.clone());
125 placeholder
126 };
127
128 let id = subject.identity.clone();
129 let pattern = Pattern::pattern(subject, vec![element_pattern]);
130 self.inner.pg_annotations.insert(id, pattern);
131 self
132 }
133
134 pub fn add_pattern(&mut self, pattern: Pattern<Subject>) -> &mut Self {
141 let classifier = canonical_classifier();
142 self.inner = crate::pattern_graph::merge(
143 &classifier,
144 pattern,
145 std::mem::replace(&mut self.inner, PatternGraph::empty()),
146 );
147 self
148 }
149
150 pub fn add_patterns(
152 &mut self,
153 patterns: impl IntoIterator<Item = Pattern<Subject>>,
154 ) -> &mut Self {
155 let classifier = canonical_classifier();
156 let mut graph = std::mem::replace(&mut self.inner, PatternGraph::empty());
157 for pattern in patterns {
158 graph = crate::pattern_graph::merge(&classifier, pattern, graph);
159 }
160 self.inner = graph;
161 self
162 }
163
164 pub fn from_patterns(patterns: impl IntoIterator<Item = Pattern<Subject>>) -> Self {
166 let classifier = canonical_classifier();
167 let inner = crate::pattern_graph::from_patterns(&classifier, patterns);
168 StandardGraph { inner }
169 }
170
171 pub fn from_pattern_graph(graph: PatternGraph<(), Subject>) -> Self {
173 StandardGraph { inner: graph }
174 }
175
176 pub fn node(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
182 self.inner.pg_nodes.get(id)
183 }
184
185 pub fn relationship(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
187 self.inner.pg_relationships.get(id)
188 }
189
190 pub fn walk(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
192 self.inner.pg_walks.get(id)
193 }
194
195 pub fn annotation(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
197 self.inner.pg_annotations.get(id)
198 }
199
200 pub fn node_count(&self) -> usize {
206 self.inner.pg_nodes.len()
207 }
208
209 pub fn relationship_count(&self) -> usize {
211 self.inner.pg_relationships.len()
212 }
213
214 pub fn walk_count(&self) -> usize {
216 self.inner.pg_walks.len()
217 }
218
219 pub fn annotation_count(&self) -> usize {
221 self.inner.pg_annotations.len()
222 }
223
224 pub fn is_empty(&self) -> bool {
226 self.inner.pg_nodes.is_empty()
227 && self.inner.pg_relationships.is_empty()
228 && self.inner.pg_walks.is_empty()
229 && self.inner.pg_annotations.is_empty()
230 && self.inner.pg_other.is_empty()
231 && self.inner.pg_conflicts.is_empty()
232 }
233
234 pub fn has_conflicts(&self) -> bool {
236 !self.inner.pg_conflicts.is_empty()
237 }
238
239 pub fn conflicts(&self) -> &HashMap<Symbol, Vec<Pattern<Subject>>> {
241 &self.inner.pg_conflicts
242 }
243
244 pub fn other(&self) -> &HashMap<Symbol, ((), Pattern<Subject>)> {
246 &self.inner.pg_other
247 }
248
249 pub fn nodes(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
255 self.inner.pg_nodes.iter()
256 }
257
258 pub fn relationships(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
260 self.inner.pg_relationships.iter()
261 }
262
263 pub fn walks(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
265 self.inner.pg_walks.iter()
266 }
267
268 pub fn annotations(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
270 self.inner.pg_annotations.iter()
271 }
272
273 pub fn source(&self, rel_id: &Symbol) -> Option<&Pattern<Subject>> {
279 self.inner
280 .pg_relationships
281 .get(rel_id)
282 .and_then(|rel| rel.elements.first())
283 }
284
285 pub fn target(&self, rel_id: &Symbol) -> Option<&Pattern<Subject>> {
287 self.inner
288 .pg_relationships
289 .get(rel_id)
290 .and_then(|rel| rel.elements.get(1))
291 }
292
293 pub fn neighbors(&self, node_id: &Symbol) -> Vec<&Pattern<Subject>> {
295 let mut result = Vec::new();
296 for rel in self.inner.pg_relationships.values() {
297 if rel.elements.len() == 2 {
298 let src_id = rel.elements[0].value.identify();
299 let tgt_id = rel.elements[1].value.identify();
300 if src_id == node_id {
301 result.push(&rel.elements[1]);
302 } else if tgt_id == node_id {
303 result.push(&rel.elements[0]);
304 }
305 }
306 }
307 result
308 }
309
310 pub fn degree(&self, node_id: &Symbol) -> usize {
312 self.inner
313 .pg_relationships
314 .values()
315 .filter(|rel| {
316 rel.elements.len() == 2
317 && (rel.elements[0].value.identify() == node_id
318 || rel.elements[1].value.identify() == node_id)
319 })
320 .count()
321 }
322
323 pub fn as_pattern_graph(&self) -> &PatternGraph<(), Subject> {
329 &self.inner
330 }
331
332 pub fn into_pattern_graph(self) -> PatternGraph<(), Subject> {
334 self.inner
335 }
336
337 #[cfg(not(feature = "thread-safe"))]
339 pub fn as_query(&self) -> GraphQuery<Subject> {
340 use std::rc::Rc;
341 let graph = Rc::new(PatternGraph {
342 pg_nodes: self.inner.pg_nodes.clone(),
343 pg_relationships: self.inner.pg_relationships.clone(),
344 pg_walks: self.inner.pg_walks.clone(),
345 pg_annotations: self.inner.pg_annotations.clone(),
346 pg_other: self.inner.pg_other.clone(),
347 pg_conflicts: self.inner.pg_conflicts.clone(),
348 });
349 crate::pattern_graph::from_pattern_graph(graph)
350 }
351
352 #[cfg(feature = "thread-safe")]
354 pub fn as_query(&self) -> GraphQuery<Subject> {
355 use std::sync::Arc;
356 let graph = Arc::new(PatternGraph {
357 pg_nodes: self.inner.pg_nodes.clone(),
358 pg_relationships: self.inner.pg_relationships.clone(),
359 pg_walks: self.inner.pg_walks.clone(),
360 pg_annotations: self.inner.pg_annotations.clone(),
361 pg_other: self.inner.pg_other.clone(),
362 pg_conflicts: self.inner.pg_conflicts.clone(),
363 });
364 crate::pattern_graph::from_pattern_graph(graph)
365 }
366
367 pub fn as_snapshot(&self) -> GraphView<(), Subject> {
369 let classifier = canonical_classifier();
370 crate::graph::graph_view::from_pattern_graph(&classifier, &self.inner)
371 }
372
373 fn make_placeholder_node(id: &Symbol) -> Pattern<Subject> {
378 Pattern::point(Subject {
379 identity: id.clone(),
380 labels: std::collections::HashSet::new(),
381 properties: HashMap::new(),
382 })
383 }
384
385 fn get_or_create_placeholder_node(&mut self, id: &Symbol) -> Pattern<Subject> {
386 if let Some(node) = self.inner.pg_nodes.get(id) {
387 node.clone()
388 } else {
389 let placeholder = Self::make_placeholder_node(id);
390 self.inner.pg_nodes.insert(id.clone(), placeholder.clone());
391 placeholder
392 }
393 }
394
395 fn get_or_create_placeholder_relationship(&self, id: &Symbol) -> Pattern<Subject> {
396 if let Some(rel) = self.inner.pg_relationships.get(id) {
397 rel.clone()
398 } else {
399 Pattern::point(Subject {
401 identity: id.clone(),
402 labels: std::collections::HashSet::new(),
403 properties: HashMap::new(),
404 })
405 }
406 }
407
408 fn find_element(&self, id: &Symbol) -> Option<Pattern<Subject>> {
409 self.inner
410 .pg_nodes
411 .get(id)
412 .or_else(|| self.inner.pg_relationships.get(id))
413 .or_else(|| self.inner.pg_walks.get(id))
414 .or_else(|| self.inner.pg_annotations.get(id))
415 .cloned()
416 }
417}
418
419impl Default for StandardGraph {
420 fn default() -> Self {
421 Self::new()
422 }
423}