#![allow(clippy::unwrap_used, clippy::panic)]
use fraiseql_cli::schema::{converter::SchemaConverter, intermediate::IntermediateSchema};
use fraiseql_core::schema::NamingConvention;
#[test]
fn test_rich_filter_compilation_pipeline() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
assert!(
compiled.input_types.iter().any(|t| t.name == "EmailAddressWhereInput"),
"EmailAddressWhereInput should be generated"
);
assert!(
compiled.input_types.iter().any(|t| t.name == "CoordinatesWhereInput"),
"CoordinatesWhereInput should be generated"
);
let email_where = compiled
.input_types
.iter()
.find(|t| t.name == "EmailAddressWhereInput")
.expect("EmailAddressWhereInput should exist");
assert!(email_where.metadata.is_some(), "EmailAddressWhereInput should have metadata");
let metadata = email_where.metadata.as_ref().unwrap();
assert!(metadata.get("operators").is_some(), "Metadata should contain operators");
let operators = metadata["operators"].as_object().unwrap();
assert!(operators.contains_key("domainEq"), "Should have domainEq operator template");
let domain_eq = operators["domainEq"].as_object().unwrap();
for db in &["postgres", "mysql", "sqlite", "sqlserver"] {
assert!(domain_eq.contains_key(*db), "Should have {} template for domainEq", db);
}
assert!(compiled.security.is_some(), "Security section should exist for lookup data");
let security = compiled.security.as_ref().unwrap();
assert!(
security.additional.contains_key("lookup_data"),
"Lookup data should be embedded"
);
let lookup = security.additional["lookup_data"].as_object().unwrap();
assert!(lookup.contains_key("countries"), "Countries lookup should be present");
assert!(lookup.contains_key("currencies"), "Currencies lookup should be present");
assert!(lookup.contains_key("timezones"), "Timezones lookup should be present");
assert!(lookup.contains_key("languages"), "Languages lookup should be present");
}
#[test]
fn test_all_rich_types_generate_where_input() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
assert_eq!(
compiled.input_types.len(),
49,
"Should have 49 rich type WhereInput definitions"
);
let expected_types = vec![
"EmailAddressWhereInput",
"PhoneNumberWhereInput",
"URLWhereInput",
"VINWhereInput",
"IBANWhereInput",
"CountryCodeWhereInput",
"CoordinatesWhereInput",
"DateRangeWhereInput",
"DurationWhereInput",
"CurrencyCodeWhereInput",
];
for expected in expected_types {
assert!(
compiled.input_types.iter().any(|t| t.name == expected),
"Should have {} type",
expected
);
}
}
#[test]
fn test_where_input_fields_include_standard_operators() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
let email_where = compiled
.input_types
.iter()
.find(|t| t.name == "EmailAddressWhereInput")
.expect("EmailAddressWhereInput should exist");
let field_names: Vec<_> = email_where.fields.iter().map(|f| &f.name).collect();
assert!(field_names.contains(&&"eq".to_string()), "Should have eq operator");
assert!(field_names.contains(&&"neq".to_string()), "Should have neq operator");
assert!(field_names.contains(&&"contains".to_string()), "Should have contains operator");
assert!(field_names.contains(&&"isnull".to_string()), "Should have isnull operator");
assert!(field_names.contains(&&"domainEq".to_string()), "Should have domainEq operator");
assert!(field_names.contains(&&"domainIn".to_string()), "Should have domainIn operator");
assert!(
field_names.contains(&&"domainEndswith".to_string()),
"Should have domainEndswith operator"
);
assert!(email_where.fields.len() >= 10, "Should have at least 10 fields");
}
#[test]
fn test_sql_templates_cover_all_databases() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
let types_to_check = vec![
"EmailAddressWhereInput",
"VINWhereInput",
"CoordinatesWhereInput",
];
for type_name in types_to_check {
let where_input = compiled
.input_types
.iter()
.find(|t| t.name == type_name)
.unwrap_or_else(|| panic!("{} should exist", type_name));
let metadata = where_input
.metadata
.as_ref()
.unwrap_or_else(|| panic!("{} should have metadata", type_name));
let operators = metadata["operators"].as_object().unwrap();
for (op_name, templates) in operators {
let db_templates = templates.as_object().unwrap();
for db in &["postgres", "mysql", "sqlite", "sqlserver"] {
assert!(
db_templates.contains_key(*db),
"{}/{} should have {} template",
type_name,
op_name,
db
);
}
}
}
}
#[test]
fn test_lookup_data_integrity() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
let security = compiled.security.as_ref().expect("Security section should exist");
let lookup = security.additional["lookup_data"]
.as_object()
.expect("Lookup data should be an object");
let countries = lookup["countries"].as_object().expect("Countries should exist");
assert!(countries.len() >= 10, "Should have at least 10 countries");
if let Some(us) = countries.get("US") {
let us_obj = us.as_object().unwrap();
assert!(us_obj.contains_key("continent"), "US should have continent");
assert!(us_obj.contains_key("in_eu"), "US should have in_eu");
assert!(us_obj.contains_key("in_schengen"), "US should have in_schengen");
}
let currencies = lookup["currencies"].as_object().expect("Currencies should exist");
assert!(currencies.len() >= 5, "Should have at least 5 currencies");
if let Some(usd) = currencies.get("USD") {
let usd_obj = usd.as_object().unwrap();
assert!(usd_obj.contains_key("symbol"), "USD should have symbol");
assert!(usd_obj.contains_key("decimal_places"), "USD should have decimal_places");
}
let timezones = lookup["timezones"].as_object().expect("Timezones should exist");
assert!(timezones.len() >= 5, "Should have at least 5 timezones");
let languages = lookup["languages"].as_object().expect("Languages should exist");
assert!(languages.len() >= 5, "Should have at least 5 languages");
}
#[test]
fn test_compiled_schema_is_valid() {
let intermediate = IntermediateSchema {
security: None,
version: "2.0.0".to_string(),
types: vec![],
enums: vec![],
input_types: vec![],
interfaces: vec![],
unions: vec![],
queries: vec![],
mutations: vec![],
subscriptions: vec![],
fragments: None,
directives: None,
fact_tables: None,
aggregate_queries: None,
observers: None,
custom_scalars: None,
observers_config: None,
subscriptions_config: None,
validation_config: None,
federation_config: None,
debug_config: None,
mcp_config: None,
rest_config: None,
query_defaults: None,
naming_convention: NamingConvention::default(),
session_variables: None,
hierarchies_config: None,
};
let compiled = SchemaConverter::convert(intermediate).expect("Compilation should succeed");
assert!(
!compiled.types.is_empty() || !compiled.input_types.is_empty(),
"Compiled schema should have types or input types"
);
assert!(!compiled.input_types.is_empty(), "Should have input types");
for where_input in &compiled.input_types {
assert!(!where_input.name.is_empty(), "Type name should not be empty");
assert!(
where_input.name.ends_with("WhereInput"),
"Type {} should end with 'WhereInput'",
where_input.name
);
assert!(!where_input.fields.is_empty(), "Type {} should have fields", where_input.name);
for field in &where_input.fields {
assert!(!field.name.is_empty(), "Field name should not be empty");
assert!(!field.field_type.is_empty(), "Field type should not be empty");
}
}
}