reifydb-engine 0.4.12

Query execution and processing engine for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 ReifyDB

use reifydb_core::interface::catalog::property::ColumnSaturationStrategy;
use reifydb_type::{
	Result,
	error::TypeError,
	fragment::Fragment,
	value::{number::safe::convert::SafeConvert, r#type::get::GetType},
};

use crate::expression::context::EvalContext;

pub trait Convert {
	fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
	where
		From: SafeConvert<To> + GetType,
		To: GetType;
}

impl Convert for EvalContext<'_> {
	fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
	where
		From: SafeConvert<To> + GetType,
		To: GetType,
	{
		Convert::convert(&self, from, fragment)
	}
}

impl Convert for &EvalContext<'_> {
	fn convert<From, To>(&self, from: From, fragment: impl Into<Fragment>) -> Result<Option<To>>
	where
		From: SafeConvert<To> + GetType,
		To: GetType,
	{
		let fragment = fragment.into();
		match &self.saturation_policy() {
			ColumnSaturationStrategy::Error => from
				.checked_convert()
				.ok_or_else(|| {
					if From::get_type().is_integer() && To::get_type().is_floating_point() {
						return TypeError::IntegerPrecisionLoss {
							shape_type: From::get_type(),
							target: To::get_type(),
							fragment: fragment.clone(),
						}
						.into();
					};

					let descriptor = self.target.as_ref().and_then(|c| c.to_number_descriptor());
					TypeError::NumberOutOfRange {
						target: To::get_type(),
						fragment: fragment.clone(),
						descriptor,
					}
					.into()
				})
				.map(Some),
			ColumnSaturationStrategy::None => match from.checked_convert() {
				None => Ok(None),
				Some(value) => Ok(Some(value)),
			},
		}
	}
}