Skip to main content

graphrecords_query/operations/comparison/
equal_to.rs

1use super::{equality_bare, equality_indexed};
2use crate::{
3    Bare, BareValueDomain, Explain, IndexDomain, Indexed, Labeled, Mask, Operand, QueryResult,
4    capabilities::ValueEquality,
5    execution::EvaluationCache,
6    operations::{
7        Apply, ArgumentSource, ElementKernel, ElementPipeline, Keyed, Operation, OperationContext,
8        Prepare, Unaligned,
9    },
10    optimizer::{Estimate, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs, Stats},
11    registry::{describe::ArgumentRetention, operation_manifest},
12    traits::EqualTo,
13};
14use graphrecords_core::GraphRecord;
15
16#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
17#[operation(scope = Element)]
18#[explain(label = "EqualTo")]
19#[plan(optimizer_hints(empty = if_all))]
20pub struct EqualToOperation<A> {
21    #[argument]
22    argument: A,
23}
24
25impl<A: Prepare> Prepare for EqualToOperation<A> {
26    type Prepared<'a>
27        = A::Prepared<'a>
28    where
29        Self: 'a;
30
31    fn prepare<'a>(
32        &'a self,
33        graphrecord: &'a GraphRecord,
34        cache: &'a EvaluationCache<'a>,
35    ) -> QueryResult<Self::Prepared<'a>> {
36        self.argument.prepare(graphrecord, cache)
37    }
38}
39
40impl<I, V, A> ElementKernel<Indexed<I, V>> for EqualToOperation<A>
41where
42    I: IndexDomain,
43    V: ValueEquality,
44    A: ArgumentSource<Keyed<I>, V>,
45{
46    type Emission = A::Retention;
47    type OutShape = Indexed<I, Mask>;
48
49    fn pipeline<'a>(
50        _graphrecord: &'a GraphRecord,
51        prepared: Self::Prepared<'a>,
52    ) -> QueryResult<ElementPipeline<'a, Indexed<I, V>, Self>> {
53        Ok(equality_indexed::<_, V, A>(prepared, Self::LABEL, V::equal))
54    }
55
56    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
57        let selectivity = input.distinct.map(|distinct| 1.0 / distinct.max(1) as f64);
58
59        Estimate {
60            selectivity,
61            ..input.with_unknown_distinct()
62        }
63    }
64}
65
66impl<V, A> ElementKernel<Bare<V>> for EqualToOperation<A>
67where
68    V: ValueEquality + BareValueDomain,
69    A: ArgumentSource<Unaligned, V>,
70{
71    type Emission = A::Retention;
72    type OutShape = Bare<Mask>;
73
74    fn pipeline<'a>(
75        _graphrecord: &'a GraphRecord,
76        prepared: Self::Prepared<'a>,
77    ) -> QueryResult<ElementPipeline<'a, Bare<V>, Self>> {
78        Ok(equality_bare::<V, A>(prepared, Self::LABEL, V::equal))
79    }
80
81    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
82        let selectivity = input.distinct.map(|distinct| 1.0 / distinct.max(1) as f64);
83
84        Estimate {
85            selectivity,
86            ..input.with_unknown_distinct()
87        }
88    }
89}
90
91impl<O, A> EqualTo<A> for O
92where
93    EqualToOperation<A>: Operation,
94    O: Apply<EqualToOperation<A>>,
95{
96    type ReturnOperand = O::Output;
97
98    fn equal_to(&self, argument: A) -> Self::ReturnOperand {
99        Self::ReturnOperand::new(OperationContext::new(
100            self.clone(),
101            EqualToOperation { argument },
102        ))
103    }
104}
105
106operation_manifest! {
107    EqualToOperation<A> {
108        method: EqualTo<A>::equal_to;
109        scope: element;
110
111        kernel {
112            parameters: <I: IndexDomain, V: ValueEquality>;
113            argument: A: ArgumentSource<Keyed<I>, V>;
114            input: Indexed<I, V>;
115            output: Indexed<I, Mask>;
116            emission: ArgumentRetention;
117        }
118
119        kernel {
120            parameters: <V: ValueEquality + BareValueDomain>;
121            argument: A: ArgumentSource<Unaligned, V>;
122            input: Bare<V>;
123            output: Bare<Mask>;
124            emission: ArgumentRetention;
125        }
126    }
127}