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 {
145 let classifier = canonical_classifier();
146 let policy = pattern_merge_policy();
147 self.inner = crate::pattern_graph::merge_with_policy(
148 &classifier,
149 &policy,
150 pattern,
151 std::mem::replace(&mut self.inner, PatternGraph::empty()),
152 );
153 self
154 }
155
156 pub fn add_patterns(
162 &mut self,
163 patterns: impl IntoIterator<Item = Pattern<Subject>>,
164 ) -> &mut Self {
165 let classifier = canonical_classifier();
166 let policy = pattern_merge_policy();
167 let mut graph = std::mem::replace(&mut self.inner, PatternGraph::empty());
168 for pattern in patterns {
169 graph = crate::pattern_graph::merge_with_policy(&classifier, &policy, pattern, graph);
170 }
171 self.inner = graph;
172 self
173 }
174
175 pub fn from_patterns(patterns: impl IntoIterator<Item = Pattern<Subject>>) -> Self {
181 let classifier = canonical_classifier();
182 let policy = pattern_merge_policy();
183 let inner = crate::pattern_graph::from_patterns_with_policy(&classifier, &policy, patterns);
184 StandardGraph { inner }
185 }
186
187 pub fn from_pattern_graph(graph: PatternGraph<(), Subject>) -> Self {
189 StandardGraph { inner: graph }
190 }
191
192 pub fn node(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
198 self.inner.pg_nodes.get(id)
199 }
200
201 pub fn relationship(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
203 self.inner.pg_relationships.get(id)
204 }
205
206 pub fn walk(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
208 self.inner.pg_walks.get(id)
209 }
210
211 pub fn annotation(&self, id: &Symbol) -> Option<&Pattern<Subject>> {
213 self.inner.pg_annotations.get(id)
214 }
215
216 pub fn node_count(&self) -> usize {
222 self.inner.pg_nodes.len()
223 }
224
225 pub fn relationship_count(&self) -> usize {
227 self.inner.pg_relationships.len()
228 }
229
230 pub fn walk_count(&self) -> usize {
232 self.inner.pg_walks.len()
233 }
234
235 pub fn annotation_count(&self) -> usize {
237 self.inner.pg_annotations.len()
238 }
239
240 pub fn is_empty(&self) -> bool {
242 self.inner.pg_nodes.is_empty()
243 && self.inner.pg_relationships.is_empty()
244 && self.inner.pg_walks.is_empty()
245 && self.inner.pg_annotations.is_empty()
246 && self.inner.pg_other.is_empty()
247 && self.inner.pg_conflicts.is_empty()
248 }
249
250 pub fn has_conflicts(&self) -> bool {
252 !self.inner.pg_conflicts.is_empty()
253 }
254
255 pub fn conflicts(&self) -> &HashMap<Symbol, Vec<Pattern<Subject>>> {
257 &self.inner.pg_conflicts
258 }
259
260 pub fn other(&self) -> &HashMap<Symbol, ((), Pattern<Subject>)> {
262 &self.inner.pg_other
263 }
264
265 pub fn nodes(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
271 self.inner.pg_nodes.iter()
272 }
273
274 pub fn relationships(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
276 self.inner.pg_relationships.iter()
277 }
278
279 pub fn walks(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
281 self.inner.pg_walks.iter()
282 }
283
284 pub fn annotations(&self) -> impl Iterator<Item = (&Symbol, &Pattern<Subject>)> {
286 self.inner.pg_annotations.iter()
287 }
288
289 pub fn source(&self, rel_id: &Symbol) -> Option<&Pattern<Subject>> {
295 self.inner
296 .pg_relationships
297 .get(rel_id)
298 .and_then(|rel| rel.elements.first())
299 }
300
301 pub fn target(&self, rel_id: &Symbol) -> Option<&Pattern<Subject>> {
303 self.inner
304 .pg_relationships
305 .get(rel_id)
306 .and_then(|rel| rel.elements.get(1))
307 }
308
309 pub fn neighbors(&self, node_id: &Symbol) -> Vec<&Pattern<Subject>> {
311 let mut result = Vec::new();
312 for rel in self.inner.pg_relationships.values() {
313 if rel.elements.len() == 2 {
314 let src_id = rel.elements[0].value.identify();
315 let tgt_id = rel.elements[1].value.identify();
316 if src_id == node_id {
317 result.push(&rel.elements[1]);
318 } else if tgt_id == node_id {
319 result.push(&rel.elements[0]);
320 }
321 }
322 }
323 result
324 }
325
326 pub fn degree(&self, node_id: &Symbol) -> usize {
328 self.inner
329 .pg_relationships
330 .values()
331 .filter(|rel| {
332 rel.elements.len() == 2
333 && (rel.elements[0].value.identify() == node_id
334 || rel.elements[1].value.identify() == node_id)
335 })
336 .count()
337 }
338
339 pub fn as_pattern_graph(&self) -> &PatternGraph<(), Subject> {
345 &self.inner
346 }
347
348 pub fn into_pattern_graph(self) -> PatternGraph<(), Subject> {
350 self.inner
351 }
352
353 #[cfg(not(feature = "thread-safe"))]
355 pub fn as_query(&self) -> GraphQuery<Subject> {
356 use std::rc::Rc;
357 let graph = Rc::new(PatternGraph {
358 pg_nodes: self.inner.pg_nodes.clone(),
359 pg_relationships: self.inner.pg_relationships.clone(),
360 pg_walks: self.inner.pg_walks.clone(),
361 pg_annotations: self.inner.pg_annotations.clone(),
362 pg_other: self.inner.pg_other.clone(),
363 pg_conflicts: self.inner.pg_conflicts.clone(),
364 });
365 crate::pattern_graph::from_pattern_graph(graph)
366 }
367
368 #[cfg(feature = "thread-safe")]
370 pub fn as_query(&self) -> GraphQuery<Subject> {
371 use std::sync::Arc;
372 let graph = Arc::new(PatternGraph {
373 pg_nodes: self.inner.pg_nodes.clone(),
374 pg_relationships: self.inner.pg_relationships.clone(),
375 pg_walks: self.inner.pg_walks.clone(),
376 pg_annotations: self.inner.pg_annotations.clone(),
377 pg_other: self.inner.pg_other.clone(),
378 pg_conflicts: self.inner.pg_conflicts.clone(),
379 });
380 crate::pattern_graph::from_pattern_graph(graph)
381 }
382
383 pub fn as_snapshot(&self) -> GraphView<(), Subject> {
385 let classifier = canonical_classifier();
386 crate::graph::graph_view::from_pattern_graph(&classifier, &self.inner)
387 }
388
389 fn make_placeholder_node(id: &Symbol) -> Pattern<Subject> {
394 Pattern::point(Subject {
395 identity: id.clone(),
396 labels: std::collections::HashSet::new(),
397 properties: HashMap::new(),
398 })
399 }
400
401 fn get_or_create_placeholder_node(&mut self, id: &Symbol) -> Pattern<Subject> {
402 if let Some(node) = self.inner.pg_nodes.get(id) {
403 node.clone()
404 } else {
405 let placeholder = Self::make_placeholder_node(id);
406 self.inner.pg_nodes.insert(id.clone(), placeholder.clone());
407 placeholder
408 }
409 }
410
411 fn get_or_create_placeholder_relationship(&self, id: &Symbol) -> Pattern<Subject> {
412 if let Some(rel) = self.inner.pg_relationships.get(id) {
413 rel.clone()
414 } else {
415 Pattern::point(Subject {
417 identity: id.clone(),
418 labels: std::collections::HashSet::new(),
419 properties: HashMap::new(),
420 })
421 }
422 }
423
424 fn find_element(&self, id: &Symbol) -> Option<Pattern<Subject>> {
425 self.inner
426 .pg_nodes
427 .get(id)
428 .or_else(|| self.inner.pg_relationships.get(id))
429 .or_else(|| self.inner.pg_walks.get(id))
430 .or_else(|| self.inner.pg_annotations.get(id))
431 .cloned()
432 }
433}
434
435impl Default for StandardGraph {
436 fn default() -> Self {
437 Self::new()
438 }
439}
440
441fn pattern_merge_policy(
448) -> crate::reconcile::ReconciliationPolicy<crate::reconcile::SubjectMergeStrategy> {
449 crate::reconcile::ReconciliationPolicy::Merge(
450 crate::reconcile::ElementMergeStrategy::UnionElements,
451 crate::reconcile::default_subject_merge_strategy(),
452 )
453}