Skip to main content

graphrecords_query/operations/string_operations/
replace.rs

1use super::{string_replace_bare, string_replace_indexed};
2use crate::{
3    Bare, BareValueDomain, Explain, IndexDomain, Indexed, Labeled, Operand, QueryResult,
4    capabilities::StringValue,
5    element::Retention,
6    execution::EvaluationCache,
7    operations::{
8        Apply, ArgumentSource, ElementKernel, ElementPipeline, Keyed, Operation, OperationContext,
9        Prepare, Unaligned,
10    },
11    optimizer::{Estimate, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs, Stats},
12    registry::{describe::ArgumentRetention, operation_manifest},
13    traits::Replace,
14};
15use graphrecords_core::GraphRecord;
16
17#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
18#[operation(scope = Element)]
19#[explain(label = "Replace")]
20#[plan(optimizer_hints(empty = if_all))]
21pub struct ReplaceOperation<A, B> {
22    #[argument]
23    old: A,
24    #[argument]
25    new: B,
26}
27
28impl<A: Prepare, B: Prepare> Prepare for ReplaceOperation<A, B> {
29    type Prepared<'a>
30        = (A::Prepared<'a>, B::Prepared<'a>)
31    where
32        Self: 'a;
33
34    fn prepare<'a>(
35        &'a self,
36        graphrecord: &'a GraphRecord,
37        cache: &'a EvaluationCache<'a>,
38    ) -> QueryResult<Self::Prepared<'a>> {
39        Ok((
40            self.old.prepare(graphrecord, cache)?,
41            self.new.prepare(graphrecord, cache)?,
42        ))
43    }
44}
45
46impl<I, V, A, B> ElementKernel<Indexed<I, V>> for ReplaceOperation<A, B>
47where
48    I: IndexDomain,
49    V: StringValue,
50    A: ArgumentSource<Keyed<I>>,
51    A::ValueDomain: StringValue,
52    B: ArgumentSource<Keyed<I>>,
53    B::ValueDomain: StringValue,
54{
55    type Emission = <A::Retention as Retention>::Then<B::Retention>;
56    type OutShape = Indexed<I, V>;
57
58    fn pipeline<'a>(
59        _graphrecord: &'a GraphRecord,
60        prepared: Self::Prepared<'a>,
61    ) -> QueryResult<ElementPipeline<'a, Indexed<I, V>, Self>> {
62        Ok(string_replace_indexed::<_, V, A, B>(
63            prepared,
64            Self::LABEL,
65            |value, old, new| value.replacen(old, new, 1),
66        ))
67    }
68
69    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
70        input.with_unknown_distinct()
71    }
72}
73
74impl<V, A, B> ElementKernel<Bare<V>> for ReplaceOperation<A, B>
75where
76    V: StringValue + BareValueDomain,
77    A: ArgumentSource<Unaligned>,
78    A::ValueDomain: StringValue,
79    B: ArgumentSource<Unaligned>,
80    B::ValueDomain: StringValue,
81{
82    type Emission = <A::Retention as Retention>::Then<B::Retention>;
83    type OutShape = Bare<V>;
84
85    fn pipeline<'a>(
86        _graphrecord: &'a GraphRecord,
87        prepared: Self::Prepared<'a>,
88    ) -> QueryResult<ElementPipeline<'a, Bare<V>, Self>> {
89        Ok(string_replace_bare::<V, A, B>(
90            prepared,
91            Self::LABEL,
92            |value, old, new| value.replacen(old, new, 1),
93        ))
94    }
95
96    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
97        input.with_unknown_distinct()
98    }
99}
100
101impl<O, A, B> Replace<A, B> for O
102where
103    ReplaceOperation<A, B>: Operation,
104    O: Apply<ReplaceOperation<A, B>>,
105{
106    type ReturnOperand = O::Output;
107
108    fn replace(&self, old: A, new: B) -> Self::ReturnOperand {
109        Self::ReturnOperand::new(OperationContext::new(
110            self.clone(),
111            ReplaceOperation { old, new },
112        ))
113    }
114}
115
116operation_manifest! {
117    ReplaceOperation<A, B> {
118        method: Replace<A, B>::replace;
119        scope: element;
120
121        kernel {
122            parameters: <I: IndexDomain, V: StringValue>;
123            argument: A: ArgumentSource<Keyed<I>> where A::ValueDomain: StringValue;
124            argument: B: ArgumentSource<Keyed<I>> where B::ValueDomain: StringValue;
125            input: Indexed<I, V>;
126            output: Indexed<I, V>;
127            emission: ArgumentRetention;
128        }
129        kernel {
130            parameters: <V: StringValue + BareValueDomain>;
131            argument: A: ArgumentSource<Unaligned> where A::ValueDomain: StringValue;
132            argument: B: ArgumentSource<Unaligned> where B::ValueDomain: StringValue;
133            input: Bare<V>;
134            output: Bare<V>;
135            emission: ArgumentRetention;
136        }
137    }
138}