Skip to main content

reifydb_engine/expression/
prefix.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::{
5	error::CoreError,
6	value::column::{Column, data::ColumnData},
7};
8use reifydb_function::registry::Functions;
9use reifydb_rql::expression::{PrefixExpression, PrefixOperator};
10use reifydb_runtime::clock::Clock;
11use reifydb_type::{
12	error::{LogicalOp, OperandCategory, TypeError},
13	value::{decimal::Decimal, int::Int, uint::Uint},
14};
15
16use super::eval::evaluate;
17use crate::{
18	Result,
19	expression::{context::EvalContext, option::unary_op_unwrap_option},
20};
21
22pub(crate) fn prefix_eval(
23	ctx: &EvalContext,
24	prefix: &PrefixExpression,
25	functions: &Functions,
26	clock: &Clock,
27) -> Result<Column> {
28	let inner_ctx = EvalContext {
29		target: None,
30		columns: ctx.columns.clone(),
31		row_count: ctx.row_count,
32		take: ctx.take,
33		params: ctx.params,
34		symbol_table: ctx.symbol_table,
35		is_aggregate_context: ctx.is_aggregate_context,
36		functions: ctx.functions,
37		clock: ctx.clock,
38		arena: None,
39		identity: ctx.identity,
40	};
41	let column = evaluate(&inner_ctx, &prefix.expression, functions, clock)?;
42
43	unary_op_unwrap_option(&column, |column| match column.data() {
44		ColumnData::Bool(container) => match prefix.operator {
45			PrefixOperator::Not(_) => {
46				let mut result = Vec::with_capacity(container.data().len());
47				for (idx, val) in container.data().iter().enumerate() {
48					if container.is_defined(idx) {
49						result.push(!val);
50					} else {
51						result.push(false);
52					}
53				}
54
55				let new_data = ColumnData::bool(result);
56				Ok(column.with_new_data(new_data))
57			}
58			_ => Err(CoreError::FrameError {
59				message: "Cannot apply arithmetic prefix operator to bool".to_string(),
60			}
61			.into()),
62		},
63
64		ColumnData::Float4(container) => {
65			let mut result = Vec::with_capacity(container.data().len());
66			for (idx, val) in container.data().iter().enumerate() {
67				if container.is_defined(idx) {
68					result.push(match prefix.operator {
69						PrefixOperator::Minus(_) => -*val,
70						PrefixOperator::Plus(_) => *val,
71						PrefixOperator::Not(_) => {
72							return Err(TypeError::LogicalOperatorNotApplicable {
73								operator: LogicalOp::Not,
74								operand_category: OperandCategory::Number,
75								fragment: prefix.full_fragment_owned(),
76							}
77							.into());
78						}
79					});
80				} else {
81					result.push(0.0f32);
82				}
83			}
84			let new_data = ColumnData::float4(result);
85			Ok(column.with_new_data(new_data))
86		}
87
88		ColumnData::Float8(container) => {
89			let mut result = Vec::with_capacity(container.data().len());
90			for (idx, val) in container.data().iter().enumerate() {
91				if container.is_defined(idx) {
92					result.push(match prefix.operator {
93						PrefixOperator::Minus(_) => -*val,
94						PrefixOperator::Plus(_) => *val,
95						PrefixOperator::Not(_) => {
96							return Err(TypeError::LogicalOperatorNotApplicable {
97								operator: LogicalOp::Not,
98								operand_category: OperandCategory::Number,
99								fragment: prefix.full_fragment_owned(),
100							}
101							.into());
102						}
103					});
104				} else {
105					result.push(0.0f64);
106				}
107			}
108			let new_data = ColumnData::float8(result);
109			Ok(column.with_new_data(new_data))
110		}
111
112		ColumnData::Int1(container) => {
113			let mut result = Vec::with_capacity(container.data().len());
114			for (idx, val) in container.data().iter().enumerate() {
115				if container.is_defined(idx) {
116					result.push(match prefix.operator {
117						PrefixOperator::Minus(_) => -*val,
118						PrefixOperator::Plus(_) => *val,
119						PrefixOperator::Not(_) => {
120							return Err(TypeError::LogicalOperatorNotApplicable {
121								operator: LogicalOp::Not,
122								operand_category: OperandCategory::Number,
123								fragment: prefix.full_fragment_owned(),
124							}
125							.into());
126						}
127					});
128				} else {
129					result.push(0);
130				}
131			}
132			let new_data = ColumnData::int1(result);
133			Ok(column.with_new_data(new_data))
134		}
135
136		ColumnData::Int2(container) => {
137			let mut result = Vec::with_capacity(container.data().len());
138			for (idx, val) in container.data().iter().enumerate() {
139				if container.is_defined(idx) {
140					result.push(match prefix.operator {
141						PrefixOperator::Minus(_) => -*val,
142						PrefixOperator::Plus(_) => *val,
143						PrefixOperator::Not(_) => {
144							return Err(TypeError::LogicalOperatorNotApplicable {
145								operator: LogicalOp::Not,
146								operand_category: OperandCategory::Number,
147								fragment: prefix.full_fragment_owned(),
148							}
149							.into());
150						}
151					});
152				} else {
153					result.push(0);
154				}
155			}
156			let new_data = ColumnData::int2(result);
157			Ok(column.with_new_data(new_data))
158		}
159
160		ColumnData::Int4(container) => {
161			let mut result = Vec::with_capacity(container.data().len());
162			for (idx, val) in container.data().iter().enumerate() {
163				if container.is_defined(idx) {
164					result.push(match prefix.operator {
165						PrefixOperator::Minus(_) => -*val,
166						PrefixOperator::Plus(_) => *val,
167						PrefixOperator::Not(_) => {
168							return Err(TypeError::LogicalOperatorNotApplicable {
169								operator: LogicalOp::Not,
170								operand_category: OperandCategory::Number,
171								fragment: prefix.full_fragment_owned(),
172							}
173							.into());
174						}
175					});
176				} else {
177					result.push(0);
178				}
179			}
180			let new_data = ColumnData::int4(result);
181			Ok(column.with_new_data(new_data))
182		}
183
184		ColumnData::Int8(container) => {
185			let mut result = Vec::with_capacity(container.data().len());
186			for (idx, val) in container.data().iter().enumerate() {
187				if container.is_defined(idx) {
188					result.push(match prefix.operator {
189						PrefixOperator::Minus(_) => -*val,
190						PrefixOperator::Plus(_) => *val,
191						PrefixOperator::Not(_) => {
192							return Err(TypeError::LogicalOperatorNotApplicable {
193								operator: LogicalOp::Not,
194								operand_category: OperandCategory::Number,
195								fragment: prefix.full_fragment_owned(),
196							}
197							.into());
198						}
199					});
200				} else {
201					result.push(0);
202				}
203			}
204			let new_data = ColumnData::int8(result);
205			Ok(column.with_new_data(new_data))
206		}
207
208		ColumnData::Int16(container) => {
209			let mut result = Vec::with_capacity(container.data().len());
210			for (idx, val) in container.data().iter().enumerate() {
211				if container.is_defined(idx) {
212					result.push(match prefix.operator {
213						PrefixOperator::Minus(_) => -*val,
214						PrefixOperator::Plus(_) => *val,
215						PrefixOperator::Not(_) => {
216							return Err(TypeError::LogicalOperatorNotApplicable {
217								operator: LogicalOp::Not,
218								operand_category: OperandCategory::Number,
219								fragment: prefix.full_fragment_owned(),
220							}
221							.into());
222						}
223					});
224				} else {
225					result.push(0);
226				}
227			}
228			let new_data = ColumnData::int16(result);
229			Ok(column.with_new_data(new_data))
230		}
231
232		ColumnData::Utf8 {
233			container: _,
234			..
235		} => match prefix.operator {
236			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
237				operator: LogicalOp::Not,
238				operand_category: OperandCategory::Text,
239				fragment: prefix.full_fragment_owned(),
240			}
241			.into()),
242			_ => Err(CoreError::FrameError {
243				message: "Cannot apply arithmetic prefix operator to text".to_string(),
244			}
245			.into()),
246		},
247
248		ColumnData::Uint1(container) => {
249			let mut result = Vec::with_capacity(container.data().len());
250			for val in container.data().iter() {
251				let signed = *val as i8;
252				result.push(match prefix.operator {
253					PrefixOperator::Minus(_) => -signed,
254					PrefixOperator::Plus(_) => signed,
255					PrefixOperator::Not(_) => {
256						return Err(TypeError::LogicalOperatorNotApplicable {
257							operator: LogicalOp::Not,
258							operand_category: OperandCategory::Number,
259							fragment: prefix.full_fragment_owned(),
260						}
261						.into());
262					}
263				});
264			}
265			let new_data = ColumnData::int1(result);
266			Ok(column.with_new_data(new_data))
267		}
268
269		ColumnData::Uint2(container) => {
270			let mut result = Vec::with_capacity(container.data().len());
271			for val in container.data().iter() {
272				let signed = *val as i16;
273				result.push(match prefix.operator {
274					PrefixOperator::Minus(_) => -signed,
275					PrefixOperator::Plus(_) => signed,
276					PrefixOperator::Not(_) => {
277						return Err(TypeError::LogicalOperatorNotApplicable {
278							operator: LogicalOp::Not,
279							operand_category: OperandCategory::Number,
280							fragment: prefix.full_fragment_owned(),
281						}
282						.into());
283					}
284				});
285			}
286			let new_data = ColumnData::int2(result);
287			Ok(column.with_new_data(new_data))
288		}
289
290		ColumnData::Uint4(container) => {
291			let mut result = Vec::with_capacity(container.data().len());
292			for val in container.data().iter() {
293				let signed = *val as i32;
294				result.push(match prefix.operator {
295					PrefixOperator::Minus(_) => -signed,
296					PrefixOperator::Plus(_) => signed,
297					PrefixOperator::Not(_) => {
298						return Err(TypeError::LogicalOperatorNotApplicable {
299							operator: LogicalOp::Not,
300							operand_category: OperandCategory::Number,
301							fragment: prefix.full_fragment_owned(),
302						}
303						.into());
304					}
305				});
306			}
307			let new_data = ColumnData::int4(result);
308			Ok(column.with_new_data(new_data))
309		}
310
311		ColumnData::Uint8(container) => {
312			let mut result = Vec::with_capacity(container.data().len());
313			for val in container.data().iter() {
314				let signed = *val as i64;
315				result.push(match prefix.operator {
316					PrefixOperator::Minus(_) => -signed,
317					PrefixOperator::Plus(_) => signed,
318					PrefixOperator::Not(_) => {
319						return Err(TypeError::LogicalOperatorNotApplicable {
320							operator: LogicalOp::Not,
321							operand_category: OperandCategory::Number,
322							fragment: prefix.full_fragment_owned(),
323						}
324						.into());
325					}
326				});
327			}
328			let new_data = ColumnData::int8(result);
329			Ok(column.with_new_data(new_data))
330		}
331		ColumnData::Uint16(container) => {
332			let mut result = Vec::with_capacity(container.data().len());
333			for val in container.data().iter() {
334				let signed = *val as i128;
335				result.push(match prefix.operator {
336					PrefixOperator::Minus(_) => -signed,
337					PrefixOperator::Plus(_) => signed,
338					PrefixOperator::Not(_) => {
339						return Err(TypeError::LogicalOperatorNotApplicable {
340							operator: LogicalOp::Not,
341							operand_category: OperandCategory::Number,
342							fragment: prefix.full_fragment_owned(),
343						}
344						.into());
345					}
346				});
347			}
348			let new_data = ColumnData::int16(result);
349			Ok(column.with_new_data(new_data))
350		}
351		ColumnData::Date(_) => match prefix.operator {
352			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
353				operator: LogicalOp::Not,
354				operand_category: OperandCategory::Temporal,
355				fragment: prefix.full_fragment_owned(),
356			}
357			.into()),
358			_ => unimplemented!(),
359		},
360		ColumnData::DateTime(_) => match prefix.operator {
361			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
362				operator: LogicalOp::Not,
363				operand_category: OperandCategory::Temporal,
364				fragment: prefix.full_fragment_owned(),
365			}
366			.into()),
367			_ => unimplemented!(),
368		},
369		ColumnData::Time(_) => match prefix.operator {
370			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
371				operator: LogicalOp::Not,
372				operand_category: OperandCategory::Temporal,
373				fragment: prefix.full_fragment_owned(),
374			}
375			.into()),
376			_ => unimplemented!(),
377		},
378		ColumnData::Duration(_) => match prefix.operator {
379			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
380				operator: LogicalOp::Not,
381				operand_category: OperandCategory::Temporal,
382				fragment: prefix.full_fragment_owned(),
383			}
384			.into()),
385			_ => unimplemented!(),
386		},
387		ColumnData::IdentityId(_) => match prefix.operator {
388			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
389				operator: LogicalOp::Not,
390				operand_category: OperandCategory::Uuid,
391				fragment: prefix.full_fragment_owned(),
392			}
393			.into()),
394			_ => unimplemented!(),
395		},
396		ColumnData::Uuid4(_) => match prefix.operator {
397			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
398				operator: LogicalOp::Not,
399				operand_category: OperandCategory::Uuid,
400				fragment: prefix.full_fragment_owned(),
401			}
402			.into()),
403			_ => unimplemented!(),
404		},
405		ColumnData::Uuid7(_) => match prefix.operator {
406			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
407				operator: LogicalOp::Not,
408				operand_category: OperandCategory::Uuid,
409				fragment: prefix.full_fragment_owned(),
410			}
411			.into()),
412			_ => unimplemented!(),
413		},
414		ColumnData::Blob {
415			container: _,
416			..
417		} => match prefix.operator {
418			PrefixOperator::Not(_) => Err(CoreError::FrameError {
419				message: "Cannot apply NOT operator to BLOB".to_string(),
420			}
421			.into()),
422			_ => Err(CoreError::FrameError {
423				message: "Cannot apply arithmetic prefix operator to BLOB".to_string(),
424			}
425			.into()),
426		},
427		ColumnData::Int {
428			container,
429			..
430		} => {
431			let mut result = Vec::with_capacity(container.data().len());
432			for (idx, val) in container.data().iter().enumerate() {
433				if container.is_defined(idx) {
434					result.push(match prefix.operator {
435						PrefixOperator::Minus(_) => Int(-val.0.clone()),
436						PrefixOperator::Plus(_) => val.clone(),
437						PrefixOperator::Not(_) => {
438							return Err(TypeError::LogicalOperatorNotApplicable {
439								operator: LogicalOp::Not,
440								operand_category: OperandCategory::Number,
441								fragment: prefix.full_fragment_owned(),
442							}
443							.into());
444						}
445					});
446				} else {
447					result.push(Int::zero());
448				}
449			}
450			let new_data = ColumnData::int(result);
451			Ok(column.with_new_data(new_data))
452		}
453		ColumnData::Uint {
454			container,
455			..
456		} => match prefix.operator {
457			PrefixOperator::Minus(_) => {
458				let mut result = Vec::with_capacity(container.data().len());
459				for (idx, val) in container.data().iter().enumerate() {
460					if container.is_defined(idx) {
461						let negated = -val.0.clone();
462						result.push(Int::from(negated));
463					} else {
464						result.push(Int::zero());
465					}
466				}
467				let new_data = ColumnData::int(result);
468				Ok(column.with_new_data(new_data))
469			}
470			PrefixOperator::Plus(_) => {
471				let mut result = Vec::with_capacity(container.data().len());
472				for (idx, val) in container.data().iter().enumerate() {
473					if container.is_defined(idx) {
474						result.push(val.clone());
475					} else {
476						result.push(Uint::zero());
477					}
478				}
479				let new_data = ColumnData::uint(result);
480				Ok(column.with_new_data(new_data))
481			}
482			PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
483				operator: LogicalOp::Not,
484				operand_category: OperandCategory::Number,
485				fragment: prefix.full_fragment_owned(),
486			}
487			.into()),
488		},
489		ColumnData::Decimal {
490			container,
491			..
492		} => {
493			let mut result = Vec::with_capacity(container.data().len());
494			for (idx, val) in container.data().iter().enumerate() {
495				if container.is_defined(idx) {
496					result.push(match prefix.operator {
497						PrefixOperator::Minus(_) => val.clone().negate(),
498						PrefixOperator::Plus(_) => val.clone(),
499						PrefixOperator::Not(_) => {
500							return Err(TypeError::LogicalOperatorNotApplicable {
501								operator: LogicalOp::Not,
502								operand_category: OperandCategory::Number,
503								fragment: prefix.full_fragment_owned(),
504							}
505							.into());
506						}
507					});
508				} else {
509					result.push(Decimal::from(0));
510				}
511			}
512			let new_data = ColumnData::decimal(result);
513			Ok(column.with_new_data(new_data))
514		}
515		ColumnData::DictionaryId(_) => match prefix.operator {
516			PrefixOperator::Not(_) => Err(CoreError::FrameError {
517				message: "Cannot apply NOT operator to DictionaryId type".to_string(),
518			}
519			.into()),
520			_ => Err(CoreError::FrameError {
521				message: "Cannot apply arithmetic prefix operator to DictionaryId type".to_string(),
522			}
523			.into()),
524		},
525		ColumnData::Any(_) => match prefix.operator {
526			PrefixOperator::Not(_) => Err(CoreError::FrameError {
527				message: "Cannot apply NOT operator to Any type".to_string(),
528			}
529			.into()),
530			_ => Err(CoreError::FrameError {
531				message: "Cannot apply arithmetic prefix operator to Any type".to_string(),
532			}
533			.into()),
534		},
535		ColumnData::Option {
536			..
537		} => unreachable!("nested Option after unwrap"),
538	})
539}