1use crate::executor::expression::evaluator::collection_operations::CollectionOperationEvaluator;
2use crate::executor::expression::ExpressionError;
3use linkrs_core::types::operators::{BinaryOperator, UnaryOperator};
4use linkrs_core::value::list::List;
5use linkrs_core::value::Value;
9
10pub struct BinaryOperationEvaluator;
12
13impl BinaryOperationEvaluator {
14 pub fn evaluate(
16 left: &Value,
17 op: &BinaryOperator,
18 right: &Value,
19 ) -> Result<Value, ExpressionError> {
20 match op {
21 BinaryOperator::Add => Self::eval_add(left, right),
23 BinaryOperator::Subtract => Self::eval_subtract(left, right),
24 BinaryOperator::Multiply => Self::eval_multiply(left, right),
25 BinaryOperator::Divide => Self::eval_divide(left, right),
26 BinaryOperator::Modulo => Self::eval_modulo(left, right),
27 BinaryOperator::Exponent => Self::eval_exponent(left, right),
28
29 BinaryOperator::Equal => Self::eval_equal(left, right),
31 BinaryOperator::NotEqual => Self::eval_not_equal(left, right),
32 BinaryOperator::LessThan => Self::eval_less_than(left, right),
33 BinaryOperator::LessThanOrEqual => Self::eval_less_than_or_equal(left, right),
34 BinaryOperator::GreaterThan => Self::eval_greater_than(left, right),
35 BinaryOperator::GreaterThanOrEqual => Self::eval_greater_than_or_equal(left, right),
36
37 BinaryOperator::And => Self::eval_and(left, right),
39 BinaryOperator::Or => Self::eval_or(left, right),
40 BinaryOperator::Xor => Self::eval_xor(left, right),
41
42 BinaryOperator::StringConcat => Self::eval_string_concat(left, right),
44 BinaryOperator::Like => Self::eval_like(left, right),
45 BinaryOperator::In => Self::eval_in(left, right),
46 BinaryOperator::NotIn => Self::eval_not_in(left, right),
47
48 BinaryOperator::JsonGet => Self::eval_json_get(left, right),
50 BinaryOperator::JsonGetText => Self::eval_json_get_text(left, right),
51 BinaryOperator::JsonPathGet => Self::eval_json_path_get(left, right),
52 BinaryOperator::JsonPathGetText => Self::eval_json_path_get_text(left, right),
53 BinaryOperator::Contains => Self::eval_contains(left, right),
54 BinaryOperator::StartsWith => Self::eval_starts_with(left, right),
55 BinaryOperator::EndsWith => Self::eval_ends_with(left, right),
56
57 BinaryOperator::Subscript => {
59 CollectionOperationEvaluator::eval_subscript_access(left, right)
60 }
61 BinaryOperator::Attribute => {
62 CollectionOperationEvaluator::eval_attribute_access(left, right)
63 }
64
65 BinaryOperator::Union => Self::eval_union(left, right),
67 BinaryOperator::Intersect => Self::eval_intersect(left, right),
68 BinaryOperator::Except => Self::eval_except(left, right),
69
70 BinaryOperator::BitwiseOr => left.bit_or(right).map_err(ExpressionError::runtime_error),
72 BinaryOperator::BitwiseAnd => {
73 left.bit_and(right).map_err(ExpressionError::runtime_error)
74 }
75 BinaryOperator::ShiftLeft => {
76 left.bit_shl(right).map_err(ExpressionError::runtime_error)
77 }
78 BinaryOperator::ShiftRight => {
79 left.bit_shr(right).map_err(ExpressionError::runtime_error)
80 }
81 }
82 }
83
84 fn eval_add(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
85 left.add(right).map_err(ExpressionError::runtime_error)
86 }
87
88 fn eval_subtract(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
89 left.sub(right).map_err(ExpressionError::runtime_error)
90 }
91
92 fn eval_multiply(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
93 left.mul(right).map_err(ExpressionError::runtime_error)
94 }
95
96 fn eval_divide(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
97 left.div(right).map_err(ExpressionError::runtime_error)
98 }
99
100 fn eval_modulo(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
101 left.rem(right).map_err(ExpressionError::runtime_error)
102 }
103
104 fn eval_exponent(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
105 left.pow(right).map_err(ExpressionError::runtime_error)
106 }
107
108 fn eval_equal(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
109 Ok(Value::Bool(left == right))
110 }
111
112 fn eval_not_equal(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
113 Ok(Value::Bool(left != right))
114 }
115
116 fn eval_less_than(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
117 Ok(Value::Bool(left < right))
118 }
119
120 fn eval_less_than_or_equal(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
121 Ok(Value::Bool(left <= right))
122 }
123
124 fn eval_greater_than(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
125 Ok(Value::Bool(left > right))
126 }
127
128 fn eval_greater_than_or_equal(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
129 Ok(Value::Bool(left >= right))
130 }
131
132 fn eval_and(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
133 left.and(right).map_err(ExpressionError::runtime_error)
134 }
135
136 fn eval_or(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
137 left.or(right).map_err(ExpressionError::runtime_error)
138 }
139
140 fn eval_xor(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
141 match (left, right) {
142 (Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(*l ^ *r)),
143 _ => Err(ExpressionError::type_error(
144 "The XOR operation requires boolean values.",
145 )),
146 }
147 }
148
149 fn eval_string_concat(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
150 left.add(right).map_err(ExpressionError::runtime_error)
151 }
152
153 fn eval_like(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
154 if left.is_bad_null() || right.is_bad_null() {
155 return Ok(Value::Null(linkrs_core::value::NullType::BadData));
156 }
157
158 if (!left.is_null() && !left.is_empty() && !matches!(left, Value::String(_)))
159 || (!right.is_null() && !right.is_empty() && !matches!(right, Value::String(_)))
160 {
161 return Ok(Value::Null(linkrs_core::value::NullType::BadData));
162 }
163
164 if left.is_null() || right.is_null() {
165 return Ok(Value::Null(linkrs_core::value::NullType::Null));
166 }
167
168 match (left, right) {
169 (Value::String(l), Value::String(r)) => Self::eval_like_operation(l, r),
170 _ => Ok(Value::Null(linkrs_core::value::NullType::BadData)),
171 }
172 }
173
174 fn eval_like_operation(pattern: &str, text: &str) -> Result<Value, ExpressionError> {
175 let mut pattern_chars = pattern.chars().peekable();
176 let mut text_chars = text.chars().peekable();
177
178 while let Some(p) = pattern_chars.next() {
179 match p {
180 '%' => {
181 let remaining_pattern: String = pattern_chars.collect();
182 let remaining_text: String = text_chars.collect();
183
184 if remaining_pattern.is_empty() {
185 return Ok(Value::Bool(true));
186 }
187
188 for i in 0..=remaining_text.len() {
189 if let Value::Bool(b) =
190 Self::eval_like_operation(&remaining_pattern, &remaining_text[i..])?
191 {
192 if b {
193 return Ok(Value::Bool(true));
194 }
195 }
196 }
197
198 return Ok(Value::Bool(false));
199 }
200 '_' => {
201 if text_chars.next().is_none() {
202 return Ok(Value::Bool(false));
203 }
204 }
205 '\\' => {
206 if let Some(escaped_char) = pattern_chars.next() {
207 if text_chars.next() != Some(escaped_char) {
208 return Ok(Value::Bool(false));
209 }
210 }
211 }
212 c => {
213 if text_chars.next() != Some(c) {
214 return Ok(Value::Bool(false));
215 }
216 }
217 }
218 }
219
220 Ok(Value::Bool(text_chars.next().is_none()))
221 }
222
223 fn eval_in(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
224 if left.is_null() || right.is_null() {
225 return Ok(Value::Null(linkrs_core::value::NullType::Null));
226 }
227
228 match right {
229 Value::List(items) => {
230 if items.iter().any(|item| item.is_null()) {
231 return Ok(Value::Null(linkrs_core::value::NullType::Null));
232 }
233 Ok(Value::Bool(items.contains(left)))
234 }
235 _ => Err(ExpressionError::type_error(
236 "The right side of the IN operation must be a list.",
237 )),
238 }
239 }
240
241 fn eval_not_in(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
242 if left.is_null() || right.is_null() {
243 return Ok(Value::Null(linkrs_core::value::NullType::Null));
244 }
245
246 match right {
247 Value::List(items) => {
248 if items.iter().any(|item| item.is_null()) {
249 return Ok(Value::Null(linkrs_core::value::NullType::Null));
250 }
251 Ok(Value::Bool(!items.contains(left)))
252 }
253 _ => Err(ExpressionError::type_error(
254 "The right side of the NOT IN operation must be a list.",
255 )),
256 }
257 }
258
259 fn eval_contains(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
260 if left.is_null() || right.is_null() {
261 return Ok(Value::Null(linkrs_core::value::NullType::Null));
262 }
263
264 match (&left, &right) {
265 (Value::String(s), Value::String(sub)) => Ok(Value::Bool(s.contains(&**sub))),
266 (Value::List(items), item) => {
267 if items.iter().any(|i| i.is_null()) {
268 return Ok(Value::Null(linkrs_core::value::NullType::Null));
269 }
270 Ok(Value::Bool(items.contains(item)))
271 }
272 _ => Err(ExpressionError::type_error(
273 "The CONTAINS operation requires a string or a list.",
274 )),
275 }
276 }
277
278 fn eval_starts_with(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
279 if left.is_null() || right.is_null() {
280 return Ok(Value::Null(linkrs_core::value::NullType::Null));
281 }
282
283 match (&left, &right) {
284 (Value::String(s), Value::String(prefix)) => Ok(Value::Bool(s.starts_with(&**prefix))),
285 _ => Err(ExpressionError::type_error(
286 "The `STARTS WITH` operation requires a string value.",
287 )),
288 }
289 }
290
291 fn eval_ends_with(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
292 if left.is_null() || right.is_null() {
293 return Ok(Value::Null(linkrs_core::value::NullType::Null));
294 }
295
296 match (&left, &right) {
297 (Value::String(s), Value::String(suffix)) => Ok(Value::Bool(s.ends_with(&**suffix))),
298 _ => Err(ExpressionError::type_error(
299 "The ENDS WITH operation requires a string value.",
300 )),
301 }
302 }
303
304 fn eval_union(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
305 if left.is_null() || right.is_null() {
306 return Ok(Value::Null(linkrs_core::value::NullType::Null));
307 }
308
309 match (left, right) {
310 (Value::List(l), Value::List(r)) => {
311 if l.iter().any(|item| item.is_null()) || r.iter().any(|item| item.is_null()) {
312 return Ok(Value::Null(linkrs_core::value::NullType::Null));
313 }
314 let mut result = (**l).clone();
315 result.extend(r.iter().cloned());
316 Ok(Value::list(result))
317 }
318 _ => Err(ExpressionError::type_error("UNION requires list values")),
319 }
320 }
321
322 fn eval_intersect(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
323 if left.is_null() || right.is_null() {
324 return Ok(Value::Null(linkrs_core::value::NullType::Null));
325 }
326
327 match (left, right) {
328 (Value::List(l), Value::List(r)) => {
329 if l.iter().any(|item| item.is_null()) || r.iter().any(|item| item.is_null()) {
330 return Ok(Value::Null(linkrs_core::value::NullType::Null));
331 }
332 let result: Vec<Value> =
333 l.iter().filter(|item| r.contains(item)).cloned().collect();
334 Ok(Value::list(List::from(result)))
335 }
336 _ => Err(ExpressionError::type_error(
337 "INTERSECT requires list values",
338 )),
339 }
340 }
341
342 fn eval_except(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
343 if left.is_null() || right.is_null() {
344 return Ok(Value::Null(linkrs_core::value::NullType::Null));
345 }
346
347 match (left, right) {
348 (Value::List(l), Value::List(r)) => {
349 if l.iter().any(|item| item.is_null()) || r.iter().any(|item| item.is_null()) {
350 return Ok(Value::Null(linkrs_core::value::NullType::Null));
351 }
352 let result: Vec<Value> =
353 l.iter().filter(|item| !r.contains(item)).cloned().collect();
354 Ok(Value::list(List::from(result)))
355 }
356 _ => Err(ExpressionError::type_error("EXCEPT requires list values")),
357 }
358 }
359
360 fn eval_json_get(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
362 Self::eval_json_operator(left, right, false, false)
363 }
364
365 fn eval_json_get_text(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
366 Self::eval_json_operator(left, right, true, false)
367 }
368
369 fn eval_json_path_get(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
370 Self::eval_json_operator(left, right, false, true)
371 }
372
373 fn eval_json_path_get_text(left: &Value, right: &Value) -> Result<Value, ExpressionError> {
374 Self::eval_json_operator(left, right, true, true)
375 }
376
377 fn eval_json_operator(
378 json: &Value,
379 key_or_path: &Value,
380 as_text: bool,
381 is_path: bool,
382 ) -> Result<Value, ExpressionError> {
383 use linkrs_core::value::NullType;
384 use serde_json::Value as JsonValue;
385
386 if json.is_null() || key_or_path.is_null() {
387 return Ok(Value::Null(NullType::Null));
388 }
389
390 let json_value = match json {
391 Value::String(s) => serde_json::from_str(s)
392 .map_err(|e| ExpressionError::type_error(format!("Invalid JSON string: {}", e))),
393 Value::Json(j) => j
394 .to_value()
395 .map_err(|e| ExpressionError::type_error(format!("Invalid JSON: {}", e))),
396 Value::JsonB(j) => Ok(j.as_value().clone()),
397 _ => Err(ExpressionError::type_error(
398 "JSON operator requires JSON/JSONB or JSON string",
399 )),
400 }?;
401
402 let key_str = match key_or_path {
403 Value::String(s) => s.to_string(),
404 _ => {
405 return Err(ExpressionError::type_error(
406 "JSON operator key/path must be a string",
407 ))
408 }
409 };
410
411 let result = if is_path {
412 let path_segments: Vec<&str> = if key_str.starts_with('$') {
414 key_str.split('.').collect()
415 } else {
416 return Err(ExpressionError::type_error("JSON path must start with '$'"));
417 };
418
419 let mut current = &json_value;
420 for segment in path_segments.iter().skip(1) {
421 match current {
422 JsonValue::Object(map) => {
423 if let Some(v) = map.get(*segment) {
424 current = v;
425 } else {
426 return Ok(Value::Null(NullType::Null));
427 }
428 }
429 JsonValue::Array(arr) => {
430 if let Ok(index) = segment.parse::<usize>() {
431 if index < arr.len() {
432 current = &arr[index];
433 } else {
434 return Ok(Value::Null(NullType::Null));
435 }
436 } else {
437 return Ok(Value::Null(NullType::Null));
438 }
439 }
440 _ => return Ok(Value::Null(NullType::Null)),
441 }
442 }
443 current.clone()
444 } else {
445 match &json_value {
447 JsonValue::Object(map) => map.get(&key_str).cloned().unwrap_or(JsonValue::Null),
448 JsonValue::Array(arr) => {
449 if let Ok(index) = key_str.parse::<usize>() {
450 if index < arr.len() {
451 arr[index].clone()
452 } else {
453 JsonValue::Null
454 }
455 } else {
456 JsonValue::Null
457 }
458 }
459 _ => JsonValue::Null,
460 }
461 };
462
463 let value_result = if as_text {
465 match result {
467 JsonValue::Null => Value::Null(NullType::Null),
468 JsonValue::String(s) => Value::string(s),
469 JsonValue::Number(n) => {
470 if let Some(i) = n.as_i64() {
471 Value::BigInt(i)
472 } else if let Some(f) = n.as_f64() {
473 Value::Double(f)
474 } else {
475 Value::string(n.to_string())
476 }
477 }
478 JsonValue::Bool(b) => Value::Bool(b),
479 JsonValue::Array(_) | JsonValue::Object(_) => {
480 Value::string(serde_json::to_string(&result).unwrap_or_default())
481 }
482 }
483 } else {
484 match result {
486 JsonValue::Null => Value::Null(NullType::Null),
487 JsonValue::String(s) => Value::string(s),
488 JsonValue::Number(n) => {
489 if let Some(i) = n.as_i64() {
490 Value::BigInt(i)
491 } else if let Some(f) = n.as_f64() {
492 Value::Double(f)
493 } else {
494 Value::string(n.to_string())
495 }
496 }
497 JsonValue::Bool(b) => Value::Bool(b),
498 JsonValue::Array(arr) => {
499 let items: Vec<Value> = arr
500 .into_iter()
501 .map(|v| match v {
502 JsonValue::Null => Value::Null(NullType::Null),
503 JsonValue::String(s) => Value::string(s),
504 JsonValue::Number(n) => {
505 if let Some(i) = n.as_i64() {
506 Value::BigInt(i)
507 } else if let Some(f) = n.as_f64() {
508 Value::Double(f)
509 } else {
510 Value::string(n.to_string())
511 }
512 }
513 JsonValue::Bool(b) => Value::Bool(b),
514 JsonValue::Array(_) | JsonValue::Object(_) => {
515 Value::string(serde_json::to_string(&v).unwrap_or_default())
516 }
517 })
518 .collect();
519 Value::List(Box::new(linkrs_core::value::list::List::from(items)))
520 }
521 JsonValue::Object(_) => {
522 Value::string(serde_json::to_string(&result).unwrap_or_default())
523 }
524 }
525 };
526
527 Ok(value_result)
528 }
529}
530
531pub struct UnaryOperationEvaluator;
533
534impl UnaryOperationEvaluator {
535 pub fn evaluate(op: &UnaryOperator, value: &Value) -> Result<Value, ExpressionError> {
537 match op {
538 UnaryOperator::Plus => Self::eval_plus(value),
540 UnaryOperator::Minus => Self::eval_minus(value),
541
542 UnaryOperator::Not => Self::eval_not(value),
544
545 UnaryOperator::IsNull => Self::eval_is_null(value),
547 UnaryOperator::IsNotNull => Self::eval_is_not_null(value),
548 UnaryOperator::IsEmpty => Self::eval_is_empty(value),
549 UnaryOperator::IsNotEmpty => Self::eval_is_not_empty(value),
550 }
551 }
552
553 fn eval_plus(value: &Value) -> Result<Value, ExpressionError> {
554 Ok(value.clone())
555 }
556
557 fn eval_minus(value: &Value) -> Result<Value, ExpressionError> {
558 value.neg().map_err(ExpressionError::runtime_error)
559 }
560
561 fn eval_not(value: &Value) -> Result<Value, ExpressionError> {
562 value.not().map_err(ExpressionError::runtime_error)
563 }
564
565 fn eval_is_null(value: &Value) -> Result<Value, ExpressionError> {
566 Ok(Value::Bool(value.is_null()))
567 }
568
569 fn eval_is_not_null(value: &Value) -> Result<Value, ExpressionError> {
570 Ok(Value::Bool(!value.is_null()))
571 }
572
573 fn eval_is_empty(value: &Value) -> Result<Value, ExpressionError> {
574 match value {
575 Value::String(s) => Ok(Value::Bool(s.is_empty())),
576 Value::List(l) => Ok(Value::Bool(l.is_empty())),
577 Value::Map(m) => Ok(Value::Bool(m.is_empty())),
578 _ => Err(ExpressionError::type_error(
579 "The EMPTY check requires the container type.",
580 )),
581 }
582 }
583
584 fn eval_is_not_empty(value: &Value) -> Result<Value, ExpressionError> {
585 match value {
586 Value::String(s) => Ok(Value::Bool(!s.is_empty())),
587 Value::List(l) => Ok(Value::Bool(!l.is_empty())),
588 Value::Map(m) => Ok(Value::Bool(!m.is_empty())),
589 _ => Err(ExpressionError::type_error(
590 "The EMPTY check requires the container type.",
591 )),
592 }
593 }
594}