1use reifydb_core::{
5 error::CoreError,
6 value::column::{ColumnWithName, buffer::ColumnBuffer},
7};
8use reifydb_rql::expression::PrefixOperator;
9use reifydb_value::{
10 error::{LogicalOp, OperandCategory, TypeError},
11 fragment::Fragment,
12 value::{decimal::Decimal, int::Int, uint::Uint},
13};
14
15use crate::{Result, expression::option::unary_op_unwrap_option};
16
17macro_rules! prefix_signed_int {
18 ($column:expr, $container:expr, $operator:expr, $fragment:expr, $variant:ident) => {{
19 let mut result = Vec::with_capacity($container.data().len());
20 for (idx, val) in $container.data().iter().enumerate() {
21 if $container.is_defined(idx) {
22 result.push(match $operator {
23 PrefixOperator::Minus(_) => -*val,
24 PrefixOperator::Plus(_) => *val,
25 PrefixOperator::Not(_) => {
26 return Err(TypeError::LogicalOperatorNotApplicable {
27 operator: LogicalOp::Not,
28 operand_category: OperandCategory::Number,
29 fragment: $fragment,
30 }
31 .into());
32 }
33 });
34 } else {
35 result.push(0);
36 }
37 }
38 let new_data = ColumnBuffer::$variant(result);
39 Ok($column.with_new_data(new_data))
40 }};
41}
42
43macro_rules! prefix_unsigned_int {
44 ($column:expr, $container:expr, $operator:expr, $fragment:expr, $signed_ty:ty, $constructor:ident) => {{
45 let mut result = Vec::with_capacity($container.data().len());
46 for val in $container.data().iter() {
47 let signed = *val as $signed_ty;
48 result.push(match $operator {
49 PrefixOperator::Minus(_) => -signed,
50 PrefixOperator::Plus(_) => signed,
51 PrefixOperator::Not(_) => {
52 return Err(TypeError::LogicalOperatorNotApplicable {
53 operator: LogicalOp::Not,
54 operand_category: OperandCategory::Number,
55 fragment: $fragment,
56 }
57 .into());
58 }
59 });
60 }
61 let new_data = ColumnBuffer::$constructor(result);
62 Ok($column.with_new_data(new_data))
63 }};
64}
65
66macro_rules! prefix_float {
67 ($column:expr, $container:expr, $operator:expr, $fragment:expr, $zero:expr, $constructor:ident) => {{
68 let mut result = Vec::with_capacity($container.data().len());
69 for (idx, val) in $container.data().iter().enumerate() {
70 if $container.is_defined(idx) {
71 result.push(match $operator {
72 PrefixOperator::Minus(_) => -*val,
73 PrefixOperator::Plus(_) => *val,
74 PrefixOperator::Not(_) => {
75 return Err(TypeError::LogicalOperatorNotApplicable {
76 operator: LogicalOp::Not,
77 operand_category: OperandCategory::Number,
78 fragment: $fragment,
79 }
80 .into());
81 }
82 });
83 } else {
84 result.push($zero);
85 }
86 }
87 let new_data = ColumnBuffer::$constructor(result);
88 Ok($column.with_new_data(new_data))
89 }};
90}
91
92macro_rules! prefix_not_error {
93 ($operator:expr, $fragment:expr, $category:expr) => {
94 match $operator {
95 PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
96 operator: LogicalOp::Not,
97 operand_category: $category,
98 fragment: $fragment,
99 }
100 .into()),
101 _ => unimplemented!(),
102 }
103 };
104}
105
106pub fn prefix_apply(column: &ColumnWithName, operator: &PrefixOperator, fragment: &Fragment) -> Result<ColumnWithName> {
107 unary_op_unwrap_option(column, |column| match column.data() {
108 ColumnBuffer::Bool(container) => match operator {
109 PrefixOperator::Not(_) => {
110 let mut result = Vec::with_capacity(container.data().len());
111 for (idx, val) in container.data().iter().enumerate() {
112 if container.is_defined(idx) {
113 result.push(!val);
114 } else {
115 result.push(false);
116 }
117 }
118
119 let new_data = ColumnBuffer::bool(result);
120 Ok(column.with_new_data(new_data))
121 }
122 _ => Err(CoreError::FrameError {
123 message: "Cannot apply arithmetic prefix operator to bool".to_string(),
124 }
125 .into()),
126 },
127
128 ColumnBuffer::Float4(container) => {
129 prefix_float!(column, container, operator, fragment.clone(), 0.0f32, float4)
130 }
131
132 ColumnBuffer::Float8(container) => {
133 prefix_float!(column, container, operator, fragment.clone(), 0.0f64, float8)
134 }
135
136 ColumnBuffer::Int1(container) => {
137 prefix_signed_int!(column, container, operator, fragment.clone(), int1)
138 }
139
140 ColumnBuffer::Int2(container) => {
141 prefix_signed_int!(column, container, operator, fragment.clone(), int2)
142 }
143
144 ColumnBuffer::Int4(container) => {
145 prefix_signed_int!(column, container, operator, fragment.clone(), int4)
146 }
147
148 ColumnBuffer::Int8(container) => {
149 prefix_signed_int!(column, container, operator, fragment.clone(), int8)
150 }
151
152 ColumnBuffer::Int16(container) => {
153 prefix_signed_int!(column, container, operator, fragment.clone(), int16)
154 }
155
156 ColumnBuffer::Utf8 {
157 container: _,
158 ..
159 } => match operator {
160 PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
161 operator: LogicalOp::Not,
162 operand_category: OperandCategory::Text,
163 fragment: fragment.clone(),
164 }
165 .into()),
166 _ => Err(CoreError::FrameError {
167 message: "Cannot apply arithmetic prefix operator to text".to_string(),
168 }
169 .into()),
170 },
171
172 ColumnBuffer::Uint1(container) => {
173 prefix_unsigned_int!(column, container, operator, fragment.clone(), i8, int1)
174 }
175
176 ColumnBuffer::Uint2(container) => {
177 prefix_unsigned_int!(column, container, operator, fragment.clone(), i16, int2)
178 }
179
180 ColumnBuffer::Uint4(container) => {
181 prefix_unsigned_int!(column, container, operator, fragment.clone(), i32, int4)
182 }
183
184 ColumnBuffer::Uint8(container) => {
185 prefix_unsigned_int!(column, container, operator, fragment.clone(), i64, int8)
186 }
187
188 ColumnBuffer::Uint16(container) => {
189 prefix_unsigned_int!(column, container, operator, fragment.clone(), i128, int16)
190 }
191
192 ColumnBuffer::Date(_) => {
193 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
194 }
195 ColumnBuffer::DateTime(_) => {
196 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
197 }
198 ColumnBuffer::Time(_) => {
199 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
200 }
201 ColumnBuffer::Duration(_) => {
202 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
203 }
204 ColumnBuffer::IdentityId(_) => {
205 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
206 }
207 ColumnBuffer::Uuid4(_) => {
208 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
209 }
210 ColumnBuffer::Uuid7(_) => {
211 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
212 }
213
214 ColumnBuffer::Blob {
215 container: _,
216 ..
217 } => match operator {
218 PrefixOperator::Not(_) => Err(CoreError::FrameError {
219 message: "Cannot apply NOT operator to BLOB".to_string(),
220 }
221 .into()),
222 _ => Err(CoreError::FrameError {
223 message: "Cannot apply arithmetic prefix operator to BLOB".to_string(),
224 }
225 .into()),
226 },
227 ColumnBuffer::Int {
228 container,
229 ..
230 } => {
231 let mut result = Vec::with_capacity(container.data().len());
232 for (idx, val) in container.data().iter().enumerate() {
233 if container.is_defined(idx) {
234 result.push(match operator {
235 PrefixOperator::Minus(_) => Int(-val.0.clone()),
236 PrefixOperator::Plus(_) => val.clone(),
237 PrefixOperator::Not(_) => {
238 return Err(TypeError::LogicalOperatorNotApplicable {
239 operator: LogicalOp::Not,
240 operand_category: OperandCategory::Number,
241 fragment: fragment.clone(),
242 }
243 .into());
244 }
245 });
246 } else {
247 result.push(Int::zero());
248 }
249 }
250 let new_data = ColumnBuffer::int(result);
251 Ok(column.with_new_data(new_data))
252 }
253 ColumnBuffer::Uint {
254 container,
255 ..
256 } => match operator {
257 PrefixOperator::Minus(_) => {
258 let mut result = Vec::with_capacity(container.data().len());
259 for (idx, val) in container.data().iter().enumerate() {
260 if container.is_defined(idx) {
261 let negated = -val.0.clone();
262 result.push(Int::from(negated));
263 } else {
264 result.push(Int::zero());
265 }
266 }
267 let new_data = ColumnBuffer::int(result);
268 Ok(column.with_new_data(new_data))
269 }
270 PrefixOperator::Plus(_) => {
271 let mut result = Vec::with_capacity(container.data().len());
272 for (idx, val) in container.data().iter().enumerate() {
273 if container.is_defined(idx) {
274 result.push(val.clone());
275 } else {
276 result.push(Uint::zero());
277 }
278 }
279 let new_data = ColumnBuffer::uint(result);
280 Ok(column.with_new_data(new_data))
281 }
282 PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
283 operator: LogicalOp::Not,
284 operand_category: OperandCategory::Number,
285 fragment: fragment.clone(),
286 }
287 .into()),
288 },
289 ColumnBuffer::Decimal {
290 container,
291 ..
292 } => {
293 let mut result = Vec::with_capacity(container.data().len());
294 for (idx, val) in container.data().iter().enumerate() {
295 if container.is_defined(idx) {
296 result.push(match operator {
297 PrefixOperator::Minus(_) => val.clone().negate(),
298 PrefixOperator::Plus(_) => val.clone(),
299 PrefixOperator::Not(_) => {
300 return Err(TypeError::LogicalOperatorNotApplicable {
301 operator: LogicalOp::Not,
302 operand_category: OperandCategory::Number,
303 fragment: fragment.clone(),
304 }
305 .into());
306 }
307 });
308 } else {
309 result.push(Decimal::from(0));
310 }
311 }
312 let new_data = ColumnBuffer::decimal(result);
313 Ok(column.with_new_data(new_data))
314 }
315 ColumnBuffer::DictionaryId(_) => match operator {
316 PrefixOperator::Not(_) => Err(CoreError::FrameError {
317 message: "Cannot apply NOT operator to DictionaryId type".to_string(),
318 }
319 .into()),
320 _ => Err(CoreError::FrameError {
321 message: "Cannot apply arithmetic prefix operator to DictionaryId type".to_string(),
322 }
323 .into()),
324 },
325 ColumnBuffer::Any(_) => match operator {
326 PrefixOperator::Not(_) => Err(CoreError::FrameError {
327 message: "Cannot apply NOT operator to Any type".to_string(),
328 }
329 .into()),
330 _ => Err(CoreError::FrameError {
331 message: "Cannot apply arithmetic prefix operator to Any type".to_string(),
332 }
333 .into()),
334 },
335 ColumnBuffer::Option {
336 ..
337 } => unreachable!("nested Option after unwrap"),
338 })
339}