partiql_value/
graph.rs

1use crate::Value;
2use lasso::{Key, Rodeo, RodeoReader, Spur};
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::cmp::Ordering;
6use std::collections::HashSet;
7use std::fmt::{Debug, Formatter};
8use std::hash::{Hash, Hasher};
9use std::rc::Rc;
10
11#[derive(Clone, Debug)]
12pub enum Graph {
13    Simple(Rc<SimpleGraph>),
14}
15
16#[cfg(feature = "serde")]
17impl Serialize for Graph {
18    fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
19    where
20        S: Serializer,
21    {
22        todo!("Serialize for Graph")
23    }
24}
25
26#[cfg(feature = "serde")]
27impl<'de> Deserialize<'de> for Graph {
28    fn deserialize<D>(_: D) -> Result<Self, D::Error>
29    where
30        D: Deserializer<'de>,
31    {
32        todo!("Deserialize for Graph")
33    }
34}
35
36impl Hash for Graph {
37    fn hash<H: Hasher>(&self, _state: &mut H) {
38        todo!("Hash for Graph")
39    }
40}
41
42impl Eq for Graph {}
43impl PartialEq for Graph {
44    fn eq(&self, _other: &Self) -> bool {
45        todo!("PartialEq for Graph")
46    }
47}
48
49impl PartialOrd for Graph {
50    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl Ord for Graph {
56    fn cmp(&self, _other: &Self) -> Ordering {
57        todo!("Ord for Graph")
58    }
59}
60
61/// The id of a node in the graph.
62#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
63pub struct GNodeId(pub usize);
64
65/// The id of an edge in the graph.
66#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
67pub struct GEdgeId(pub usize);
68
69/// A label; backed by a [`Rodeo`] interner.
70#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
71pub struct GLabelId(pub Spur);
72
73/// A set of labels applied to an element.
74#[derive(Clone, PartialEq, Eq)]
75pub struct GLabels(pub HashSet<GLabelId>);
76
77/// An element's attributes: labels and optional payload.
78#[derive(Clone, PartialEq, Eq)]
79pub struct GElem {
80    pub value: Option<Value>,
81    pub labels: GLabels,
82}
83
84impl GElem {
85    pub fn new(value: Option<Value>, labels: GLabels) -> Self {
86        GElem { value, labels }
87    }
88}
89
90/// A 'simple' graph of nodes and edges in both directed and undirected graphs.
91pub struct SimpleGraph {
92    pub nodes: Vec<GElem>,
93    pub edges: Vec<GElem>,
94    pub g_dir: Vec<(GNodeId, GEdgeId, GNodeId)>,
95    pub g_undir: Vec<(GNodeId, GEdgeId, GNodeId)>,
96    pub labels: RodeoReader,
97}
98
99impl Debug for SimpleGraph {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        f.debug_struct("SimpleGraph")
102            .field("nodes", &DebugGElems("node", &self.nodes, &self.labels))
103            .field("edges", &DebugGElems("edge", &self.edges, &self.labels))
104            .field("directed", &self.g_dir)
105            .field("undirected", &self.g_undir)
106            .finish()
107    }
108}
109
110/// Wrapper to debug output elements.
111pub(crate) struct DebugGElems<'a>(&'a str, &'a Vec<GElem>, &'a RodeoReader);
112
113/// Wrapper to debug output an element.
114pub(crate) struct DebugGElem<'a>(usize, &'a str, &'a GElem, &'a RodeoReader);
115
116impl Debug for DebugGElems<'_> {
117    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
118        let mut l = f.debug_list();
119
120        for (id, gelem) in self.1.iter().enumerate() {
121            l.entry(&DebugGElem(id, self.0, gelem, self.2));
122        }
123
124        l.finish()
125    }
126}
127
128impl Debug for DebugGElem<'_> {
129    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
130        let DebugGElem(id, name, GElem { value, labels, .. }, reader) = self;
131        let labels = labels
132            .0
133            .iter()
134            .map(|id| reader.resolve(&id.0))
135            .collect::<Vec<_>>();
136        f.debug_struct(name)
137            .field("id", id)
138            .field("value", value)
139            .field("labels", &labels)
140            .finish()
141    }
142}
143
144/// Specification for an edge; Direciton and end-points.
145pub enum EdgeSpec {
146    Directed(String, String),   // from node, to node
147    Undirected(String, String), // node, node
148}
149
150/// Specification for a collection of Nodes;
151/// Comprises parallel arrays for:
152///    - Node names
153///    - Node label sets
154///    - Node values
155type NodeSpec = (Vec<String>, Vec<HashSet<String>>, Vec<Option<Value>>);
156
157/// Specification for a collection of Edges;
158/// Comprises parallel arrays for:
159///    - Edge names
160///    - Edge label sets
161///    - Edge specificaiton (direction and endpoints)
162///    - Edge values
163#[allow(clippy::type_complexity)]
164type EdgesSpec = (
165    Vec<String>,
166    Vec<HashSet<String>>,
167    Vec<EdgeSpec>,
168    Vec<Option<Value>>,
169);
170
171impl SimpleGraph {
172    pub fn from_spec(node_specs: NodeSpec, edge_specs: EdgesSpec) -> Self {
173        let mut node_ids = Rodeo::default();
174        let mut label_ids = Rodeo::default();
175        let mut nodes: Vec<GElem> = vec![];
176
177        // Process all nodes
178        let (ids, labels, values) = node_specs;
179        assert_eq!(ids.len(), labels.len());
180        assert_eq!(ids.len(), values.len());
181        for ((id, labels), value) in ids
182            .into_iter()
183            .zip(labels.into_iter())
184            .zip(values.into_iter())
185        {
186            let nid = node_ids.get_or_intern(id);
187            let labels: HashSet<_> = labels
188                .into_iter()
189                .map(|l| GLabelId(label_ids.get_or_intern(l)))
190                .collect();
191            let nidx = nid.into_usize();
192            assert_eq!(nodes.len(), nidx);
193            nodes.push(GElem::new(value, GLabels(labels)));
194        }
195
196        let mut edge_ids = Rodeo::default();
197        let mut edges: Vec<GElem> = vec![];
198
199        let mut g_dir = vec![];
200        let mut g_undir = vec![];
201
202        // Process all edges
203        let (ids, labels, ends, values) = edge_specs;
204        assert_eq!(ids.len(), labels.len());
205        assert_eq!(ids.len(), ends.len());
206        assert_eq!(ids.len(), values.len());
207        for (((id, labels), edge_spec), value) in ids
208            .into_iter()
209            .zip(labels.into_iter())
210            .zip(ends.into_iter())
211            .zip(values.into_iter())
212        {
213            let eid = edge_ids.get_or_intern(id);
214            let labels: HashSet<_> = labels
215                .into_iter()
216                .map(|l| GLabelId(label_ids.get_or_intern(l)))
217                .collect();
218
219            let eidx = eid.into_usize();
220            assert_eq!(edges.len(), eidx);
221            edges.push(GElem::new(value, GLabels(labels)));
222
223            match edge_spec {
224                EdgeSpec::Directed(l, r) => {
225                    let eidx = GEdgeId(eidx);
226                    let lidx = GNodeId(node_ids.get(l).expect("expected node").into_usize());
227                    let ridx = GNodeId(node_ids.get(r).expect("expected node").into_usize());
228                    g_dir.push((lidx, eidx, ridx));
229                }
230                EdgeSpec::Undirected(l, r) => {
231                    let eidx = GEdgeId(eidx);
232                    let lidx = GNodeId(node_ids.get(l).expect("expected node").into_usize());
233                    let ridx = GNodeId(node_ids.get(r).expect("expected node").into_usize());
234                    g_undir.push((lidx, eidx, ridx));
235                }
236            }
237        }
238
239        let labels = label_ids.into_reader();
240        SimpleGraph {
241            nodes,
242            edges,
243            labels,
244            g_dir,
245            g_undir,
246        }
247    }
248}