Skip to main content

reifydb_routine/function/math/
ceil.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use 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 Ceil {
15	info: RoutineInfo,
16}
17
18impl Default for Ceil {
19	fn default() -> Self {
20		Self::new()
21	}
22}
23
24impl Ceil {
25	pub fn new() -> Self {
26		Self {
27			info: RoutineInfo::new("math::ceil"),
28		}
29	}
30}
31
32impl<'a> Routine<FunctionContext<'a>> for Ceil {
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.ceil());
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.ceil());
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.ceil()));
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 Ceil {
128	fn kinds(&self) -> &[FunctionKind] {
129		&[FunctionKind::Scalar]
130	}
131}