use serde_json::Value;
use crate::{
parser::ast::{ASTExpr, CompareOp},
parser::query_parser::get_value_by_path,
};
pub fn eval_query_expr(expr: &ASTExpr, label: &Value) -> bool {
match expr {
ASTExpr::And(subs) => subs.iter().all(|e| eval_query_expr(e, label)),
ASTExpr::Or(subs) => subs.iter().any(|e| eval_query_expr(e, label)),
ASTExpr::Not(sub) => !eval_query_expr(sub, label),
ASTExpr::Compare { field, op } => {
if let Some(field_val) = get_value_by_path(label, field) {
match op {
CompareOp::Eq(value) => field_val == value,
CompareOp::Ne(value) => field_val != value,
CompareOp::Lt(num) => {
if let Some(f1) = field_val.as_f64() {
f1 < *num
} else {
false
}
}
CompareOp::Lte(num) => {
if let Some(f1) = field_val.as_f64() {
f1 <= *num
} else {
false
}
}
CompareOp::Gt(num) => {
if let Some(f1) = field_val.as_f64() {
f1 > *num
} else {
false
}
}
CompareOp::Gte(num) => {
if let Some(f1) = field_val.as_f64() {
f1 >= *num
} else {
false
}
}
}
} else {
false }
}
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
use crate::parser::query_parser::parse_query_filter;
#[test]
fn test_and_or_not_compare() {
let label = json!({
"a": 1,
"b": 2,
"c": 3,
"specs": { "cpu": "i7" },
"arr": [1,2,3]
});
let filter = json!({"$and": [
{"a": {"$eq": 1}},
{"b": {"$gt": 1}},
{"specs.cpu": {"$eq": "i7"}},
{"$or": [
{"c": {"$lt": 2}},
{"c": {"$gte": 3}}
]},
{"b": {"$eq": 2}}
]});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_not() {
let label = json!({"x": 5});
let filter = json!({"$not": {"x": {"$eq": 3}}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_compare_fail() {
let label = json!({"foo": 1});
let filter = json!({"foo": {"$gt": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
}
#[test]
#[ignore] fn test_in_with_array_field() {
let label = json!({"tags": ["a", "b", "c"]});
let filter = json!({"tags": {"$in": ["b", "x"]}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
#[ignore] fn test_nin_with_array_field() {
let label = json!({"tags": ["a", "b", "c"]});
let filter = json!({"tags": {"$nin": ["x", "y"]}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_dot_notation_missing_field() {
let label = json!({"specs": {}});
let filter = json!({"specs.cpu": {"$eq": "i7"}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
}
#[test]
fn test_multiple_field_and() {
let label = json!({"a": 1, "b": 2});
let filter = json!({"a": {"$eq": 1}, "b": {"$eq": 2}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_ne_operator() {
let label = json!({"foo": 5});
let filter = json!({"foo": {"$ne": 3}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_all_compare_ops() {
let label = json!({
"int": 5,
"flt": 3.5,
"str": "abc",
"arr": [1, 2, 3],
});
let filter = json!({"int": {"$eq": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"int": {"$ne": 3}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"flt": {"$lt": 4.0}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"flt": {"$lte": 3.5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"int": {"$gt": 4}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"int": {"$gte": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"int": {"$eq": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"int": {"$ne": 1}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_all_logical_ops() {
let label = json!({"a": 1, "b": 2, "c": 3});
let filter = json!({"$and": [
{"a": {"$eq": 1}},
{"b": {"$eq": 2}}
]});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"$or": [
{"a": {"$eq": 2}},
{"b": {"$eq": 2}}
]});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"$not": {"c": {"$eq": 4}}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"$and": [
{"$or": [
{"a": {"$eq": 2}},
{"b": {"$eq": 2}}
]},
{"$not": {"c": {"$eq": 4}}}
]});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
#[test]
fn test_numeric_comparison_edge_cases() {
let label = json!({
"integer": 10,
"float": 10.5,
"zero": 0,
"negative": -5,
"string": "10",
"bool": true,
"null": null,
"array": [1, 2, 3],
"object": {"value": 10}
});
let filter = json!({"integer": {"$eq": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"float": {"$eq": 10.5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$eq": 10.0}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$lt": 11}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$lt": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$lte": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$gt": 9}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$gt": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"integer": {"$gte": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"negative": {"$lt": 0}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"zero": {"$eq": 0}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"string": {"$gt": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"bool": {"$lt": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"null": {"$gte": 0}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"array": {"$lte": 5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"object": {"$lt": 15}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
}
#[test]
fn test_mixed_type_comparisons() {
let label = json!({
"integer": 10,
"float": 10.5,
"string_num": "10",
"string_text": "hello",
"large_integer": 9007199254740991i64, "scientific": 1.23e2, });
let filter = json!({"integer": {"$lt": 10.5}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"float": {"$gt": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"scientific": {"$eq": 123}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"string_num": {"$eq": 10}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"string_num": {"$lt": 11}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(!eval_query_expr(&ast, &label));
let filter = json!({"large_integer": {"$eq": 9007199254740991i64}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"float": {"$gt": 10.499999}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
let filter = json!({"float": {"$lt": 10.500001}});
let ast = parse_query_filter(&filter).expect("Failed to parse filter");
assert!(eval_query_expr(&ast, &label));
}
}