reifydb_routine/function/text/
repeat.rs1use reifydb_core::value::column::{ColumnWithName, buffer::ColumnBuffer, columns::Columns};
5use reifydb_type::value::{constraint::bytes::MaxBytes, container::utf8::Utf8Container, r#type::Type};
6
7use crate::routine::{Function, FunctionKind, Routine, RoutineInfo, context::FunctionContext, error::RoutineError};
8
9pub struct TextRepeat {
10 info: RoutineInfo,
11}
12
13impl Default for TextRepeat {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl TextRepeat {
20 pub fn new() -> Self {
21 Self {
22 info: RoutineInfo::new("text::repeat"),
23 }
24 }
25}
26
27impl<'a> Routine<FunctionContext<'a>> for TextRepeat {
28 fn info(&self) -> &RoutineInfo {
29 &self.info
30 }
31
32 fn return_type(&self, _input_types: &[Type]) -> Type {
33 Type::Utf8
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 str_col = &args[0];
46 let count_col = &args[1];
47
48 let (str_data, str_bv) = str_col.unwrap_option();
49 let (count_data, count_bv) = count_col.unwrap_option();
50 let row_count = str_data.len();
51
52 match str_data {
53 ColumnBuffer::Utf8 {
54 container: str_container,
55 ..
56 } => {
57 let mut result_data = Vec::with_capacity(row_count);
58
59 for i in 0..row_count {
60 if !str_container.is_defined(i) {
61 result_data.push(String::new());
62 continue;
63 }
64
65 let count = match count_data {
66 ColumnBuffer::Int1(c) => c.get(i).map(|&v| v as i64),
67 ColumnBuffer::Int2(c) => c.get(i).map(|&v| v as i64),
68 ColumnBuffer::Int4(c) => c.get(i).map(|&v| v as i64),
69 ColumnBuffer::Int8(c) => c.get(i).copied(),
70 ColumnBuffer::Uint1(c) => c.get(i).map(|&v| v as i64),
71 ColumnBuffer::Uint2(c) => c.get(i).map(|&v| v as i64),
72 ColumnBuffer::Uint4(c) => c.get(i).map(|&v| v as i64),
73 _ => {
74 return Err(RoutineError::FunctionInvalidArgumentType {
75 function: ctx.fragment.clone(),
76 argument_index: 1,
77 expected: vec![
78 Type::Int1,
79 Type::Int2,
80 Type::Int4,
81 Type::Int8,
82 ],
83 actual: count_data.get_type(),
84 });
85 }
86 };
87
88 match count {
89 Some(n) if n >= 0 => {
90 let s = str_container.get(i).unwrap();
91 result_data.push(s.repeat(n as usize));
92 }
93 Some(_) => {
94 result_data.push(String::new());
95 }
96 None => {
97 result_data.push(String::new());
98 }
99 }
100 }
101
102 let result_col_data = ColumnBuffer::Utf8 {
103 container: Utf8Container::new(result_data),
104 max_bytes: MaxBytes::MAX,
105 };
106
107 let combined_bv = match (str_bv, count_bv) {
108 (Some(b), Some(e)) => Some(b.and(e)),
109 (Some(b), None) => Some(b.clone()),
110 (None, Some(e)) => Some(e.clone()),
111 (None, None) => None,
112 };
113
114 let final_data = match combined_bv {
115 Some(bv) => ColumnBuffer::Option {
116 inner: Box::new(result_col_data),
117 bitvec: bv,
118 },
119 None => result_col_data,
120 };
121 Ok(Columns::new(vec![ColumnWithName::new(ctx.fragment.clone(), final_data)]))
122 }
123 other => Err(RoutineError::FunctionInvalidArgumentType {
124 function: ctx.fragment.clone(),
125 argument_index: 0,
126 expected: vec![Type::Utf8],
127 actual: other.get_type(),
128 }),
129 }
130 }
131}
132
133impl Function for TextRepeat {
134 fn kinds(&self) -> &[FunctionKind] {
135 &[FunctionKind::Scalar]
136 }
137}