1use reifydb_core::{
5 error::CoreError,
6 value::column::{Column, data::ColumnData},
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 = ColumnData::$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 = ColumnData::$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 = ColumnData::$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(column: &Column, operator: &PrefixOperator, fragment: &Fragment) -> Result<Column> {
117 unary_op_unwrap_option(column, |column| match column.data() {
118 ColumnData::Bool(container) => match operator {
119 PrefixOperator::Not(_) => {
120 let mut result = Vec::with_capacity(container.data().len());
121 for (idx, val) in container.data().iter().enumerate() {
122 if container.is_defined(idx) {
123 result.push(!val);
124 } else {
125 result.push(false);
126 }
127 }
128
129 let new_data = ColumnData::bool(result);
130 Ok(column.with_new_data(new_data))
131 }
132 _ => Err(CoreError::FrameError {
133 message: "Cannot apply arithmetic prefix operator to bool".to_string(),
134 }
135 .into()),
136 },
137
138 ColumnData::Float4(container) => {
139 prefix_float!(column, container, operator, fragment.clone(), 0.0f32, float4)
140 }
141
142 ColumnData::Float8(container) => {
143 prefix_float!(column, container, operator, fragment.clone(), 0.0f64, float8)
144 }
145
146 ColumnData::Int1(container) => {
147 prefix_signed_int!(column, container, operator, fragment.clone(), int1)
148 }
149
150 ColumnData::Int2(container) => {
151 prefix_signed_int!(column, container, operator, fragment.clone(), int2)
152 }
153
154 ColumnData::Int4(container) => {
155 prefix_signed_int!(column, container, operator, fragment.clone(), int4)
156 }
157
158 ColumnData::Int8(container) => {
159 prefix_signed_int!(column, container, operator, fragment.clone(), int8)
160 }
161
162 ColumnData::Int16(container) => {
163 prefix_signed_int!(column, container, operator, fragment.clone(), int16)
164 }
165
166 ColumnData::Utf8 {
167 container: _,
168 ..
169 } => match operator {
170 PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
171 operator: LogicalOp::Not,
172 operand_category: OperandCategory::Text,
173 fragment: fragment.clone(),
174 }
175 .into()),
176 _ => Err(CoreError::FrameError {
177 message: "Cannot apply arithmetic prefix operator to text".to_string(),
178 }
179 .into()),
180 },
181
182 ColumnData::Uint1(container) => {
183 prefix_unsigned_int!(column, container, operator, fragment.clone(), i8, int1)
184 }
185
186 ColumnData::Uint2(container) => {
187 prefix_unsigned_int!(column, container, operator, fragment.clone(), i16, int2)
188 }
189
190 ColumnData::Uint4(container) => {
191 prefix_unsigned_int!(column, container, operator, fragment.clone(), i32, int4)
192 }
193
194 ColumnData::Uint8(container) => {
195 prefix_unsigned_int!(column, container, operator, fragment.clone(), i64, int8)
196 }
197
198 ColumnData::Uint16(container) => {
199 prefix_unsigned_int!(column, container, operator, fragment.clone(), i128, int16)
200 }
201
202 ColumnData::Date(_) => {
203 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
204 }
205 ColumnData::DateTime(_) => {
206 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
207 }
208 ColumnData::Time(_) => {
209 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
210 }
211 ColumnData::Duration(_) => {
212 prefix_not_error!(operator, fragment.clone(), OperandCategory::Temporal)
213 }
214 ColumnData::IdentityId(_) => {
215 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
216 }
217 ColumnData::Uuid4(_) => {
218 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
219 }
220 ColumnData::Uuid7(_) => {
221 prefix_not_error!(operator, fragment.clone(), OperandCategory::Uuid)
222 }
223
224 ColumnData::Blob {
225 container: _,
226 ..
227 } => match operator {
228 PrefixOperator::Not(_) => Err(CoreError::FrameError {
229 message: "Cannot apply NOT operator to BLOB".to_string(),
230 }
231 .into()),
232 _ => Err(CoreError::FrameError {
233 message: "Cannot apply arithmetic prefix operator to BLOB".to_string(),
234 }
235 .into()),
236 },
237 ColumnData::Int {
238 container,
239 ..
240 } => {
241 let mut result = Vec::with_capacity(container.data().len());
242 for (idx, val) in container.data().iter().enumerate() {
243 if container.is_defined(idx) {
244 result.push(match operator {
245 PrefixOperator::Minus(_) => Int(-val.0.clone()),
246 PrefixOperator::Plus(_) => val.clone(),
247 PrefixOperator::Not(_) => {
248 return Err(TypeError::LogicalOperatorNotApplicable {
249 operator: LogicalOp::Not,
250 operand_category: OperandCategory::Number,
251 fragment: fragment.clone(),
252 }
253 .into());
254 }
255 });
256 } else {
257 result.push(Int::zero());
258 }
259 }
260 let new_data = ColumnData::int(result);
261 Ok(column.with_new_data(new_data))
262 }
263 ColumnData::Uint {
264 container,
265 ..
266 } => match operator {
267 PrefixOperator::Minus(_) => {
268 let mut result = Vec::with_capacity(container.data().len());
269 for (idx, val) in container.data().iter().enumerate() {
270 if container.is_defined(idx) {
271 let negated = -val.0.clone();
272 result.push(Int::from(negated));
273 } else {
274 result.push(Int::zero());
275 }
276 }
277 let new_data = ColumnData::int(result);
278 Ok(column.with_new_data(new_data))
279 }
280 PrefixOperator::Plus(_) => {
281 let mut result = Vec::with_capacity(container.data().len());
282 for (idx, val) in container.data().iter().enumerate() {
283 if container.is_defined(idx) {
284 result.push(val.clone());
285 } else {
286 result.push(Uint::zero());
287 }
288 }
289 let new_data = ColumnData::uint(result);
290 Ok(column.with_new_data(new_data))
291 }
292 PrefixOperator::Not(_) => Err(TypeError::LogicalOperatorNotApplicable {
293 operator: LogicalOp::Not,
294 operand_category: OperandCategory::Number,
295 fragment: fragment.clone(),
296 }
297 .into()),
298 },
299 ColumnData::Decimal {
300 container,
301 ..
302 } => {
303 let mut result = Vec::with_capacity(container.data().len());
304 for (idx, val) in container.data().iter().enumerate() {
305 if container.is_defined(idx) {
306 result.push(match operator {
307 PrefixOperator::Minus(_) => val.clone().negate(),
308 PrefixOperator::Plus(_) => val.clone(),
309 PrefixOperator::Not(_) => {
310 return Err(TypeError::LogicalOperatorNotApplicable {
311 operator: LogicalOp::Not,
312 operand_category: OperandCategory::Number,
313 fragment: fragment.clone(),
314 }
315 .into());
316 }
317 });
318 } else {
319 result.push(Decimal::from(0));
320 }
321 }
322 let new_data = ColumnData::decimal(result);
323 Ok(column.with_new_data(new_data))
324 }
325 ColumnData::DictionaryId(_) => match operator {
326 PrefixOperator::Not(_) => Err(CoreError::FrameError {
327 message: "Cannot apply NOT operator to DictionaryId type".to_string(),
328 }
329 .into()),
330 _ => Err(CoreError::FrameError {
331 message: "Cannot apply arithmetic prefix operator to DictionaryId type".to_string(),
332 }
333 .into()),
334 },
335 ColumnData::Any(_) => match operator {
336 PrefixOperator::Not(_) => Err(CoreError::FrameError {
337 message: "Cannot apply NOT operator to Any type".to_string(),
338 }
339 .into()),
340 _ => Err(CoreError::FrameError {
341 message: "Cannot apply arithmetic prefix operator to Any type".to_string(),
342 }
343 .into()),
344 },
345 ColumnData::Option {
346 ..
347 } => unreachable!("nested Option after unwrap"),
348 })
349}