Skip to main content

graphrecords_query/operations/indexing/
expanded.rs

1use crate::{
2    Bare, ExpandedIndex, ExpandedIndexOwned, Explain, Failure, IndexDomain, IndexValue, Indexed,
3    Labeled, Operand, QueryResult,
4    element::{Pipeline, Preserving},
5    error::index::NoChildIndex,
6    execution::EvaluationCache,
7    operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
8    optimizer::{OperationInputs, OptimizerHints, PlanIdentity, PlanInputs},
9    registry::operation_manifest,
10    traits::{ChildIndex, ParentIndex},
11};
12use graphrecords_core::GraphRecord;
13
14#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
15#[operation(scope = Element)]
16#[explain(label = "ParentIndex")]
17#[plan(optimizer_hints(commutes_with_filter, allows_limit_pushdown, empty = if_any))]
18pub struct ParentIndexOperation;
19
20impl Prepare for ParentIndexOperation {
21    type Prepared<'a> = ();
22
23    fn prepare<'a>(
24        &'a self,
25        _graphrecord: &'a GraphRecord,
26        _cache: &'a EvaluationCache<'a>,
27    ) -> QueryResult<Self::Prepared<'a>> {
28        Ok(())
29    }
30}
31
32impl<I: IndexDomain, P: IndexDomain, C: IndexDomain>
33    ElementKernel<Indexed<I, IndexValue<ExpandedIndex<P, C>>>> for ParentIndexOperation
34{
35    type Emission = Preserving;
36    type OutShape = Indexed<I, IndexValue<P>>;
37
38    fn pipeline<'a>(
39        _graphrecord: &'a GraphRecord,
40        _prepared: Self::Prepared<'a>,
41    ) -> QueryResult<ElementPipeline<'a, Indexed<I, IndexValue<ExpandedIndex<P, C>>>, Self>> {
42        Ok(Pipeline::unkeyed(
43            |outcome: QueryResult<ExpandedIndexOwned<_, _>>| {
44                outcome.map(|address| address.into_parts().0)
45            },
46        ))
47    }
48}
49
50impl<P: IndexDomain, C: IndexDomain> ElementKernel<Bare<IndexValue<ExpandedIndex<P, C>>>>
51    for ParentIndexOperation
52{
53    type Emission = Preserving;
54    type OutShape = Bare<IndexValue<P>>;
55
56    fn pipeline<'a>(
57        _graphrecord: &'a GraphRecord,
58        _prepared: Self::Prepared<'a>,
59    ) -> QueryResult<ElementPipeline<'a, Bare<IndexValue<ExpandedIndex<P, C>>>, Self>> {
60        Ok(Pipeline::new(
61            |outcome: QueryResult<ExpandedIndexOwned<_, _>>| {
62                outcome.map(|address| address.into_parts().0)
63            },
64        ))
65    }
66}
67
68impl<O: Apply<ParentIndexOperation>> ParentIndex for O {
69    type ReturnOperand = O::Output;
70
71    fn parent_index(&self) -> Self::ReturnOperand {
72        Self::ReturnOperand::new(OperationContext::new(self.clone(), ParentIndexOperation))
73    }
74}
75
76pub(super) mod parent_index {
77    use super::{
78        Bare, ExpandedIndex, IndexValue, Indexed, ParentIndex, ParentIndexOperation, Preserving,
79        operation_manifest,
80    };
81
82    operation_manifest! {
83        ParentIndexOperation {
84            method: ParentIndex::parent_index;
85            scope: element;
86
87            kernel {
88                parameters: <I: IndexDomain, P: IndexDomain, C: IndexDomain>;
89                input: Indexed<I, IndexValue<ExpandedIndex<P, C>>>;
90                output: Indexed<I, IndexValue<P>>;
91                emission: Preserving;
92            }
93            kernel {
94                parameters: <P: IndexDomain, C: IndexDomain>;
95                input: Bare<IndexValue<ExpandedIndex<P, C>>>;
96                output: Bare<IndexValue<P>>;
97                emission: Preserving;
98            }
99        }
100    }
101}
102
103#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
104#[operation(scope = Element)]
105#[explain(label = "ChildIndex")]
106#[plan(optimizer_hints(allows_limit_pushdown, empty = if_any))]
107pub struct ChildIndexOperation;
108
109impl Prepare for ChildIndexOperation {
110    type Prepared<'a> = ();
111
112    fn prepare<'a>(
113        &'a self,
114        _graphrecord: &'a GraphRecord,
115        _cache: &'a EvaluationCache<'a>,
116    ) -> QueryResult<Self::Prepared<'a>> {
117        Ok(())
118    }
119}
120
121impl<I: IndexDomain, P: IndexDomain, C: IndexDomain>
122    ElementKernel<Indexed<I, IndexValue<ExpandedIndex<P, C>>>> for ChildIndexOperation
123{
124    type Emission = Preserving;
125    type OutShape = Indexed<I, IndexValue<C>>;
126
127    fn pipeline<'a>(
128        _graphrecord: &'a GraphRecord,
129        _prepared: Self::Prepared<'a>,
130    ) -> QueryResult<ElementPipeline<'a, Indexed<I, IndexValue<ExpandedIndex<P, C>>>, Self>> {
131        Ok(Pipeline::keyed(
132            |lane_index, outcome: QueryResult<ExpandedIndexOwned<_, _>>| {
133                let (parent, child) = outcome?.into_parts();
134
135                child.ok_or_else(|| {
136                    Failure::new_at::<I, _>(
137                        Self::LABEL,
138                        NoChildIndex::<P>::new(parent),
139                        &lane_index,
140                    )
141                })
142            },
143        ))
144    }
145}
146
147impl<P: IndexDomain, C: IndexDomain> ElementKernel<Bare<IndexValue<ExpandedIndex<P, C>>>>
148    for ChildIndexOperation
149{
150    type Emission = Preserving;
151    type OutShape = Bare<IndexValue<C>>;
152
153    fn pipeline<'a>(
154        _graphrecord: &'a GraphRecord,
155        _prepared: Self::Prepared<'a>,
156    ) -> QueryResult<ElementPipeline<'a, Bare<IndexValue<ExpandedIndex<P, C>>>, Self>> {
157        Ok(Pipeline::new(
158            |outcome: QueryResult<ExpandedIndexOwned<_, _>>| {
159                let (parent, child) = outcome?.into_parts();
160
161                child.ok_or_else(|| Failure::new(Self::LABEL, NoChildIndex::<P>::new(parent)))
162            },
163        ))
164    }
165}
166
167impl<O: Apply<ChildIndexOperation>> ChildIndex for O {
168    type ReturnOperand = O::Output;
169
170    fn child_index(&self) -> Self::ReturnOperand {
171        Self::ReturnOperand::new(OperationContext::new(self.clone(), ChildIndexOperation))
172    }
173}
174
175pub(super) mod child_index {
176    use super::{
177        Bare, ChildIndex, ChildIndexOperation, ExpandedIndex, IndexValue, Indexed, Preserving,
178        operation_manifest,
179    };
180
181    operation_manifest! {
182        ChildIndexOperation {
183            method: ChildIndex::child_index;
184            scope: element;
185
186            kernel {
187                parameters: <I: IndexDomain, P: IndexDomain, C: IndexDomain>;
188                input: Indexed<I, IndexValue<ExpandedIndex<P, C>>>;
189                output: Indexed<I, IndexValue<C>>;
190                emission: Preserving;
191            }
192            kernel {
193                parameters: <P: IndexDomain, C: IndexDomain>;
194                input: Bare<IndexValue<ExpandedIndex<P, C>>>;
195                output: Bare<IndexValue<C>>;
196                emission: Preserving;
197            }
198        }
199    }
200}