reifydb_function/duration/
days.rs1use reifydb_core::value::column::data::ColumnData;
5use reifydb_type::value::{container::temporal::TemporalContainer, duration::Duration, r#type::Type};
6
7use crate::{ScalarFunction, ScalarFunctionContext, error::ScalarFunctionError, propagate_options};
8
9pub struct DurationDays;
10
11impl DurationDays {
12 pub fn new() -> Self {
13 Self
14 }
15}
16
17fn extract_i64(data: &ColumnData, i: usize) -> Option<i64> {
18 match data {
19 ColumnData::Int1(c) => c.get(i).map(|&v| v as i64),
20 ColumnData::Int2(c) => c.get(i).map(|&v| v as i64),
21 ColumnData::Int4(c) => c.get(i).map(|&v| v as i64),
22 ColumnData::Int8(c) => c.get(i).copied(),
23 ColumnData::Int16(c) => c.get(i).map(|&v| v as i64),
24 ColumnData::Uint1(c) => c.get(i).map(|&v| v as i64),
25 ColumnData::Uint2(c) => c.get(i).map(|&v| v as i64),
26 ColumnData::Uint4(c) => c.get(i).map(|&v| v as i64),
27 ColumnData::Uint8(c) => c.get(i).map(|&v| v as i64),
28 ColumnData::Uint16(c) => c.get(i).map(|&v| v as i64),
29 _ => None,
30 }
31}
32
33fn is_integer_type(data: &ColumnData) -> bool {
34 matches!(
35 data,
36 ColumnData::Int1(_)
37 | ColumnData::Int2(_) | ColumnData::Int4(_)
38 | ColumnData::Int8(_) | ColumnData::Int16(_)
39 | ColumnData::Uint1(_)
40 | ColumnData::Uint2(_)
41 | ColumnData::Uint4(_)
42 | ColumnData::Uint8(_)
43 | ColumnData::Uint16(_)
44 )
45}
46
47impl ScalarFunction for DurationDays {
48 fn scalar(&self, ctx: ScalarFunctionContext) -> crate::error::ScalarFunctionResult<ColumnData> {
49 if let Some(result) = propagate_options(self, &ctx) {
50 return result;
51 }
52 let columns = ctx.columns;
53 let row_count = ctx.row_count;
54
55 if columns.len() != 1 {
56 return Err(ScalarFunctionError::ArityMismatch {
57 function: ctx.fragment.clone(),
58 expected: 1,
59 actual: columns.len(),
60 });
61 }
62
63 let col = columns.get(0).unwrap();
64
65 if !is_integer_type(col.data()) {
66 return Err(ScalarFunctionError::InvalidArgumentType {
67 function: ctx.fragment.clone(),
68 argument_index: 0,
69 expected: vec![
70 Type::Int1,
71 Type::Int2,
72 Type::Int4,
73 Type::Int8,
74 Type::Int16,
75 Type::Uint1,
76 Type::Uint2,
77 Type::Uint4,
78 Type::Uint8,
79 Type::Uint16,
80 ],
81 actual: col.data().get_type(),
82 });
83 }
84
85 let mut container = TemporalContainer::with_capacity(row_count);
86
87 for i in 0..row_count {
88 if let Some(val) = extract_i64(col.data(), i) {
89 container.push(Duration::from_days(val));
90 } else {
91 container.push_default();
92 }
93 }
94
95 Ok(ColumnData::Duration(container))
96 }
97
98 fn return_type(&self, _input_types: &[Type]) -> Type {
99 Type::Duration
100 }
101}