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