Skip to main content

graphrecords_query/operations/conversion/
cast.rs

1use crate::{
2    Bare, BareValueDomain, Explain, IndexDomain, Indexed, Labeled, Operand, QueryResult,
3    capabilities::ValueCast,
4    cast::{Bool, CastTarget, DateTime, Duration, Float, Int, String},
5    element::{Pipeline, Preserving},
6    execution::EvaluationCache,
7    operations::{Apply, ElementKernel, ElementPipeline, Operation, OperationContext, Prepare},
8    optimizer::{Estimate, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs, Stats},
9    registry::operation_manifest,
10    traits::Cast,
11};
12use graphrecords_core::GraphRecord;
13
14#[derive(Clone, Explain, Operation, OperationInputs, OptimizerHints, PlanIdentity, PlanInputs)]
15#[operation(scope = Element)]
16#[explain(label = "Cast")]
17#[plan(optimizer_hints(allows_limit_pushdown, empty = if_any))]
18pub struct CastOperation<T: CastTarget> {
19    #[explain(label)]
20    target: T,
21}
22
23impl<T: CastTarget> Prepare for CastOperation<T> {
24    type Prepared<'a>
25        = &'a T
26    where
27        Self: 'a;
28
29    fn prepare<'a>(
30        &'a self,
31        _graphrecord: &'a GraphRecord,
32        _cache: &'a EvaluationCache<'a>,
33    ) -> QueryResult<Self::Prepared<'a>> {
34        Ok(&self.target)
35    }
36}
37
38impl<I, V, T> ElementKernel<Indexed<I, V>> for CastOperation<T>
39where
40    I: IndexDomain,
41    V: ValueCast<T>,
42    T: CastTarget,
43{
44    type Emission = Preserving;
45    type OutShape = Indexed<I, V>;
46
47    fn pipeline<'a>(
48        _graphrecord: &'a GraphRecord,
49        prepared: Self::Prepared<'a>,
50    ) -> QueryResult<ElementPipeline<'a, Indexed<I, V>, Self>> {
51        Ok(Pipeline::keyed(move |index, outcome: QueryResult<_>| {
52            outcome.and_then(|value| {
53                V::cast(Self::LABEL, value, prepared).map_err(|failure| failure.at::<I>(&index))
54            })
55        }))
56    }
57
58    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
59        input.with_unknown_distinct()
60    }
61}
62
63impl<V, T> ElementKernel<Bare<V>> for CastOperation<T>
64where
65    V: ValueCast<T> + BareValueDomain,
66    T: CastTarget,
67{
68    type Emission = Preserving;
69    type OutShape = Bare<V>;
70
71    fn pipeline<'a>(
72        _graphrecord: &'a GraphRecord,
73        prepared: Self::Prepared<'a>,
74    ) -> QueryResult<ElementPipeline<'a, Bare<V>, Self>> {
75        Ok(Pipeline::new(move |outcome: QueryResult<_>| {
76            outcome.and_then(|value| V::cast(Self::LABEL, value, prepared))
77        }))
78    }
79
80    fn estimate(&self, input: Estimate, _stats: &Stats) -> Estimate {
81        input.with_unknown_distinct()
82    }
83}
84
85impl<O, T> Cast<T> for O
86where
87    CastOperation<T>: Operation,
88    O: Apply<CastOperation<T>>,
89    T: CastTarget,
90{
91    type ReturnOperand = O::Output;
92
93    fn cast(&self, target: T) -> Self::ReturnOperand {
94        Self::ReturnOperand::new(OperationContext::new(
95            self.clone(),
96            CastOperation { target },
97        ))
98    }
99}
100
101pub(super) mod bool {
102    use super::{Bare, Bool, Cast, CastOperation, Indexed, Preserving, operation_manifest};
103
104    operation_manifest! {
105        CastOperation<Bool> {
106            method: Cast<Bool>::cast;
107            scope: element;
108
109            kernel {
110                parameters: <I: IndexDomain, V: ValueCast<Bool>,>;
111                selector: Bool;
112                input: Indexed<I, V>;
113                output: Indexed<I, V>;
114                emission: Preserving;
115            }
116
117            kernel {
118                parameters: <V: ValueCast<Bool> + BareValueDomain>;
119                selector: Bool;
120                input: Bare<V>;
121                output: Bare<V>;
122                emission: Preserving;
123            }
124        }
125    }
126}
127
128pub(super) mod date_time {
129    use super::{Bare, Cast, CastOperation, DateTime, Indexed, Preserving, operation_manifest};
130
131    operation_manifest! {
132        CastOperation<DateTime> {
133            method: Cast<DateTime>::cast;
134            scope: element;
135
136            kernel {
137                parameters: <I: IndexDomain, V: ValueCast<DateTime>,>;
138                selector: DateTime;
139                input: Indexed<I, V>;
140                output: Indexed<I, V>;
141                emission: Preserving;
142            }
143
144            kernel {
145                parameters: <V: ValueCast<DateTime> + BareValueDomain>;
146                selector: DateTime;
147                input: Bare<V>;
148                output: Bare<V>;
149                emission: Preserving;
150            }
151        }
152    }
153}
154
155pub(super) mod duration {
156    use super::{Bare, Cast, CastOperation, Duration, Indexed, Preserving, operation_manifest};
157
158    operation_manifest! {
159        CastOperation<Duration> {
160            method: Cast<Duration>::cast;
161            scope: element;
162
163            kernel {
164                parameters: <I: IndexDomain, V: ValueCast<Duration>,>;
165                selector: Duration;
166                input: Indexed<I, V>;
167                output: Indexed<I, V>;
168                emission: Preserving;
169            }
170
171            kernel {
172                parameters: <V: ValueCast<Duration> + BareValueDomain>;
173                selector: Duration;
174                input: Bare<V>;
175                output: Bare<V>;
176                emission: Preserving;
177            }
178        }
179    }
180}
181
182pub(super) mod float {
183    use super::{Bare, Cast, CastOperation, Float, Indexed, Preserving, operation_manifest};
184
185    operation_manifest! {
186        CastOperation<Float> {
187            method: Cast<Float>::cast;
188            scope: element;
189
190            kernel {
191                parameters: <I: IndexDomain, V: ValueCast<Float>,>;
192                selector: Float;
193                input: Indexed<I, V>;
194                output: Indexed<I, V>;
195                emission: Preserving;
196            }
197
198            kernel {
199                parameters: <V: ValueCast<Float> + BareValueDomain>;
200                selector: Float;
201                input: Bare<V>;
202                output: Bare<V>;
203                emission: Preserving;
204            }
205        }
206    }
207}
208
209pub(super) mod int {
210    use super::{Bare, Cast, CastOperation, Indexed, Int, Preserving, operation_manifest};
211
212    operation_manifest! {
213        CastOperation<Int> {
214            method: Cast<Int>::cast;
215            scope: element;
216
217            kernel {
218                parameters: <I: IndexDomain, V: ValueCast<Int>,>;
219                selector: Int;
220                input: Indexed<I, V>;
221                output: Indexed<I, V>;
222                emission: Preserving;
223            }
224
225            kernel {
226                parameters: <V: ValueCast<Int> + BareValueDomain>;
227                selector: Int;
228                input: Bare<V>;
229                output: Bare<V>;
230                emission: Preserving;
231            }
232        }
233    }
234}
235
236pub(super) mod string {
237    use super::{Bare, Cast, CastOperation, Indexed, Preserving, String, operation_manifest};
238
239    operation_manifest! {
240        CastOperation<String> {
241            method: Cast<String>::cast;
242            scope: element;
243
244            kernel {
245                parameters: <I: IndexDomain, V: ValueCast<String>,>;
246                selector: String;
247                input: Indexed<I, V>;
248                output: Indexed<I, V>;
249                emission: Preserving;
250            }
251
252            kernel {
253                parameters: <V: ValueCast<String> + BareValueDomain>;
254                selector: String;
255                input: Bare<V>;
256                output: Bare<V>;
257                emission: Preserving;
258            }
259        }
260    }
261}