datacules-agentdb 0.4.5

Single-file embedded database for AI agents. SQL + Vector Search + Full-Text Search + Hybrid Queries + Memory Graphs.
Documentation
use serde_json::Value;

/// Evaluate a metadata filter against a JSON document.
///
/// Supports exact match and operators:
/// `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$exists`
pub fn matches(metadata: &Value, filter: &Value) -> bool {
    let (meta_obj, filter_obj) = match (metadata, filter) {
        (Value::Object(m), Value::Object(f)) => (m, f),
        _ => return false,
    };
    for (key, condition) in filter_obj {
        let field = meta_obj.get(key);
        match condition {
            Value::Object(ops) => {
                for (op, operand) in ops {
                    if !apply_op(op, field, operand) {
                        return false;
                    }
                }
            }
            expected => {
                if field != Some(expected) {
                    return false;
                }
            }
        }
    }
    true
}

fn apply_op(op: &str, field: Option<&Value>, operand: &Value) -> bool {
    match op {
        "$eq" => field == Some(operand),
        "$ne" => field != Some(operand),
        "$exists" => field.is_some() == operand.as_bool().unwrap_or(true),
        "$gt" => cmp_num(field, operand, |a, b| a > b),
        "$gte" => cmp_num(field, operand, |a, b| a >= b),
        "$lt" => cmp_num(field, operand, |a, b| a < b),
        "$lte" => cmp_num(field, operand, |a, b| a <= b),
        "$in" => match (field, operand) {
            (Some(v), Value::Array(arr)) => arr.contains(v),
            _ => false,
        },
        "$nin" => match (field, operand) {
            (Some(v), Value::Array(arr)) => !arr.contains(v),
            _ => true,
        },
        _ => false,
    }
}

fn cmp_num<F>(field: Option<&Value>, operand: &Value, cmp: F) -> bool
where
    F: Fn(f64, f64) -> bool,
{
    match (field, operand) {
        (Some(Value::Number(a)), Value::Number(b)) => match (a.as_f64(), b.as_f64()) {
            (Some(av), Some(bv)) => cmp(av, bv),
            _ => false,
        },
        _ => false,
    }
}