Skip to main content

graphrecords_query/operations/comparison/
not_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::NotEqualTo,
13};
14use graphrecords_core::GraphRecord;
15
16#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
17#[operation(scope = Element)]
18#[explain(label = "NotEqualTo")]
19#[plan(optimizer_hints(empty = if_all))]
20pub struct NotEqualToOperation<A> {
21    #[argument]
22    argument: A,
23}
24
25impl<A: Prepare> Prepare for NotEqualToOperation<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 NotEqualToOperation<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>(
54            prepared,
55            Self::LABEL,
56            |value, argument| !V::equal(value, argument),
57        ))
58    }
59
60    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
61        let selectivity = input
62            .distinct
63            .map(|distinct| 1.0 - 1.0 / distinct.max(1) as f64);
64
65        Estimate {
66            selectivity,
67            ..input.with_unknown_distinct()
68        }
69    }
70}
71
72impl<V, A> ElementKernel<Bare<V>> for NotEqualToOperation<A>
73where
74    V: ValueEquality + BareValueDomain,
75    A: ArgumentSource<Unaligned, V>,
76{
77    type Emission = A::Retention;
78    type OutShape = Bare<Mask>;
79
80    fn pipeline<'a>(
81        _graphrecord: &'a GraphRecord,
82        prepared: Self::Prepared<'a>,
83    ) -> QueryResult<ElementPipeline<'a, Bare<V>, Self>> {
84        Ok(equality_bare::<V, A>(
85            prepared,
86            Self::LABEL,
87            |value, argument| !V::equal(value, argument),
88        ))
89    }
90
91    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
92        let selectivity = input
93            .distinct
94            .map(|distinct| 1.0 - 1.0 / distinct.max(1) as f64);
95
96        Estimate {
97            selectivity,
98            ..input.with_unknown_distinct()
99        }
100    }
101}
102
103impl<O, A> NotEqualTo<A> for O
104where
105    NotEqualToOperation<A>: Operation,
106    O: Apply<NotEqualToOperation<A>>,
107{
108    type ReturnOperand = O::Output;
109
110    fn not_equal_to(&self, argument: A) -> Self::ReturnOperand {
111        Self::ReturnOperand::new(OperationContext::new(
112            self.clone(),
113            NotEqualToOperation { argument },
114        ))
115    }
116}
117
118operation_manifest! {
119    NotEqualToOperation<A> {
120        method: NotEqualTo<A>::not_equal_to;
121        scope: element;
122
123        kernel {
124            parameters: <I: IndexDomain, V: ValueEquality>;
125            argument: A: ArgumentSource<Keyed<I>, V>;
126            input: Indexed<I, V>;
127            output: Indexed<I, Mask>;
128            emission: ArgumentRetention;
129        }
130
131        kernel {
132            parameters: <V: ValueEquality + BareValueDomain>;
133            argument: A: ArgumentSource<Unaligned, V>;
134            input: Bare<V>;
135            output: Bare<Mask>;
136            emission: ArgumentRetention;
137        }
138    }
139}