Skip to main content

graphrecords_query/
lib.rs

1pub mod capabilities;
2pub mod cast;
3#[cfg(feature = "dynamic")]
4pub mod dynamic;
5pub mod element;
6pub mod error;
7pub mod execution;
8pub mod explain;
9pub mod index;
10pub mod operands;
11pub mod operations;
12pub mod optimizer;
13pub mod prelude;
14pub mod registry;
15pub mod selection;
16pub mod traits;
17pub mod value;
18
19pub use element::{
20    Arity, Bare, BoxedIterator, Definite, ElementShape, Indexed, Multiple, OrderState, Ordered,
21    Return, ReturnShape, Single, Unordered,
22};
23pub use error::{Diagnostic, ErrorGroup, External, Failure, FailureKind, QueryResult};
24pub use explain::{Explain, ExplainFormatter, Explanation, Labeled};
25pub use index::{
26    EdgeEndpointRole, EntityDomain, ExpandedChild, ExpandedIndex, ExpandedIndexOwned,
27    ExpandedIndexReference, GroupKey, IndexDomain, OwnedIndex, Position, Positional,
28};
29pub use operands::{
30    Bucket, BucketOwned, CheckedIndexedLaneBuilder, DefiniteEdgeOperand, DefiniteNodeOperand,
31    DefiniteReferenceOperand, EdgeOperand, EdgesOperand, EvaluateContext, EvaluateOperand,
32    GroupOperand, KeyFailure, KeyFailureOwned, NodeOperand, NodesOperand, Operand, OperandContext,
33    Partition, PartitionBucketParts, PartitionKeyFailureParts, PartitionOwned, PartitionOwnedParts,
34    PartitionParts, ReferenceOperand, ReferencesOperand, ReturnBucket, ReturnKeyFailure,
35    ReturnPartition, ReturnPartitionParts,
36};
37pub use operations::{EdgeDirection, MaybeAbsent, PreparedIndexedMultiple};
38pub use selection::{QueryEdges, QueryNodes};
39pub use traits::*;
40pub use value::{
41    AttributeName, BareValueDomain, EntityReference, FailureKindValue, FailureValue, IndexValue,
42    Mask, ReturnValueDomain, Scalar, Unit, ValueDomain,
43};
44
45mod sealed {
46    pub trait Sealed {}
47}
48
49#[cfg(test)]
50mod test {
51    use crate::{Attribute, Filter, HasAttribute, InGroup, QueryEdges, QueryNodes};
52    use graphrecords_core::{
53        GraphRecord,
54        errors::GraphRecordError,
55        graphrecord::{AttributeMap, GraphRecordValue, NodeIndex},
56    };
57    use std::collections::HashMap;
58
59    fn create_nodes() -> Vec<(NodeIndex, AttributeMap)> {
60        vec![
61            (
62                "0".into(),
63                HashMap::from([("lorem".into(), "ipsum".into())]),
64            ),
65            (
66                "1".into(),
67                HashMap::from([("amet".into(), "consectetur".into())]),
68            ),
69            (
70                "2".into(),
71                HashMap::from([("adipiscing".into(), "elit".into())]),
72            ),
73            ("3".into(), HashMap::new()),
74        ]
75    }
76
77    fn create_edges() -> Vec<(NodeIndex, NodeIndex, AttributeMap)> {
78        vec![
79            (
80                "0".into(),
81                "1".into(),
82                HashMap::from([
83                    ("sed".into(), "do".into()),
84                    ("eiusmod".into(), "tempor".into()),
85                ]),
86            ),
87            (
88                "1".into(),
89                "0".into(),
90                HashMap::from([
91                    ("sed".into(), "do".into()),
92                    ("eiusmod".into(), "tempor".into()),
93                ]),
94            ),
95            (
96                "1".into(),
97                "2".into(),
98                HashMap::from([("incididunt".into(), "ut".into())]),
99            ),
100            ("0".into(), "2".into(), HashMap::new()),
101        ]
102    }
103
104    fn create_graphrecord() -> GraphRecord {
105        let nodes = create_nodes();
106        let edges = create_edges();
107
108        let mut graphrecord = GraphRecord::from_tuples(nodes, Some(edges), None).unwrap();
109
110        graphrecord
111            .add_group("lorem".into(), Some(vec!["0".into(), "1".into()]), None)
112            .unwrap();
113        graphrecord
114            .add_group("ipsum".into(), Some(vec!["0".into()]), None)
115            .unwrap();
116
117        graphrecord
118    }
119
120    #[test]
121    fn test_query_nodes_attribute() {
122        let graphrecord = create_graphrecord();
123
124        let selection = graphrecord.query_nodes(|node| {
125            let nodes = node.filter(node.has_attribute("lorem".into()));
126
127            nodes.attribute("lorem".into())
128        });
129
130        let elements: Vec<_> = selection.evaluate().unwrap().collect();
131
132        assert_eq!(1, elements.len());
133        assert_eq!(&NodeIndex::from("0"), elements[0].0);
134        assert_eq!(
135            &GraphRecordValue::from("ipsum"),
136            elements[0].1.as_ref().unwrap()
137        );
138    }
139
140    #[test]
141    fn test_query_nodes_in_group() {
142        let graphrecord = create_graphrecord();
143
144        let selection = graphrecord.query_nodes(|node| {
145            let nodes = node.filter(node.in_group("lorem".into()) & !node.in_group("ipsum".into()));
146
147            nodes.attribute("amet".into())
148        });
149
150        let elements: Vec<_> = selection.evaluate().unwrap().collect();
151
152        assert_eq!(1, elements.len());
153        assert_eq!(&NodeIndex::from("1"), elements[0].0);
154        assert_eq!(
155            &GraphRecordValue::from("consectetur"),
156            elements[0].1.as_ref().unwrap()
157        );
158    }
159
160    #[test]
161    fn test_invalid_query_nodes_in_group() {
162        let graphrecord = create_graphrecord();
163
164        let selection =
165            graphrecord.query_nodes(|node| node.filter(node.in_group("consectetur".into())));
166
167        // Querying the nodes in a non-existing group should fail
168        assert!(selection.evaluate().is_err_and(|failure| matches!(
169            failure.downcast_cause::<GraphRecordError>(),
170            Some(GraphRecordError::GroupNotFound { .. })
171        )));
172    }
173
174    #[test]
175    fn test_query_edges_attribute() {
176        let graphrecord = create_graphrecord();
177
178        let selection = graphrecord.query_edges(|edge| {
179            let edges = edge.filter(edge.has_attribute("incididunt".into()));
180
181            edges.attribute("incididunt".into())
182        });
183
184        let elements: Vec<_> = selection.evaluate().unwrap().collect();
185
186        assert_eq!(1, elements.len());
187        assert_eq!(&2, elements[0].0);
188        assert_eq!(
189            &GraphRecordValue::from("ut"),
190            elements[0].1.as_ref().unwrap()
191        );
192    }
193}