Skip to main content

agentdb/
filter.rs

1use serde_json::Value;
2
3/// Evaluate a metadata filter against a JSON document.
4///
5/// Supports exact match and operators:
6/// `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$exists`
7pub fn matches(metadata: &Value, filter: &Value) -> bool {
8    let (meta_obj, filter_obj) = match (metadata, filter) {
9        (Value::Object(m), Value::Object(f)) => (m, f),
10        _ => return false,
11    };
12    for (key, condition) in filter_obj {
13        let field = meta_obj.get(key);
14        match condition {
15            Value::Object(ops) => {
16                for (op, operand) in ops {
17                    if !apply_op(op, field, operand) {
18                        return false;
19                    }
20                }
21            }
22            expected => {
23                if field != Some(expected) {
24                    return false;
25                }
26            }
27        }
28    }
29    true
30}
31
32fn apply_op(op: &str, field: Option<&Value>, operand: &Value) -> bool {
33    match op {
34        "$eq" => field == Some(operand),
35        "$ne" => field != Some(operand),
36        "$exists" => field.is_some() == operand.as_bool().unwrap_or(true),
37        "$gt" => cmp_num(field, operand, |a, b| a > b),
38        "$gte" => cmp_num(field, operand, |a, b| a >= b),
39        "$lt" => cmp_num(field, operand, |a, b| a < b),
40        "$lte" => cmp_num(field, operand, |a, b| a <= b),
41        "$in" => match (field, operand) {
42            (Some(v), Value::Array(arr)) => arr.contains(v),
43            _ => false,
44        },
45        "$nin" => match (field, operand) {
46            (Some(v), Value::Array(arr)) => !arr.contains(v),
47            _ => true,
48        },
49        _ => false,
50    }
51}
52
53fn cmp_num<F>(field: Option<&Value>, operand: &Value, cmp: F) -> bool
54where
55    F: Fn(f64, f64) -> bool,
56{
57    match (field, operand) {
58        (Some(Value::Number(a)), Value::Number(b)) => match (a.as_f64(), b.as_f64()) {
59            (Some(av), Some(bv)) => cmp(av, bv),
60            _ => false,
61        },
62        _ => false,
63    }
64}