Skip to main content

graphrecords_query/operations/indexing/
index.rs

1use crate::{
2    EntityDomain, EntityReference, Explain, IndexDomain, IndexValue, Indexed, Operand, QueryResult,
3    Unit,
4    element::{Pipeline, Preserving},
5    execution::EvaluationCache,
6    operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
7    optimizer::{Estimate, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs, Stats},
8    registry::operation_manifest,
9    traits::Index,
10};
11use graphrecords_core::GraphRecord;
12
13#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
14#[operation(scope = Element)]
15#[explain(label = "Index")]
16#[plan(optimizer_hints(commutes_with_filter, allows_limit_pushdown, empty = if_any))]
17pub struct IndexOperation;
18
19impl Prepare for IndexOperation {
20    type Prepared<'a> = ();
21
22    fn prepare<'a>(
23        &'a self,
24        _graphrecord: &'a GraphRecord,
25        _cache: &'a EvaluationCache<'a>,
26    ) -> QueryResult<Self::Prepared<'a>> {
27        Ok(())
28    }
29}
30
31impl<K: IndexDomain> ElementKernel<Indexed<K, Unit>> for IndexOperation {
32    type Emission = Preserving;
33    type OutShape = Indexed<K, IndexValue<K>>;
34
35    fn pipeline<'a>(
36        _graphrecord: &'a GraphRecord,
37        _prepared: Self::Prepared<'a>,
38    ) -> QueryResult<ElementPipeline<'a, Indexed<K, Unit>, Self>> {
39        Ok(Pipeline::keyed(|index, value: QueryResult<_>| {
40            value.map(|()| K::to_owned(&index))
41        }))
42    }
43
44    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
45        Estimate {
46            distinct: input.elements,
47            ..input
48        }
49    }
50}
51
52impl<E: EntityDomain, I: IndexDomain> ElementKernel<Indexed<I, EntityReference<E>>>
53    for IndexOperation
54{
55    type Emission = Preserving;
56    type OutShape = Indexed<I, IndexValue<E>>;
57
58    fn pipeline<'a>(
59        _graphrecord: &'a GraphRecord,
60        _prepared: Self::Prepared<'a>,
61    ) -> QueryResult<ElementPipeline<'a, Indexed<I, EntityReference<E>>, Self>> {
62        Ok(Pipeline::unkeyed(|reference: QueryResult<_>| {
63            reference.map(|entity| E::to_owned(&entity))
64        }))
65    }
66
67    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
68        input
69    }
70}
71
72impl<O: Apply<IndexOperation>> Index for O {
73    type ReturnOperand = O::Output;
74
75    fn index(&self) -> Self::ReturnOperand {
76        Self::ReturnOperand::new(OperationContext::new(self.clone(), IndexOperation))
77    }
78}
79
80operation_manifest! {
81    IndexOperation {
82        method: Index::index;
83        scope: element;
84
85        kernel {
86            parameters: <K: IndexDomain>;
87            input: Indexed<K, Unit>;
88            output: Indexed<K, IndexValue<K>>;
89            emission: Preserving;
90        }
91
92        kernel {
93            parameters: <E: EntityDomain, I: IndexDomain>;
94            input: Indexed<I, EntityReference<E>>;
95            output: Indexed<I, IndexValue<E>>;
96            emission: Preserving;
97        }
98    }
99}