use fraiseql_core::schema::QueryDefinition;
use super::{Diagnostic, DiagnosticLevel};
pub(super) fn derive_resource_name(
type_name: &str,
queries: &[&QueryDefinition],
diagnostics: &mut Vec<Diagnostic>,
) -> String {
if let Some(list_q) = queries.iter().find(|q| q.returns_list) {
return list_q.name.clone();
}
if let Some(q) = queries.first() {
if let Some(ref sql) = q.sql_source {
let stripped = strip_cqrs_prefix(sql);
if !stripped.is_empty() {
return simple_pluralize(stripped);
}
}
}
let base = type_name_to_snake(type_name);
let name = simple_pluralize(&base);
diagnostics.push(Diagnostic {
level: DiagnosticLevel::Info,
message: format!(
"No list query for type '{type_name}'; derived resource name '{name}' from type name"
),
});
name
}
pub(super) fn strip_cqrs_prefix(name: &str) -> &str {
name.strip_prefix("v_")
.or_else(|| name.strip_prefix("tv_"))
.or_else(|| name.strip_prefix("tb_"))
.unwrap_or(name)
}
pub(super) fn type_name_to_snake(name: &str) -> String {
let mut result = String::with_capacity(name.len() + 4);
for (i, ch) in name.chars().enumerate() {
if ch.is_uppercase() && i > 0 {
result.push('_');
}
result.push(ch.to_ascii_lowercase());
}
result
}
pub(super) fn simple_pluralize(word: &str) -> String {
if word.ends_with("ics") || word.ends_with("ies") {
return word.to_string();
}
if word.ends_with("ss")
|| word.ends_with('x')
|| word.ends_with("ch")
|| word.ends_with("sh")
|| word.ends_with('s')
{
format!("{word}es")
} else if word.ends_with('y')
&& !word.ends_with("ey")
&& !word.ends_with("ay")
&& !word.ends_with("oy")
{
format!("{}ies", &word[..word.len() - 1])
} else {
format!("{word}s")
}
}
pub(super) fn derive_action_name(mutation_name: &str, type_name: &str) -> String {
let lower_mutation = mutation_name.to_ascii_lowercase();
let lower_type = type_name.to_ascii_lowercase();
let without_type = if let Some(pos) = lower_mutation.find(&lower_type) {
let before = &mutation_name[..pos];
let after = &mutation_name[pos + type_name.len()..];
format!("{before}{after}")
} else {
mutation_name.to_string()
};
camel_to_kebab(&without_type)
}
pub(super) fn camel_to_kebab(s: &str) -> String {
let mut result = String::with_capacity(s.len() + 4);
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() && i > 0 {
result.push('-');
}
result.push(ch.to_ascii_lowercase());
}
if result.starts_with('-') {
result.remove(0);
}
result
}