tellaro-query-language 2.0.0

A flexible, human-friendly query language for searching and filtering structured data
Documentation
//! Tests for array operators with post-processing.
//!
//! This module tests ANY, ALL, NONE operators with array fields
//! and verifies post-processing preserves original data.

use serde_json::json;
use tellaro_query_language::Tql;

/// Test ANY operator with single value (array)
#[test]
fn test_any_operator_with_single_value() {
    let tql = Tql::new();
    let data = vec![
        json!({"tags": ["python"]}), // Single element array
        json!({"tags": ["java"]}),
    ];

    // ANY works on arrays - single element array should match
    let results = tql
        .query(&data, "any tags eq 'python'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 1);
    assert!(results[0].get("tags").and_then(|t| t.as_array()).is_some());
}

/// Test ANY operator with array field
#[test]
fn test_any_operator_with_array_field() {
    let tql = Tql::new();
    let data = vec![
        json!({"tags": ["python", "rust"]}),
        json!({"tags": ["java", "javascript"]}),
        json!({"tags": ["python", "go"]}),
    ];

    let results = tql
        .query(&data, "any tags eq 'python'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2);
}

/// Test ALL operator with array field
#[test]
fn test_all_operator_with_array_field() {
    let tql = Tql::new();
    let data = vec![
        json!({"scores": [100, 100, 100]}), // All 100
        json!({"scores": [100, 90, 100]}),  // Not all 100
        json!({"scores": [100]}),           // Single 100
    ];

    let results = tql
        .query(&data, "all scores eq 100")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2); // First and third records
}

/// Test NONE operator with array field
#[test]
fn test_none_operator_with_array_field() {
    let tql = Tql::new();
    let data = vec![
        json!({"status": ["error", "warning"]}),
        json!({"status": ["info", "debug"]}),
        json!({"status": ["error"]}),
    ];

    let results = tql
        .query(&data, "none status eq 'error'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 1);
    assert!(results[0]
        .get("status")
        .and_then(|s| s.as_array())
        .map(|a| a.iter().all(|v| v.as_str() != Some("error")))
        .unwrap_or(false));
}

/// Test array operators with comparison operators (not just eq)
#[test]
fn test_array_operators_with_comparison_operators() {
    let tql = Tql::new();
    let data = vec![
        json!({"scores": [50, 75, 90]}),
        json!({"scores": [30, 40, 50]}),
        json!({"scores": [80, 85, 95]}),
    ];

    // Any score > 70
    let results = tql
        .query(&data, "any scores gt 70")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2); // First and third

    // All scores < 60
    let results = tql
        .query(&data, "all scores lt 60")
        .expect("Query should succeed");
    assert_eq!(results.len(), 1); // Second only
}

/// Test array operators with logical operators
#[test]
fn test_array_operators_with_logical_operators() {
    let tql = Tql::new();
    let data = vec![
        json!({"tags": ["python", "data"], "active": true}),
        json!({"tags": ["java"], "active": false}),
        json!({"tags": ["python", "web"], "active": true}),
    ];

    let results = tql
        .query(&data, "any tags eq 'python' and active = true")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2);
}

/// Test array operators preserve original data
#[test]
fn test_array_operators_preserve_original_data() {
    let tql = Tql::new();
    let data = vec![json!({
        "id": 1,
        "tags": ["a", "b", "c"],
        "metadata": {"key": "value"}
    })];

    let results = tql
        .query(&data, "any tags eq 'b'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 1);

    // Verify original data is preserved
    let record = &results[0];
    assert_eq!(record.get("id").and_then(|v| v.as_i64()), Some(1));
    assert!(record.get("tags").and_then(|t| t.as_array()).is_some());
    assert!(record.get("metadata").and_then(|m| m.get("key")).is_some());
}

/// Test array operators with nested fields
#[test]
fn test_array_operators_with_nested_fields() {
    let tql = Tql::new();
    let data = vec![
        json!({"user": {"roles": ["admin", "user"]}}),
        json!({"user": {"roles": ["guest"]}}),
        json!({"user": {"roles": ["admin", "moderator"]}}),
    ];

    let results = tql
        .query(&data, "any user.roles eq 'admin'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2);
}

/// Test array operators with empty arrays
#[test]
fn test_array_operators_with_empty_arrays() {
    let tql = Tql::new();
    let data = vec![
        json!({"tags": []}),
        json!({"tags": ["a"]}),
        json!({"tags": ["a", "b"]}),
    ];

    // ANY on empty array should return false
    let results = tql
        .query(&data, "any tags eq 'a'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2); // Second and third

    // NONE on empty array should return true (vacuous truth)
    let results = tql
        .query(&data, "none tags eq 'z'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 3); // All records
}

/// Test ANY with contains operator
#[test]
fn test_any_with_contains() {
    let tql = Tql::new();
    let data = vec![
        json!({"names": ["Alice", "Bob"]}),
        json!({"names": ["Charlie", "David"]}),
    ];

    let results = tql
        .query(&data, "any names contains 'li'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2); // Alice and Charlie both contain 'li'
}

/// Test ALL with contains operator
#[test]
fn test_all_with_contains() {
    let tql = Tql::new();
    let data = vec![
        json!({"words": ["apple", "application"]}), // All contain 'appl'
        json!({"words": ["apple", "banana"]}),      // Not all contain 'appl'
    ];

    let results = tql
        .query(&data, "all words contains 'appl'")
        .expect("Query should succeed");
    assert_eq!(results.len(), 1);
}

/// Test multiple array operators in same query
#[test]
fn test_multiple_array_operators() {
    let tql = Tql::new();
    let data = vec![
        json!({"tags": ["a", "b"], "scores": [10, 20]}),
        json!({"tags": ["c"], "scores": [30, 40]}),
        json!({"tags": ["a"], "scores": [50]}),
    ];

    let results = tql
        .query(&data, "any tags eq 'a' and any scores gt 15")
        .expect("Query should succeed");
    assert_eq!(results.len(), 2); // First and third (third has score 50)
}