reifydb_routine/function/time/
trunc.rs1use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer, columns::Columns};
5use reifydb_type::value::{container::temporal::TemporalContainer, time::Time, r#type::Type};
6
7use crate::routine::{Function, FunctionKind, Routine, RoutineInfo, context::FunctionContext, error::RoutineError};
8
9pub struct TimeTrunc {
10 info: RoutineInfo,
11}
12
13impl Default for TimeTrunc {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl TimeTrunc {
20 pub fn new() -> Self {
21 Self {
22 info: RoutineInfo::new("time::trunc"),
23 }
24 }
25}
26
27impl<'a> Routine<FunctionContext<'a>> for TimeTrunc {
28 fn info(&self) -> &RoutineInfo {
29 &self.info
30 }
31
32 fn return_type(&self, _input_types: &[Type]) -> Type {
33 Type::Time
34 }
35
36 fn execute(&self, ctx: &mut FunctionContext<'a>, args: &Columns) -> Result<Columns, RoutineError> {
37 if args.len() != 2 {
38 return Err(RoutineError::FunctionArityMismatch {
39 function: ctx.fragment.clone(),
40 expected: 2,
41 actual: args.len(),
42 });
43 }
44
45 let time_col = &args[0];
46 let prec_col = &args[1];
47
48 let (time_data, time_bv) = time_col.unwrap_option();
49 let (prec_data, _) = prec_col.unwrap_option();
50
51 match (time_data, prec_data) {
52 (
53 ColumnBuffer::Time(time_container),
54 ColumnBuffer::Utf8 {
55 container: prec_container,
56 ..
57 },
58 ) => {
59 let row_count = time_data.len();
60 let mut container = TemporalContainer::with_capacity(row_count);
61
62 for i in 0..row_count {
63 match (time_container.get(i), prec_container.is_defined(i)) {
64 (Some(t), true) => {
65 let precision = prec_container.get(i).unwrap();
66 let truncated = match precision {
67 "hour" => Time::new(t.hour(), 0, 0, 0),
68 "minute" => Time::new(t.hour(), t.minute(), 0, 0),
69 "second" => {
70 Time::new(t.hour(), t.minute(), t.second(), 0)
71 }
72 other => {
73 return Err(
74 RoutineError::FunctionExecutionFailed {
75 function: ctx.fragment.clone(),
76 reason: format!(
77 "invalid precision: '{}'",
78 other
79 ),
80 },
81 );
82 }
83 };
84 match truncated {
85 Some(val) => container.push(val),
86 None => container.push_default(),
87 }
88 }
89 _ => container.push_default(),
90 }
91 }
92
93 let mut result_data = ColumnBuffer::Time(container);
94 if let Some(bv) = time_bv {
95 result_data = ColumnBuffer::Option {
96 inner: Box::new(result_data),
97 bitvec: bv.clone(),
98 };
99 }
100 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), result_data)]))
101 }
102 (ColumnBuffer::Time(_), other) => Err(RoutineError::FunctionInvalidArgumentType {
103 function: ctx.fragment.clone(),
104 argument_index: 1,
105 expected: vec![Type::Utf8],
106 actual: other.get_type(),
107 }),
108 (other, _) => Err(RoutineError::FunctionInvalidArgumentType {
109 function: ctx.fragment.clone(),
110 argument_index: 0,
111 expected: vec![Type::Time],
112 actual: other.get_type(),
113 }),
114 }
115 }
116}
117
118impl Function for TimeTrunc {
119 fn kinds(&self) -> &[FunctionKind] {
120 &[FunctionKind::Scalar]
121 }
122}