use std::any::TypeId;
use std::cmp::{max, min};
use crate::func::def::{FunctionDef, ParameterBindingProvider, Parameters};
use crate::func::utils::{doubles_poison_and, pls_min_dec, pls_min_dec_merge};
use crate::operator::Operator;
use crate::types::decimal_type::Decimal;
use crate::types::matcher::NumericMatcher;
use crate::types::Type;
#[derive(Default, Clone)]
pub struct NumericPlus;
impl FunctionDef for NumericPlus {
fn name(&self) -> &'static str {
Operator::Plus.str()
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("left", NumericMatcher::default())
.with("right", NumericMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
doubles_poison_and(pls_min_dec, pls_min_dec_merge)(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct NumericMinus;
impl FunctionDef for NumericMinus {
fn name(&self) -> &'static str {
Operator::Minus.str()
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("left", NumericMatcher::default())
.with("right", NumericMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
doubles_poison_and(pls_min_dec, pls_min_dec_merge)(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct NumericMultiply;
impl FunctionDef for NumericMultiply {
fn name(&self) -> &'static str {
Operator::Asterisk.str()
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("left", NumericMatcher::default())
.with("right", NumericMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
doubles_poison_and(
|dec| Decimal::new(min(dec.precision + 10, 38), dec.scale),
|left, right| {
Decimal::new(
min(38, left.precision + right.precision),
left.scale + right.scale,
)
},
)(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct NumericDivide;
impl FunctionDef for NumericDivide {
fn name(&self) -> &'static str {
Operator::Slash.str()
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("left", NumericMatcher::default())
.with("right", NumericMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
doubles_poison_and(
|dec| Ok(dec.clone()),
|left, right| {
Decimal::new(
min(
38,
left.precision + right.scale - left.scale
+ max(0, right.scale - left.scale),
),
max(left.scale, right.precision),
)
},
)(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}
#[derive(Default, Clone)]
pub struct NumericModulo;
impl FunctionDef for NumericModulo {
fn name(&self) -> &'static str {
Operator::Percent.str()
}
fn parameters(&self) -> Parameters {
Parameters::new()
.with("left", NumericMatcher::default())
.with("right", NumericMatcher::default())
}
fn return_type(&self, bindings: &dyn ParameterBindingProvider) -> anyhow::Result<Type> {
doubles_poison_and(
|dec| Ok(dec.clone()),
|left, right| {
Decimal::new(
min(left.precision - left.scale, right.precision - right.scale)
+ max(left.scale, right.scale),
max(left.scale, right.scale),
)
},
)(bindings)
}
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
}