Skip to main content

graphrecords_query/operations/string_operations/
strip_prefix.rs

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