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