#![allow(clippy::unwrap_used)]
use fraiseql_core::db::where_clause::{WhereClause, WhereOperator};
use serde_json::json;
#[test]
fn test_ltree_valid_path_formats() {
let valid_paths = vec![
"a",
"a.b",
"a.b.c",
"a.b.c.d.e",
"org.company.dept.team",
"level1.level2.level3",
"simple",
"CamelCase",
"with_underscores",
"with-dashes",
"123",
"a1.b2.c3",
];
for path in valid_paths {
let operators = vec![
WhereOperator::AncestorOf,
WhereOperator::DescendantOf,
WhereOperator::MatchesLquery,
];
for op in operators {
let clause = WhereClause::Field {
path: vec!["hierarchy".to_string()],
operator: op.clone(),
value: json!(path),
};
match clause {
WhereClause::Field {
value, operator, ..
} => {
assert_eq!(value, json!(path), "Path {} should be preserved", path);
assert_eq!(operator, op);
},
_ => panic!("Should be Field variant"),
}
}
}
}
#[test]
fn test_ltree_long_path_preservation() {
let long_path_100 = (0..100).map(|i| format!("level{}", i)).collect::<Vec<_>>().join(".");
let long_paths: Vec<&str> = vec![
"a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", "level1.level2.level3.level4.level5.level6.level7.level8.level9.level10", ];
for path in &long_paths {
let clause = WhereClause::Field {
path: vec!["tree".to_string()],
operator: WhereOperator::AncestorOf,
value: json!(path),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(path));
let component_count = path.split('.').count();
let json_str = value.as_str().unwrap();
let json_component_count = json_str.split('.').count();
assert_eq!(json_component_count, component_count);
},
_ => panic!("Should be Field variant"),
}
}
let clause = WhereClause::Field {
path: vec!["tree".to_string()],
operator: WhereOperator::AncestorOf,
value: json!(&long_path_100),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(&long_path_100));
let component_count = long_path_100.split('.').count();
let json_str = value.as_str().unwrap();
let json_component_count = json_str.split('.').count();
assert_eq!(json_component_count, component_count);
},
_ => panic!("Should be Field variant"),
}
}
#[test]
fn test_ltree_special_characters_in_labels() {
let label_types = vec![
"all_lowercase",
"ALL_UPPERCASE",
"Mixed_Case",
"with-dashes",
"numbers123",
"123numbers",
"_leading_underscore",
"trailing_underscore_",
"_both_",
"multi_under_score",
"multi-dash-label",
"mixed_under-dash",
];
for label in label_types {
let clause = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::DescendantOf,
value: json!(label),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(label));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_queries_lquery_patterns() {
let lquery_patterns = vec![
"a", "a.b.c", "a.*", "*.b", "a.*.c", "a|b", "a.b|c", "!a", "{a,b,c}", "a.{b,c,d}.e", ];
for pattern in lquery_patterns {
let clause = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::MatchesLquery,
value: json!(pattern),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(pattern));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_depth_operators() {
let depths = vec![0, 1, 2, 5, 10, 100, 1000];
for depth in depths {
let operators = vec![
WhereOperator::DepthEq,
WhereOperator::DepthNeq,
WhereOperator::DepthGt,
WhereOperator::DepthGte,
WhereOperator::DepthLt,
WhereOperator::DepthLte,
];
for op in operators {
let clause = WhereClause::Field {
path: vec!["tree".to_string()],
operator: op.clone(),
value: json!(depth),
};
match clause {
WhereClause::Field {
value, operator, ..
} => {
assert_eq!(value, json!(depth));
assert_eq!(operator, op);
},
_ => panic!("Should be Field variant"),
}
}
}
}
#[test]
fn test_ltree_path_with_numbers() {
let numeric_paths = vec![
"0",
"1",
"123",
"0.0.0",
"1.2.3.4.5",
"100.200.300",
"9999.9999.9999",
];
for path in numeric_paths {
let clause = WhereClause::Field {
path: vec!["numeric_path".to_string()],
operator: WhereOperator::AncestorOf,
value: json!(path),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(path));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_empty_path_handling() {
let edge_paths = vec![
"", "a", ".", "a.", ".a", "a..b", ];
for path in edge_paths {
let clause = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::MatchesLquery,
value: json!(path),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(path));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_case_sensitivity() {
let case_variants = vec![
("Org", "ORG", "org"), ("Company", "COMPANY", "company"),
("Department", "DEPARTMENT", "department"),
];
for (variant1, variant2, variant3) in case_variants {
let clause1 = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::DescendantOf,
value: json!(variant1),
};
let clause2 = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::DescendantOf,
value: json!(variant2),
};
let clause3 = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::DescendantOf,
value: json!(variant3),
};
match (clause1, clause2, clause3) {
(
WhereClause::Field { value: v1, .. },
WhereClause::Field { value: v2, .. },
WhereClause::Field { value: v3, .. },
) => {
assert_eq!(v1, json!(variant1));
assert_eq!(v2, json!(variant2));
assert_eq!(v3, json!(variant3));
assert_ne!(v1, v2);
assert_ne!(v2, v3);
},
_ => panic!("Should be Field variants"),
}
}
}
#[test]
fn test_ltree_unicode_labels() {
let unicode_paths = vec![
"café",
"naïve",
"resumé",
"piñata",
"Москва", "北京", "東京", "🏢.company", ];
for path in unicode_paths {
let clause = WhereClause::Field {
path: vec!["path".to_string()],
operator: WhereOperator::AncestorOf,
value: json!(path),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(path));
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_operators_all_variants() {
let all_ltree_operators = vec![
(WhereOperator::AncestorOf, "AncestorOf"),
(WhereOperator::DescendantOf, "DescendantOf"),
(WhereOperator::MatchesLquery, "MatchesLquery"),
(WhereOperator::MatchesLtxtquery, "MatchesLtxtquery"),
(WhereOperator::MatchesAnyLquery, "MatchesAnyLquery"),
(WhereOperator::DepthEq, "DepthEq"),
(WhereOperator::DepthNeq, "DepthNeq"),
(WhereOperator::DepthGt, "DepthGt"),
(WhereOperator::DepthGte, "DepthGte"),
(WhereOperator::DepthLt, "DepthLt"),
(WhereOperator::DepthLte, "DepthLte"),
(WhereOperator::Lca, "Lca"), ];
for (operator, _name) in all_ltree_operators {
let clause = WhereClause::Field {
path: vec!["path".to_string()],
operator: operator.clone(),
value: json!("test_value"),
};
match clause {
WhereClause::Field { operator: op, .. } => {
assert_eq!(op, operator);
},
_ => panic!("Should be Field variant"),
}
}
}
#[test]
fn test_ltree_path_depth_constraints() {
for depth in [1, 10, 100, 1000] {
let components: Vec<String> = (0..depth).map(|i| format!("l{}", i)).collect();
let path = components.join(".");
let clause = WhereClause::Field {
path: vec!["tree".to_string()],
operator: WhereOperator::AncestorOf,
value: json!(&path),
};
match clause {
WhereClause::Field { value, .. } => {
assert_eq!(value, json!(&path));
let actual_depth = value.as_str().unwrap().split('.').count();
assert_eq!(actual_depth, depth);
},
_ => panic!("Should be Field variant"),
}
}
}