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