reifydb_routine/function/math/
truncate.rs1use num_traits::ToPrimitive;
5use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer, columns::Columns};
6use reifydb_type::value::{
7 container::number::NumberContainer,
8 decimal::Decimal,
9 r#type::{Type, input_types::InputTypes},
10};
11
12use crate::routine::{Function, FunctionKind, Routine, RoutineInfo, context::FunctionContext, error::RoutineError};
13
14pub struct Truncate {
15 info: RoutineInfo,
16}
17
18impl Default for Truncate {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl Truncate {
25 pub fn new() -> Self {
26 Self {
27 info: RoutineInfo::new("math::truncate"),
28 }
29 }
30}
31
32impl<'a> Routine<FunctionContext<'a>> for Truncate {
33 fn info(&self) -> &RoutineInfo {
34 &self.info
35 }
36
37 fn return_type(&self, input_types: &[Type]) -> Type {
38 input_types.first().cloned().unwrap_or(Type::Float8)
39 }
40
41 fn execute(&self, ctx: &mut FunctionContext<'a>, args: &Columns) -> Result<Columns, RoutineError> {
42 if args.len() != 1 {
43 return Err(RoutineError::FunctionArityMismatch {
44 function: ctx.fragment.clone(),
45 expected: 1,
46 actual: args.len(),
47 });
48 }
49
50 let column = &args[0];
51 let (data, bitvec) = column.unwrap_option();
52 let row_count = data.len();
53
54 let result_data = match data {
55 ColumnBuffer::Float4(container) => {
56 let mut data = Vec::with_capacity(row_count);
57 let mut res_bitvec = Vec::with_capacity(row_count);
58 for i in 0..row_count {
59 if let Some(&value) = container.get(i) {
60 data.push(value.trunc());
61 res_bitvec.push(true);
62 } else {
63 data.push(0.0);
64 res_bitvec.push(false);
65 }
66 }
67 ColumnBuffer::float4_with_bitvec(data, res_bitvec)
68 }
69 ColumnBuffer::Float8(container) => {
70 let mut data = Vec::with_capacity(row_count);
71 let mut res_bitvec = Vec::with_capacity(row_count);
72 for i in 0..row_count {
73 if let Some(&value) = container.get(i) {
74 data.push(value.trunc());
75 res_bitvec.push(true);
76 } else {
77 data.push(0.0);
78 res_bitvec.push(false);
79 }
80 }
81 ColumnBuffer::float8_with_bitvec(data, res_bitvec)
82 }
83 ColumnBuffer::Decimal {
84 container,
85 precision,
86 scale,
87 } => {
88 let mut data = Vec::with_capacity(row_count);
89 for i in 0..row_count {
90 if let Some(value) = container.get(i) {
91 let f = value.0.to_f64().unwrap_or(0.0);
92 data.push(Decimal::from(f.trunc()));
93 } else {
94 data.push(Decimal::default());
95 }
96 }
97 ColumnBuffer::Decimal {
98 container: NumberContainer::new(data),
99 precision: *precision,
100 scale: *scale,
101 }
102 }
103 other if other.get_type().is_number() => data.clone(),
104 other => {
105 return Err(RoutineError::FunctionInvalidArgumentType {
106 function: ctx.fragment.clone(),
107 argument_index: 0,
108 expected: InputTypes::numeric().expected_at(0).to_vec(),
109 actual: other.get_type(),
110 });
111 }
112 };
113
114 let final_data = if let Some(bv) = bitvec {
115 ColumnBuffer::Option {
116 inner: Box::new(result_data),
117 bitvec: bv.clone(),
118 }
119 } else {
120 result_data
121 };
122
123 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), final_data)]))
124 }
125}
126
127impl Function for Truncate {
128 fn kinds(&self) -> &[FunctionKind] {
129 &[FunctionKind::Scalar]
130 }
131}