use serde_json::json;
use tellaro_query_language::Tql;
#[test]
fn test_regexp_operator() {
let tql = Tql::new();
let data = vec![
json!({"email": "alice@example.com"}),
json!({"email": "bob@test.org"}),
json!({"email": "invalid"}),
];
let results = tql
.query(&data, "email regexp '.*@example\\.com$'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("email").and_then(|v| v.as_str()),
Some("alice@example.com")
);
}
#[test]
fn test_regexp_patterns() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice"}),
json!({"name": "Bob"}),
json!({"name": "Charlie"}),
];
let results = tql
.query(&data, "name regexp '^[AB]'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_regexp_case_sensitivity() {
let tql = Tql::new();
let data = vec![
json!({"status": "ERROR"}),
json!({"status": "error"}),
json!({"status": "Error"}),
];
let results = tql
.query(&data, "status regexp '(?i)error'")
.expect("Query should succeed");
assert_eq!(results.len(), 3);
}
#[test]
fn test_not_regexp_operator() {
let tql = Tql::new();
let data = vec![
json!({"email": "alice@example.com"}),
json!({"email": "bob@test.org"}),
json!({"email": "invalid"}),
];
let results = tql
.query(&data, "email not regexp '.*@example\\.com$'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_bang_regexp_operator() {
let tql = Tql::new();
let data = vec![json!({"name": "Alice"}), json!({"name": "Bob"})];
let results = tql
.query(&data, "name !regexp '^A'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_not_regex_underscore_operator() {
let tql = Tql::new();
let data = vec![json!({"name": "Alice"}), json!({"name": "Bob"})];
let results = tql
.query(&data, "name not_regex '^A'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_not_regex_two_word_operator() {
let tql = Tql::new();
let data = vec![json!({"name": "Alice"}), json!({"name": "Bob"})];
let results = tql
.query(&data, "name not regex '^A'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_bang_regex_operator() {
let tql = Tql::new();
let data = vec![json!({"name": "Alice"}), json!({"name": "Bob"})];
let results = tql
.query(&data, "name !regex '^A'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_between_natural_syntax() {
let tql = Tql::new();
let data = vec![json!({"age": 20}), json!({"age": 30}), json!({"age": 40})];
let results = tql
.query(&data, "age between 25 and 35")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("age").and_then(|v| v.as_i64()), Some(30));
}
#[test]
fn test_between_list_syntax_still_works() {
let tql = Tql::new();
let data = vec![json!({"age": 20}), json!({"age": 30}), json!({"age": 40})];
let results = tql
.query(&data, "age between [25, 35]")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("age").and_then(|v| v.as_i64()), Some(30));
}
#[test]
fn test_not_between_natural_syntax() {
let tql = Tql::new();
let data = vec![json!({"age": 20}), json!({"age": 30}), json!({"age": 40})];
let results = tql
.query(&data, "age not between 25 and 35")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_between_string_values() {
let tql = Tql::new();
let data = vec![
json!({"score": "50"}),
json!({"score": "75"}),
json!({"score": "100"}),
];
let results = tql
.query(&data, "score between 60 and 90")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("score").and_then(|v| v.as_str()), Some("75"));
}
#[test]
fn test_not_exists_with_space() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "email": "alice@test.com"}),
json!({"name": "Bob"}), ];
let results = tql
.query(&data, "email not exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_not_exists_underscore_still_works() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "email": "alice@test.com"}),
json!({"name": "Bob"}),
];
let results = tql
.query(&data, "email not_exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_bang_exists_still_works() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "email": "alice@test.com"}),
json!({"name": "Bob"}),
];
let results = tql
.query(&data, "email !exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_contains_with_space() {
let tql = Tql::new();
let data = vec![
json!({"message": "Error occurred"}),
json!({"message": "Success"}),
];
let results = tql
.query(&data, "message not contains 'Error'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("message").and_then(|v| v.as_str()),
Some("Success")
);
}
#[test]
fn test_bang_contains() {
let tql = Tql::new();
let data = vec![
json!({"message": "Error occurred"}),
json!({"message": "Success"}),
];
let results = tql
.query(&data, "message !contains 'Error'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_startswith_with_space() {
let tql = Tql::new();
let data = vec![json!({"path": "/api/users"}), json!({"path": "/web/home"})];
let results = tql
.query(&data, "path not startswith '/api'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("path").and_then(|v| v.as_str()),
Some("/web/home")
);
}
#[test]
fn test_bang_startswith() {
let tql = Tql::new();
let data = vec![json!({"path": "/api/users"}), json!({"path": "/web/home"})];
let results = tql
.query(&data, "path !startswith '/api'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_endswith_with_space() {
let tql = Tql::new();
let data = vec![json!({"file": "data.json"}), json!({"file": "data.csv"})];
let results = tql
.query(&data, "file not endswith '.json'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("file").and_then(|v| v.as_str()),
Some("data.csv")
);
}
#[test]
fn test_bang_endswith() {
let tql = Tql::new();
let data = vec![json!({"file": "data.json"}), json!({"file": "data.csv"})];
let results = tql
.query(&data, "file !endswith '.json'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_integer_type_hint() {
let tql = Tql::new();
let data = vec![json!({"value": "100"}), json!({"value": "50"})];
let results = tql
.query(&data, "value::integer > 75")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("value").and_then(|v| v.as_str()),
Some("100")
);
}
#[test]
fn test_boolean_type_hint() {
let tql = Tql::new();
let data = vec![json!({"enabled": "true"}), json!({"enabled": "false"})];
let results = tql
.query(&data, "enabled::boolean = true")
.expect("Query should succeed");
assert!(!results.is_empty());
}
#[test]
fn test_number_type_hint() {
let tql = Tql::new();
let data = vec![json!({"value": "100"}), json!({"value": "50"})];
let results = tql
.query(&data, "value::number > 75")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_decimal_type_hint() {
let tql = Tql::new();
let data = vec![json!({"price": "99.99"}), json!({"price": "49.99"})];
let results = tql
.query(&data, "price::decimal > 75.0")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_in_with_space() {
let tql = Tql::new();
let data = vec![
json!({"status": "active"}),
json!({"status": "pending"}),
json!({"status": "archived"}),
];
let results = tql
.query(&data, "status not in ['active', 'pending']")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("status").and_then(|v| v.as_str()),
Some("archived")
);
}
#[test]
fn test_not_cidr_with_space() {
let tql = Tql::new();
let data = vec![json!({"ip": "192.168.1.1"}), json!({"ip": "10.0.0.1"})];
let results = tql
.query(&data, "ip not cidr '192.168.0.0/16'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("ip").and_then(|v| v.as_str()),
Some("10.0.0.1")
);
}
#[test]
fn test_regexp_with_logical_operators() {
let tql = Tql::new();
let data = vec![
json!({"email": "admin@example.com", "active": true}),
json!({"email": "user@example.com", "active": false}),
json!({"email": "guest@test.org", "active": true}),
];
let results = tql
.query(&data, "email regexp '@example\\.com$' and active = true")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_complex_not_operators() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "role": "admin", "age": 30}),
json!({"name": "Bob", "role": "user", "age": 25}),
json!({"name": "Charlie", "role": "guest", "age": 40}),
];
let results = tql
.query(
&data,
"role not in ['admin', 'guest'] and age between 20 and 30",
)
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(results[0].get("name").and_then(|v| v.as_str()), Some("Bob"));
}
#[test]
fn test_between_with_type_hint() {
let tql = Tql::new();
let data = vec![
json!({"score": "50"}),
json!({"score": "75"}),
json!({"score": "100"}),
];
let results = tql
.query(&data, "score::number between 60 and 90")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_field_first_any_operator() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust"]}),
json!({"tags": ["javascript"]}),
json!({"tags": []}),
];
let results = tql
.query(&data, "tags any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_field_first_all_operator() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["admin", "admin"]}),
json!({"tags": ["admin", "user"]}),
json!({"tags": ["user"]}),
];
let results = tql
.query(&data, "tags all 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_field_first_none_operator() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust"]}),
json!({"tags": ["javascript"]}),
json!({"tags": []}),
];
let results = tql
.query(&data, "tags none 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 2); }
#[test]
fn test_not_field_first_any_operator() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust"]}),
json!({"tags": ["javascript"]}),
];
let results = tql
.query(&data, "not tags any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0]
.get("tags")
.and_then(|v| v.as_array())
.map(|a| a.len()),
Some(1)
);
}
#[test]
fn test_field_first_any_with_quoted_string() {
let tql = Tql::new();
let data = vec![
json!({"roles": ["admin", "editor"]}),
json!({"roles": ["viewer"]}),
];
let results = tql
.query(&data, r#"roles any "admin""#)
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_field_first_any_with_and() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python"], "active": true}),
json!({"tags": ["python"], "active": false}),
json!({"tags": ["javascript"], "active": true}),
];
let results = tql
.query(&data, "tags any 'python' and active = true")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_both_collection_syntaxes_equivalent() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust"]}),
json!({"tags": ["javascript"]}),
json!({"tags": []}),
];
let results_python = tql
.query(&data, "tags any 'python'")
.expect("Query should succeed");
let results_rust = tql
.query(&data, "any tags eq 'python'")
.expect("Query should succeed");
assert_eq!(results_python.len(), results_rust.len());
}
#[test]
fn test_is_null() {
let tql = Tql::new();
let data = vec![
json!({"value": null}),
json!({"value": "something"}),
json!({"other": "field"}), ];
let results = tql
.query(&data, "value is null")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_is_not_null() {
let tql = Tql::new();
let data = vec![json!({"value": null}), json!({"value": "something"})];
let results = tql
.query(&data, "value is not null")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("value").and_then(|v| v.as_str()),
Some("something")
);
}
#[test]
fn test_is_not_null_underscore() {
let tql = Tql::new();
let data = vec![json!({"value": null}), json!({"value": "something"})];
let results = tql
.query(&data, "value is_not null")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("value").and_then(|v| v.as_str()),
Some("something")
);
}
#[test]
fn test_value_in_field_basic() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust", "go"]}),
json!({"tags": ["javascript", "typescript"]}),
json!({"tags": []}),
];
let results = tql
.query(&data, "'python' in tags")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0]
.get("tags")
.and_then(|v| v.as_array())
.map(|a| a.len()),
Some(3)
);
}
#[test]
fn test_value_in_field_double_quotes() {
let tql = Tql::new();
let data = vec![
json!({"roles": ["admin", "user"]}),
json!({"roles": ["user"]}),
];
let results = tql
.query(&data, r#""admin" in roles"#)
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_value_in_nested_field() {
let tql = Tql::new();
let data = vec![
json!({"user": {"permissions": ["read", "write", "delete"]}}),
json!({"user": {"permissions": ["read"]}}),
];
let results = tql
.query(&data, "'write' in user.permissions")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_value_in_field_with_and() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python"], "active": true}),
json!({"tags": ["python"], "active": false}),
json!({"tags": ["rust"], "active": true}),
];
let results = tql
.query(&data, "'python' in tags and active = true")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_value_in_field_equivalent_to_any() {
let tql = Tql::new();
let data = vec![
json!({"categories": ["tech", "science", "art"]}),
json!({"categories": ["sports", "news"]}),
];
let results_in = tql
.query(&data, "'tech' in categories")
.expect("Query should succeed");
let results_any = tql
.query(&data, "categories any 'tech'")
.expect("Query should succeed");
assert_eq!(results_in.len(), results_any.len());
assert_eq!(results_in.len(), 1);
}
#[test]
fn test_value_in_field_numeric() {
let tql = Tql::new();
let data = vec![
json!({"codes": [100, 200, 300]}),
json!({"codes": [400, 500]}),
];
let results = tql
.query(&data, "200 in codes")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_symbolic_and_operator() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "active": true}),
json!({"name": "Bob", "active": false}),
json!({"name": "Charlie", "active": true}),
];
let results = tql
.query(&data, "name startswith 'A' && active = true")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("name").and_then(|v| v.as_str()),
Some("Alice")
);
}
#[test]
fn test_symbolic_or_operator() {
let tql = Tql::new();
let data = vec![
json!({"status": "active"}),
json!({"status": "pending"}),
json!({"status": "inactive"}),
];
let results = tql
.query(&data, "status = 'active' || status = 'pending'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_mixed_symbolic_and_keyword_operators() {
let tql = Tql::new();
let data = vec![
json!({"a": 1, "b": 2, "c": 3}),
json!({"a": 1, "b": 2, "c": 4}),
json!({"a": 2, "b": 2, "c": 3}),
];
let results = tql
.query(&data, "a = 1 && b = 2 or c = 4")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_symbolic_not_operator() {
let tql = Tql::new();
let data = vec![json!({"active": true}), json!({"active": false})];
let results = tql
.query(&data, "!(active = true)")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
assert_eq!(
results[0].get("active").and_then(|v| v.as_bool()),
Some(false)
);
}
#[test]
fn test_all_symbolic_operators_combined() {
let tql = Tql::new();
let data = vec![
json!({"x": 1, "y": 2, "z": 3}),
json!({"x": 1, "y": 3, "z": 3}),
json!({"x": 2, "y": 2, "z": 4}),
];
let results = tql
.query(&data, "(x = 1 && y = 2) || !(z = 3)")
.expect("Query should succeed");
assert_eq!(results.len(), 2); }
#[test]
fn test_value_in_fields_list_basic() {
let tql = Tql::new();
let data = vec![
json!({"role": "admin", "backup_role": "user"}),
json!({"role": "user", "backup_role": "admin"}),
json!({"role": "guest", "backup_role": "viewer"}),
];
let results = tql
.query(&data, "'admin' in [role, backup_role]")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_value_in_fields_list_single_field() {
let tql = Tql::new();
let data = vec![json!({"status": "active"}), json!({"status": "inactive"})];
let results = tql
.query(&data, "'active' in [status]")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_value_in_fields_list_no_match() {
let tql = Tql::new();
let data = vec![json!({"a": "x", "b": "y", "c": "z"})];
let results = tql
.query(&data, "'not_found' in [a, b, c]")
.expect("Query should succeed");
assert_eq!(results.len(), 0);
}
#[test]
fn test_value_in_fields_list_numeric() {
let tql = Tql::new();
let data = vec![
json!({"primary_code": 100, "secondary_code": 200}),
json!({"primary_code": 300, "secondary_code": 100}),
json!({"primary_code": 400, "secondary_code": 500}),
];
let results = tql
.query(&data, "100 in [primary_code, secondary_code]")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_value_in_fields_list_with_and() {
let tql = Tql::new();
let data = vec![
json!({"role": "admin", "backup_role": "user", "active": true}),
json!({"role": "user", "backup_role": "admin", "active": false}),
json!({"role": "guest", "backup_role": "viewer", "active": true}),
];
let results = tql
.query(&data, "'admin' in [role, backup_role] and active = true")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_eq_permutations() {
let tql = Tql::new();
let data = vec![
json!({"role": "admin"}),
json!({"role": "user"}),
json!({"role": "guest"}),
];
let results = tql
.query(&data, "role eq 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not role eq 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "role ne 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not role ne 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_relational_permutations() {
let tql = Tql::new();
let data = vec![json!({"age": 25}), json!({"age": 30}), json!({"age": 35})];
let results = tql.query(&data, "age > 30").expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not age > 30")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql.query(&data, "age >= 30").expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not age >= 30")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql.query(&data, "age < 30").expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not age < 30")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql.query(&data, "age <= 30").expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not age <= 30")
.expect("Query should succeed");
assert_eq!(results.len(), 1); }
#[test]
fn test_not_string_operator_permutations() {
let tql = Tql::new();
let data = vec![
json!({"desc": "Senior developer"}),
json!({"desc": "Junior developer"}),
json!({"desc": "Team lead"}),
];
let results = tql
.query(&data, "desc contains 'developer'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not desc contains 'developer'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "desc not contains 'developer'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not desc not contains 'developer'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "desc startswith 'Senior'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not desc startswith 'Senior'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "desc endswith 'lead'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not desc endswith 'lead'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_not_regexp_permutations() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice"}),
json!({"name": "Bob"}),
json!({"name": "Charlie"}),
];
let results = tql
.query(&data, "name regexp '^[AB]'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not name regexp '^[AB]'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "name not regexp '^[AB]'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not name not regexp '^[AB]'")
.expect("Query should succeed");
assert_eq!(results.len(), 2); }
#[test]
fn test_not_between_permutations() {
let tql = Tql::new();
let data = vec![json!({"age": 20}), json!({"age": 30}), json!({"age": 40})];
let results = tql
.query(&data, "age between [25, 35]")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not age between [25, 35]")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "age not between [25, 35]")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "age between 25 and 35")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not age between 25 and 35")
.expect("Query should succeed");
assert_eq!(results.len(), 2); }
#[test]
fn test_not_cidr_permutations() {
let tql = Tql::new();
let data = vec![
json!({"ip": "192.168.1.10"}),
json!({"ip": "10.0.0.5"}),
json!({"ip": "172.16.0.100"}),
];
let results = tql
.query(&data, "ip cidr '192.168.0.0/16'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not ip cidr '192.168.0.0/16'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "ip not cidr '192.168.0.0/16'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_not_existence_permutations() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "email": "alice@example.com"}),
json!({"name": "Bob"}),
];
let results = tql
.query(&data, "email exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not email exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "email not exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not email not exists")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_not_is_null_permutations() {
let tql = Tql::new();
let data = vec![
json!({"value": null}),
json!({"value": "something"}),
json!({"other": "field"}), ];
let results = tql
.query(&data, "value is null")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not value is null")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "value is not null")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not value is not null")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
}
#[test]
fn test_not_collection_permutations() {
let tql = Tql::new();
let data = vec![
json!({"tags": ["python", "rust"]}),
json!({"tags": ["javascript"]}),
json!({"tags": []}),
];
let results = tql
.query(&data, "tags any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not tags any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "tags !any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "tags not any 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "tags none 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not tags none 'python'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_complex_not_expressions() {
let tql = Tql::new();
let data = vec![
json!({"role": "admin", "age": 30, "active": true}),
json!({"role": "user", "age": 25, "active": false}),
json!({"role": "admin", "age": 35, "active": false}),
];
let results = tql
.query(&data, "not role eq 'admin' and not age > 30")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not role eq 'admin' or not active is true")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not (role eq 'admin' and age > 30)")
.expect("Query should succeed");
assert_eq!(results.len(), 2);
let results = tql
.query(&data, "not (role eq 'admin' or age < 27)")
.expect("Query should succeed");
assert_eq!(results.len(), 0); }
#[test]
fn test_multiple_negation() {
let tql = Tql::new();
let data = vec![json!({"role": "admin"}), json!({"role": "user"})];
let results = tql
.query(&data, "not not role eq 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not not not role eq 'admin'")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
let results = tql
.query(&data, "not (not (role eq 'admin'))")
.expect("Query should succeed");
assert_eq!(results.len(), 1);
}
#[test]
fn test_stats_without_pipe_prefix() {
let tql = Tql::new();
let data = vec![
json!({"category": "A", "value": 10}),
json!({"category": "A", "value": 20}),
json!({"category": "B", "value": 30}),
];
let result = tql
.evaluate_stats(&data, "stats count(*)")
.expect("Should parse stats without pipe");
assert!(result.get("results").is_some() || result.get("value").is_some());
}
#[test]
fn test_stats_without_pipe_with_aggregations() {
let tql = Tql::new();
let data = vec![
json!({"value": 10}),
json!({"value": 20}),
json!({"value": 30}),
];
let result = tql
.evaluate_stats(&data, "stats sum(value), avg(value)")
.expect("Should parse multiple stats");
assert!(result.get("results").is_some() || result.get("value").is_some());
}
#[test]
fn test_stats_without_pipe_with_group_by() {
let tql = Tql::new();
let data = vec![
json!({"category": "A", "value": 10}),
json!({"category": "A", "value": 20}),
json!({"category": "B", "value": 30}),
];
let result = tql
.evaluate_stats(&data, "stats sum(value) by category")
.expect("Should parse stats with group by");
assert!(result.get("results").is_some() || result.get("value").is_some());
}
#[test]
fn test_python_style_tags_any_value() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
json!({"name": "Charlie", "tags": []}),
];
let results = tql
.query(&data, "tags any 'python'")
.expect("Should parse Python-style collection");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Alice");
}
#[test]
fn test_python_style_tags_any_eq_value() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
];
let results = tql
.query(&data, "tags any eq 'python'")
.expect("Should parse Python-style collection with eq");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Alice");
}
#[test]
fn test_python_style_tags_any_contains() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
];
let results = tql
.query(&data, "tags any contains 'py'")
.expect("Should parse Python-style with contains");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Alice");
}
#[test]
fn test_python_style_scores_all_gt() {
let tql = Tql::new();
let data = vec![
json!({"name": "A", "scores": [80, 90, 85]}),
json!({"name": "B", "scores": [50, 60, 70]}),
json!({"name": "C", "scores": [90, 95, 100]}),
];
let results = tql
.query(&data, "scores all gt 75")
.expect("Should parse Python-style all gt");
assert_eq!(results.len(), 2); }
#[test]
fn test_python_style_tags_none_eq() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
json!({"name": "Charlie", "tags": []}),
];
let results = tql
.query(&data, "tags none eq 'python'")
.expect("Should parse Python-style none eq");
assert_eq!(results.len(), 2); }
#[test]
fn test_unquoted_cidr_notation() {
let tql = Tql::new();
let data = vec![
json!({"ip": "192.168.1.100"}),
json!({"ip": "10.0.0.5"}),
json!({"ip": "192.168.50.1"}),
];
let results = tql
.query(&data, "ip cidr 192.168.0.0/16")
.expect("Should parse unquoted CIDR");
assert_eq!(results.len(), 2); }
#[test]
fn test_unquoted_cidr_not_operator() {
let tql = Tql::new();
let data = vec![
json!({"ip": "192.168.1.100"}),
json!({"ip": "10.0.0.5"}),
json!({"ip": "192.168.50.1"}),
];
let results = tql
.query(&data, "ip not cidr 192.168.0.0/16")
.expect("Should parse unquoted not cidr");
assert_eq!(results.len(), 1); assert_eq!(results[0]["ip"], "10.0.0.5");
}
#[test]
fn test_both_stats_syntaxes_work() {
let tql = Tql::new();
let data = vec![json!({"value": 10}), json!({"value": 20})];
let results1 = tql
.evaluate_stats(&data, "| stats count(*)")
.expect("Should work with pipe");
let results2 = tql
.evaluate_stats(&data, "stats count(*)")
.expect("Should work without pipe");
assert_eq!(results1[0]["count"], results2[0]["count"]);
}
#[test]
fn test_both_collection_syntaxes_work() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
];
let results1 = tql
.query(&data, "any tags eq 'python'")
.expect("Rust-style should work");
let results2 = tql
.query(&data, "tags any 'python'")
.expect("Python-style should work");
assert_eq!(results1.len(), results2.len());
assert_eq!(results1[0]["name"], results2[0]["name"]);
}
#[test]
fn test_python_style_collection_with_logical_operators() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"], "active": true}),
json!({"name": "Bob", "tags": ["java"], "active": true}),
json!({"name": "Charlie", "tags": ["python"], "active": false}),
];
let results = tql
.query(&data, "tags any 'python' AND active = true")
.expect("Should work with AND");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Alice");
}
#[test]
fn test_python_style_not_any() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
];
let results = tql
.query(&data, "tags not any 'python'")
.expect("Should parse not any");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Bob");
}
#[test]
fn test_python_style_bang_any() {
let tql = Tql::new();
let data = vec![
json!({"name": "Alice", "tags": ["python", "rust"]}),
json!({"name": "Bob", "tags": ["java"]}),
];
let results = tql
.query(&data, "tags !any 'python'")
.expect("Should parse !any");
assert_eq!(results.len(), 1);
assert_eq!(results[0]["name"], "Bob");
}