Skip to main content

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