graphrecords_query/operations/string_operations/
replace_all.rs1use 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::ReplaceAll,
14};
15use graphrecords_core::GraphRecord;
16
17#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
18#[operation(scope = Element)]
19#[explain(label = "ReplaceAll")]
20#[plan(optimizer_hints(empty = if_all))]
21pub struct ReplaceAllOperation<A, B> {
22 #[argument]
23 old: A,
24 #[argument]
25 new: B,
26}
27
28impl<A: Prepare, B: Prepare> Prepare for ReplaceAllOperation<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 ReplaceAllOperation<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.replace(old, new),
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 ReplaceAllOperation<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.replace(old, new),
93 ))
94 }
95
96 fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
97 input.with_unknown_distinct()
98 }
99}
100
101impl<O, A, B> ReplaceAll<A, B> for O
102where
103 ReplaceAllOperation<A, B>: Operation,
104 O: Apply<ReplaceAllOperation<A, B>>,
105{
106 type ReturnOperand = O::Output;
107
108 fn replace_all(&self, old: A, new: B) -> Self::ReturnOperand {
109 Self::ReturnOperand::new(OperationContext::new(
110 self.clone(),
111 ReplaceAllOperation { old, new },
112 ))
113 }
114}
115
116operation_manifest! {
117 ReplaceAllOperation<A, B> {
118 method: ReplaceAll<A, B>::replace_all;
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}