reifydb_routine/function/time/
subtract.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 TimeSubtract {
10 info: RoutineInfo,
11}
12
13impl Default for TimeSubtract {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl TimeSubtract {
20 pub fn new() -> Self {
21 Self {
22 info: RoutineInfo::new("time::subtract"),
23 }
24 }
25}
26
27const NANOS_PER_DAY: i64 = 86_400_000_000_000;
28
29impl<'a> Routine<FunctionContext<'a>> for TimeSubtract {
30 fn info(&self) -> &RoutineInfo {
31 &self.info
32 }
33
34 fn return_type(&self, _input_types: &[Type]) -> Type {
35 Type::Time
36 }
37
38 fn execute(&self, ctx: &mut FunctionContext<'a>, args: &Columns) -> Result<Columns, RoutineError> {
39 if args.len() != 2 {
40 return Err(RoutineError::FunctionArityMismatch {
41 function: ctx.fragment.clone(),
42 expected: 2,
43 actual: args.len(),
44 });
45 }
46
47 let time_col = &args[0];
48 let dur_col = &args[1];
49
50 let (time_data, time_bv) = time_col.unwrap_option();
51 let (dur_data, dur_bv) = dur_col.unwrap_option();
52
53 match (time_data, dur_data) {
54 (ColumnBuffer::Time(time_container), ColumnBuffer::Duration(dur_container)) => {
55 let row_count = time_data.len();
56 let mut container = TemporalContainer::with_capacity(row_count);
57
58 for i in 0..row_count {
59 match (time_container.get(i), dur_container.get(i)) {
60 (Some(time), Some(dur)) => {
61 let time_nanos = time.to_nanos_since_midnight() as i64;
62 let dur_nanos =
63 dur.get_nanos() + dur.get_days() as i64 * NANOS_PER_DAY;
64
65 let result_nanos =
66 (time_nanos - dur_nanos).rem_euclid(NANOS_PER_DAY);
67 match Time::from_nanos_since_midnight(result_nanos as u64) {
68 Some(result) => container.push(result),
69 None => container.push_default(),
70 }
71 }
72 _ => container.push_default(),
73 }
74 }
75
76 let mut result_data = ColumnBuffer::Time(container);
77 if let Some(bv) = time_bv {
78 result_data = ColumnBuffer::Option {
79 inner: Box::new(result_data),
80 bitvec: bv.clone(),
81 };
82 } else if let Some(bv) = dur_bv {
83 result_data = ColumnBuffer::Option {
84 inner: Box::new(result_data),
85 bitvec: bv.clone(),
86 };
87 }
88 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), result_data)]))
89 }
90 (ColumnBuffer::Time(_), other) => Err(RoutineError::FunctionInvalidArgumentType {
91 function: ctx.fragment.clone(),
92 argument_index: 1,
93 expected: vec![Type::Duration],
94 actual: other.get_type(),
95 }),
96 (other, _) => Err(RoutineError::FunctionInvalidArgumentType {
97 function: ctx.fragment.clone(),
98 argument_index: 0,
99 expected: vec![Type::Time],
100 actual: other.get_type(),
101 }),
102 }
103 }
104}
105
106impl Function for TimeSubtract {
107 fn kinds(&self) -> &[FunctionKind] {
108 &[FunctionKind::Scalar]
109 }
110}