graphrecords_query/operations/string_operations/
contains.rs1use super::{string_argument_map_bare, string_argument_map_indexed};
2use crate::{
3 Bare, BareValueDomain, Explain, IndexDomain, Indexed, Labeled, Mask, Operand, QueryResult,
4 capabilities::StringValue,
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::Contains,
13};
14use graphrecords_core::GraphRecord;
15
16#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
17#[operation(scope = Element)]
18#[explain(label = "Contains")]
19#[plan(optimizer_hints(empty = if_all))]
20pub struct ContainsOperation<A> {
21 #[argument]
22 argument: A,
23}
24
25impl<A: Prepare> Prepare for ContainsOperation<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 ContainsOperation<A>
41where
42 I: IndexDomain,
43 V: StringValue,
44 A: ArgumentSource<Keyed<I>>,
45 A::ValueDomain: StringValue,
46{
47 type Emission = A::Retention;
48 type OutShape = Indexed<I, Mask>;
49
50 fn pipeline<'a>(
51 _graphrecord: &'a GraphRecord,
52 prepared: Self::Prepared<'a>,
53 ) -> QueryResult<ElementPipeline<'a, Indexed<I, V>, Self>> {
54 Ok(string_argument_map_indexed::<_, V, Mask, A>(
55 prepared,
56 Self::LABEL,
57 |_, value, argument| Ok(value.contains(&argument)),
58 ))
59 }
60
61 fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
62 Estimate {
63 selectivity: None,
64 ..input.with_unknown_distinct()
65 }
66 }
67}
68
69impl<V, A> ElementKernel<Bare<V>> for ContainsOperation<A>
70where
71 V: StringValue + BareValueDomain,
72 A: ArgumentSource<Unaligned>,
73 A::ValueDomain: StringValue,
74{
75 type Emission = A::Retention;
76 type OutShape = Bare<Mask>;
77
78 fn pipeline<'a>(
79 _graphrecord: &'a GraphRecord,
80 prepared: Self::Prepared<'a>,
81 ) -> QueryResult<ElementPipeline<'a, Bare<V>, Self>> {
82 Ok(string_argument_map_bare::<V, Mask, A>(
83 prepared,
84 Self::LABEL,
85 |_, value, argument| Ok(value.contains(&argument)),
86 ))
87 }
88
89 fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
90 Estimate {
91 selectivity: None,
92 ..input.with_unknown_distinct()
93 }
94 }
95}
96
97impl<O, A> Contains<A> for O
98where
99 ContainsOperation<A>: Operation,
100 O: Apply<ContainsOperation<A>>,
101{
102 type ReturnOperand = O::Output;
103
104 fn contains(&self, argument: A) -> Self::ReturnOperand {
105 Self::ReturnOperand::new(OperationContext::new(
106 self.clone(),
107 ContainsOperation { argument },
108 ))
109 }
110}
111
112operation_manifest! {
113 ContainsOperation<A> {
114 method: Contains<A>::contains;
115 scope: element;
116
117 kernel {
118 parameters: <I: IndexDomain, V: StringValue>;
119 argument: A: ArgumentSource<Keyed<I>> where A::ValueDomain: StringValue;
120 input: Indexed<I, V>;
121 output: Indexed<I, Mask>;
122 emission: ArgumentRetention;
123 }
124 kernel {
125 parameters: <V: StringValue + BareValueDomain>;
126 argument: A: ArgumentSource<Unaligned> where A::ValueDomain: StringValue;
127 input: Bare<V>;
128 output: Bare<Mask>;
129 emission: ArgumentRetention;
130 }
131 }
132}