reifydb_engine/expression/
convert.rs1use reifydb_core::interface::catalog::property::ColumnSaturationPolicy;
5use reifydb_type::{
6 Result,
7 error::TypeError,
8 fragment::Fragment,
9 value::{number::safe::convert::SafeConvert, r#type::get::GetType},
10};
11
12use crate::expression::context::EvalContext;
13
14pub trait Convert {
15 fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
16 where
17 From: SafeConvert<To> + GetType,
18 To: GetType;
19}
20
21impl Convert for EvalContext<'_> {
22 fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
23 where
24 From: SafeConvert<To> + GetType,
25 To: GetType,
26 {
27 Convert::convert(&self, from, fragment)
28 }
29}
30
31impl Convert for &EvalContext<'_> {
32 fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
33 where
34 From: SafeConvert<To> + GetType,
35 To: GetType,
36 {
37 let fragment = fragment.into();
38 match &self.saturation_policy() {
39 ColumnSaturationPolicy::Error => from
40 .checked_convert()
41 .ok_or_else(|| {
42 if From::get_type().is_integer() && To::get_type().is_floating_point() {
43 return TypeError::IntegerPrecisionLoss {
44 source_type: From::get_type(),
45 target: To::get_type(),
46 fragment: fragment.clone(),
47 }
48 .into();
49 };
50
51 let descriptor = self.target.as_ref().and_then(|c| c.to_number_descriptor());
52 TypeError::NumberOutOfRange {
53 target: To::get_type(),
54 fragment: fragment.clone(),
55 descriptor,
56 }
57 .into()
58 })
59 .map(Some),
60 ColumnSaturationPolicy::None => match from.checked_convert() {
61 None => Ok(None),
62 Some(value) => Ok(Some(value)),
63 },
64 }
65 }
66}