Skip to main content

pattern_core/graph/transform/
unfold_graph.rs

1//! unfold_graph: build a PatternGraph from seeds using an expander function.
2//!
3//! Ported from `Pattern.Graph.Transform.unfoldGraph` in the Haskell reference.
4
5use crate::graph::graph_classifier::{GraphClassifier, GraphValue};
6use crate::pattern::Pattern;
7use crate::pattern_graph::{from_patterns_with_policy, PatternGraph};
8use crate::reconcile::{HasIdentity, Mergeable, ReconciliationPolicy, Refinable};
9use crate::subject::Symbol;
10
11/// Build a `PatternGraph` from a list of seeds.
12///
13/// For each seed, `expand` returns a list of `Pattern<V>` to insert into the graph.
14/// All patterns from all seeds are collected and inserted using the given classifier
15/// and reconciliation policy.
16///
17/// # Examples
18///
19/// ```rust
20/// use pattern_core::{unfold_graph, canonical_classifier, Pattern, Subject, Symbol, Value};
21/// use pattern_core::reconcile::ReconciliationPolicy;
22/// use std::collections::{HashSet, HashMap};
23///
24/// let classifier = canonical_classifier();
25/// let policy = ReconciliationPolicy::LastWriteWins;
26///
27/// struct Row { id: &'static str }
28///
29/// let rows = vec![Row { id: "a" }, Row { id: "b" }];
30/// let graph = unfold_graph(
31///     &classifier,
32///     &policy,
33///     |row: Row| vec![Pattern::point(Subject {
34///         identity: Symbol(row.id.to_string()),
35///         labels: HashSet::new(),
36///         properties: HashMap::new(),
37///     })],
38///     rows,
39/// );
40///
41/// assert_eq!(graph.pg_nodes.len(), 2);
42/// ```
43pub fn unfold_graph<A, Extra, V>(
44    classifier: &GraphClassifier<Extra, V>,
45    policy: &ReconciliationPolicy<V::MergeStrategy>,
46    expand: impl Fn(A) -> Vec<Pattern<V>>,
47    seeds: Vec<A>,
48) -> PatternGraph<Extra, V>
49where
50    V: GraphValue<Id = Symbol>
51        + HasIdentity<V, Symbol>
52        + Mergeable
53        + Refinable
54        + PartialEq
55        + Clone
56        + 'static,
57    Extra: 'static,
58{
59    let patterns: Vec<Pattern<V>> = seeds.into_iter().flat_map(expand).collect();
60    from_patterns_with_policy(classifier, policy, patterns)
61}