graphrecords_query/operations/comparison/
not_equal_to.rs1use 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}