Skip to main content

graphrecords_query/operations/string_operations/
starts_with.rs

1use 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::StartsWith,
13};
14use graphrecords_core::GraphRecord;
15
16#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
17#[operation(scope = Element)]
18#[explain(label = "StartsWith")]
19#[plan(optimizer_hints(empty = if_all))]
20pub struct StartsWithOperation<A> {
21    #[argument]
22    argument: A,
23}
24
25impl<A: Prepare> Prepare for StartsWithOperation<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 StartsWithOperation<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.starts_with(&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 StartsWithOperation<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.starts_with(&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> StartsWith<A> for O
98where
99    StartsWithOperation<A>: Operation,
100    O: Apply<StartsWithOperation<A>>,
101{
102    type ReturnOperand = O::Output;
103
104    fn starts_with(&self, argument: A) -> Self::ReturnOperand {
105        Self::ReturnOperand::new(OperationContext::new(
106            self.clone(),
107            StartsWithOperation { argument },
108        ))
109    }
110}
111
112operation_manifest! {
113    StartsWithOperation<A> {
114        method: StartsWith<A>::starts_with;
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}