Skip to main content

reifydb_engine/expression/
convert.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::interface::catalog::policy::ColumnSaturationPolicy;
5use reifydb_type::{
6	error,
7	error::diagnostic::number::{integer_precision_loss, number_out_of_range},
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>) -> reifydb_type::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>) -> reifydb_type::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>) -> reifydb_type::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 error!(integer_precision_loss(
44							fragment.clone(),
45							From::get_type(),
46							To::get_type(),
47						));
48					};
49
50					let descriptor = self.target.as_ref().and_then(|c| c.to_number_descriptor());
51					return error!(number_out_of_range(
52						fragment.clone(),
53						To::get_type(),
54						descriptor.as_ref(),
55					));
56				})
57				.map(Some),
58			ColumnSaturationPolicy::None => match from.checked_convert() {
59				None => Ok(None),
60				Some(value) => Ok(Some(value)),
61			},
62		}
63	}
64}