use crate::database::introspection::Schema;
use crate::generators::rust::casing;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Names {
pub module: String,
pub type_name: String,
}
pub fn resolve(schema: &Schema) -> Vec<Names> {
let singular: Vec<String> = schema
.tables
.iter()
.map(|table| casing::singularize(&table.name))
.collect();
schema
.tables
.iter()
.zip(&singular)
.map(|(table, candidate)| {
let contested = singular.iter().filter(|other| *other == candidate).count() > 1;
let stem = if contested { &table.name } else { candidate };
casing::to_snake(stem)
})
.collect::<Vec<_>>()
.into_iter()
.scan(reserved(), |taken: &mut Vec<String>, module| {
let module = unique(module, taken);
taken.push(module.clone());
Some(Names {
type_name: casing::to_pascal(&module),
module,
})
})
.collect()
}
fn reserved() -> Vec<String> {
vec!["enums".to_string(), "api".to_string()]
}
fn unique(candidate: String, taken: &[String]) -> String {
if !taken.contains(&candidate) {
return candidate;
}
(2..)
.map(|index| format!("{candidate}_{index}"))
.find(|suffixed| !taken.contains(suffixed))
.expect("an unbounded range always yields an unused name")
}