graphrecords_query/operations/traversal/
via_nodes.rs1use crate::{
2 EdgeEndpointRole, EntityReference, ExpandedChild, ExpandedIndex, Explain, IndexDomain, Indexed,
3 Operand, Ordered, QueryResult, Unit,
4 element::{Expanding, Pipeline},
5 execution::EvaluationCache,
6 operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
7 optimizer::{OperationInputs, OptimizerHints, PlanIdentity, PlanInputs},
8 registry::operation_manifest,
9 traits::ViaNodes,
10};
11use graphrecords_core::{
12 GraphRecord,
13 graphrecord::{EdgeIndex, NodeIndex},
14};
15
16#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
17#[operation(scope = Element)]
18#[explain(label = "ViaNodes")]
19#[plan(optimizer_hints(empty = if_any))]
20pub struct ViaNodesOperation;
21
22impl Prepare for ViaNodesOperation {
23 type Prepared<'a> = ();
24
25 fn prepare<'a>(
26 &'a self,
27 _graphrecord: &'a GraphRecord,
28 _cache: &'a EvaluationCache<'a>,
29 ) -> QueryResult<Self::Prepared<'a>> {
30 Ok(())
31 }
32}
33
34impl ElementKernel<Indexed<EdgeIndex, Unit>> for ViaNodesOperation {
35 type Emission = Expanding<Ordered>;
36 type OutShape = Indexed<ExpandedIndex<EdgeIndex, EdgeEndpointRole>, EntityReference<NodeIndex>>;
37
38 fn pipeline<'a>(
39 graphrecord: &'a GraphRecord,
40 _prepared: Self::Prepared<'a>,
41 ) -> QueryResult<ElementPipeline<'a, Indexed<EdgeIndex, Unit>, Self>> {
42 Ok(Pipeline::keyed(move |parent_index, ()| {
43 let (source, target) = graphrecord
44 .edge_endpoints(parent_index)
45 .expect("Edge must exist");
46
47 Ok(vec![
48 ExpandedChild::success(EdgeEndpointRole::Source, source),
49 ExpandedChild::success(EdgeEndpointRole::Target, target),
50 ])
51 }))
52 }
53}
54
55impl<I: IndexDomain> ElementKernel<Indexed<I, EntityReference<EdgeIndex>>> for ViaNodesOperation {
56 type Emission = Expanding<Ordered>;
57 type OutShape = Indexed<ExpandedIndex<I, EdgeEndpointRole>, EntityReference<NodeIndex>>;
58
59 fn pipeline<'a>(
60 graphrecord: &'a GraphRecord,
61 _prepared: Self::Prepared<'a>,
62 ) -> QueryResult<ElementPipeline<'a, Indexed<I, EntityReference<EdgeIndex>>, Self>> {
63 Ok(Pipeline::unkeyed(move |edge| {
64 let (source, target) = graphrecord.edge_endpoints(edge).expect("Edge must exist");
65
66 Ok(vec![
67 ExpandedChild::success(EdgeEndpointRole::Source, source),
68 ExpandedChild::success(EdgeEndpointRole::Target, target),
69 ])
70 }))
71 }
72}
73
74impl<O: Apply<ViaNodesOperation>> ViaNodes for O {
75 type ReturnOperand = O::Output;
76
77 fn via_nodes(&self) -> Self::ReturnOperand {
78 Self::ReturnOperand::new(OperationContext::new(self.clone(), ViaNodesOperation))
79 }
80}
81
82operation_manifest! {
83 ViaNodesOperation {
84 method: ViaNodes::via_nodes;
85 scope: element;
86
87 kernel {
88 parameters: <>;
89 input: Indexed<EdgeIndex, Unit>;
90 output: Indexed<ExpandedIndex<EdgeIndex, EdgeEndpointRole>, EntityReference<NodeIndex>>;
91 emission: Expanding<Ordered>;
92 }
93
94 kernel {
95 parameters: <I: IndexDomain>;
96 input: Indexed<I, EntityReference<EdgeIndex>>;
97 output: Indexed<ExpandedIndex<I, EdgeEndpointRole>, EntityReference<NodeIndex>>;
98 emission: Expanding<Ordered>;
99 }
100 }
101}