#![allow(clippy::unwrap_used, clippy::panic)]
use fraiseql_core::db::where_clause::{WhereClause, WhereOperator};
use serde_json::json;
#[test]
fn test_where_null_equality_is_null() {
let clause = WhereClause::Field {
path: vec!["field".to_string()],
operator: WhereOperator::Eq,
value: json!(null),
};
match clause {
WhereClause::Field {
value, operator, ..
} => {
assert_eq!(value, json!(null));
assert_eq!(operator, WhereOperator::Eq);
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_is_null_operator() {
let clause = WhereClause::Field {
path: vec!["optional_field".to_string()],
operator: WhereOperator::IsNull,
value: json!(true), };
match clause {
WhereClause::Field {
value, operator, ..
} => {
assert_eq!(value, json!(true));
assert_eq!(operator, WhereOperator::IsNull);
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_is_not_null_operator() {
let clause = WhereClause::Field {
path: vec!["required_field".to_string()],
operator: WhereOperator::IsNull,
value: json!(false), };
match clause {
WhereClause::Field {
value, operator, ..
} => {
assert_eq!(value, json!(false));
assert_eq!(operator, WhereOperator::IsNull);
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_complex_and_with_null() {
let and_clause = WhereClause::And(vec![
WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: json!("active"),
},
WhereClause::Field {
path: vec!["deleted_at".to_string()],
operator: WhereOperator::IsNull,
value: json!(true),
},
]);
match and_clause {
WhereClause::And(clauses) => {
assert_eq!(clauses.len(), 2);
},
_ => panic!("Should be And variant"),
}
}
#[test]
fn test_where_complex_or_with_null() {
let or_clause = WhereClause::Or(vec![
WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: json!("inactive"),
},
WhereClause::Field {
path: vec!["archived_at".to_string()],
operator: WhereOperator::IsNull,
value: json!(false), },
]);
match or_clause {
WhereClause::Or(clauses) => {
assert_eq!(clauses.len(), 2);
},
_ => panic!("Should be Or variant"),
}
}
#[test]
fn test_where_not_with_null() {
let not_clause = WhereClause::Not(Box::new(WhereClause::Field {
path: vec!["value".to_string()],
operator: WhereOperator::IsNull,
value: json!(true),
}));
match not_clause {
WhereClause::Not(inner) => match *inner {
WhereClause::Field { operator, .. } => {
assert_eq!(operator, WhereOperator::IsNull);
},
_ => panic!("Inner should be Field variant"),
},
_ => panic!("Should be Not variant"),
}
}
#[test]
fn test_where_null_with_different_operators() {
let operators = vec![
WhereOperator::Eq,
WhereOperator::Neq,
WhereOperator::Gt,
WhereOperator::Gte,
WhereOperator::Lt,
WhereOperator::Lte,
WhereOperator::Contains,
];
for op in operators {
let clause = WhereClause::Field {
path: vec!["field".to_string()],
operator: op.clone(),
value: json!(null),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(null));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_where_null_in_nested_paths() {
let nested_clause = WhereClause::Field {
path: vec![
"user".to_string(),
"profile".to_string(),
"middle_name".to_string(),
],
operator: WhereOperator::IsNull,
value: json!(true),
};
match nested_clause {
WhereClause::Field { path, value, .. } => {
assert_eq!(path.len(), 3);
assert_eq!(path[0], "user");
assert_eq!(path[1], "profile");
assert_eq!(path[2], "middle_name");
assert_eq!(value, json!(true));
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_null_with_array_operators() {
let array_clause = WhereClause::Field {
path: vec!["tags".to_string()],
operator: WhereOperator::In,
value: json!([1, 2, null, 4]),
};
match array_clause {
WhereClause::Field { value, .. } => {
let arr = value.as_array().unwrap();
assert_eq!(arr.len(), 4);
assert!(arr[2].is_null());
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_null_three_valued_logic_and() {
let test_cases = vec![
(true, true, "TRUE AND UNKNOWN = UNKNOWN"),
(true, false, "TRUE AND FALSE = FALSE"),
(false, true, "FALSE AND UNKNOWN = FALSE"), (false, false, "FALSE AND FALSE = FALSE"),
];
for (left_true, right_has_null, _description) in test_cases {
let left_value = if left_true {
json!("active")
} else {
json!("inactive")
};
let right_value = if right_has_null {
json!(null)
} else {
json!(true)
};
let and_clause = WhereClause::And(vec![
WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: left_value,
},
WhereClause::Field {
path: vec!["deleted_at".to_string()],
operator: WhereOperator::IsNull,
value: right_value,
},
]);
match and_clause {
WhereClause::And(clauses) => {
assert_eq!(clauses.len(), 2);
},
_ => panic!("Should be And variant"),
}
}
}
#[test]
fn test_where_null_three_valued_logic_or() {
let test_cases = vec![
(true, true, "TRUE OR UNKNOWN = TRUE"), (true, false, "TRUE OR FALSE = TRUE"), (false, true, "FALSE OR UNKNOWN = UNKNOWN"),
(false, false, "FALSE OR FALSE = FALSE"),
];
for (left_true, right_has_null, _description) in test_cases {
let left_value = if left_true {
json!("active")
} else {
json!("inactive")
};
let right_value = if right_has_null {
json!(null)
} else {
json!(true)
};
let or_clause = WhereClause::Or(vec![
WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: left_value,
},
WhereClause::Field {
path: vec!["deleted_at".to_string()],
operator: WhereOperator::IsNull,
value: right_value,
},
]);
match or_clause {
WhereClause::Or(clauses) => {
assert_eq!(clauses.len(), 2);
},
_ => panic!("Should be Or variant"),
}
}
}
#[test]
fn test_where_null_not_in_operator() {
let nin_clause = WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Nin,
value: json!(["deleted", "archived", null]),
};
match nin_clause {
WhereClause::Field { value, .. } => {
let arr = value.as_array().unwrap();
assert_eq!(arr.len(), 3);
assert!(arr[2].is_null());
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_where_null_comparison_null_handling() {
let clauses = vec![
(json!(null), "null value"),
(json!(false), "false value"),
(json!(0), "zero value"),
(json!(""), "empty string"),
];
for (value, description) in clauses {
let clause = WhereClause::Field {
path: vec!["field".to_string()],
operator: WhereOperator::Eq,
value: value.clone(),
};
match clause {
WhereClause::Field { value: v, .. } => {
assert_eq!(v, value, "{} should be preserved exactly", description);
},
_ => panic!("Should be Field variant"),
}
}
assert_ne!(json!(null), json!(false));
assert_ne!(json!(null), json!(0));
assert_ne!(json!(null), json!(""));
assert_ne!(json!(false), json!(0));
}
#[test]
fn test_where_null_in_complex_nested_logic() {
let complex_clause = WhereClause::And(vec![
WhereClause::Or(vec![
WhereClause::Field {
path: vec!["status".to_string()],
operator: WhereOperator::Eq,
value: json!("active"),
},
WhereClause::Field {
path: vec!["trial_expires".to_string()],
operator: WhereOperator::IsNull,
value: json!(false),
},
]),
WhereClause::And(vec![
WhereClause::Field {
path: vec!["deleted_at".to_string()],
operator: WhereOperator::IsNull,
value: json!(true),
},
WhereClause::Field {
path: vec!["archived_at".to_string()],
operator: WhereOperator::IsNull,
value: json!(true),
},
]),
]);
match complex_clause {
WhereClause::And(outer_clauses) => {
assert_eq!(outer_clauses.len(), 2);
match &outer_clauses[0] {
WhereClause::Or(inner_or) => assert_eq!(inner_or.len(), 2),
_ => panic!("First should be Or"),
}
match &outer_clauses[1] {
WhereClause::And(inner_and) => assert_eq!(inner_and.len(), 2),
_ => panic!("Second should be And"),
}
},
_ => panic!("Should be And variant"),
}
}