use std::path::Path;
use rrgen::RRgen;
use serde_json::json;
use crate::{
get_mappings, infer::parse_field_type, model, render_template, AppInfo, Error, GenerateResults,
Result, ScaffoldKind,
};
pub fn generate(
rrgen: &RRgen,
name: &str,
with_tz: bool,
fields: &[(String, String)],
kind: &ScaffoldKind,
appinfo: &AppInfo,
) -> Result<GenerateResults> {
let mut gen_result = model::generate(rrgen, name, with_tz, fields, appinfo)?;
let mut columns = Vec::new();
for (fname, ftype) in fields {
if model::IGNORE_FIELDS.contains(&fname.as_str()) {
tracing::warn!(
field = fname,
"note that a redundant field was specified, it is already generated automatically"
);
continue;
}
let field_type = parse_field_type(ftype)?;
match field_type {
crate::infer::FieldType::Reference => {
let col_name = format!("{fname}_id");
columns.push((col_name, "i32".to_string(), "Integer".to_string()));
}
crate::infer::FieldType::ReferenceWithCustomField(refname) => {
columns.push((refname.clone(), "i32".to_string(), "Integer".to_string()));
}
crate::infer::FieldType::NullableReference => {
let col_name = format!("{fname}_id");
columns.push((col_name, "i32".to_string(), "IntegerNull".to_string()));
}
crate::infer::FieldType::NullableReferenceWithCustomField(refname) => {
columns.push((
refname.clone(),
"i32".to_string(),
"IntegerNull".to_string(),
));
}
crate::infer::FieldType::Type(ftype) => {
let mappings = get_mappings();
let rust_type = mappings.rust_field(ftype.as_str())?;
columns.push((fname.clone(), rust_type.to_string(), ftype));
}
crate::infer::FieldType::TypeWithParameters(ftype, params) => {
let mappings = get_mappings();
let rust_type = mappings.rust_field_with_params(ftype.as_str(), ¶ms)?;
let arity = mappings.col_type_arity(ftype.as_str()).unwrap_or_default();
if params.len() != arity {
return Err(Error::Message(format!(
"type: `{ftype}` requires specifying {arity} parameters, but only {} were \
given (`{}`).",
params.len(),
params.join(",")
)));
}
columns.push((fname.clone(), rust_type.to_string(), ftype));
}
}
}
let vars = json!({"name": name, "columns": columns, "pkg_name": appinfo.app_name});
match kind {
ScaffoldKind::Api => {
let res = render_template(rrgen, Path::new("scaffold/api"), &vars)?;
gen_result.rrgen.extend(res.rrgen);
gen_result.local_templates.extend(res.local_templates);
}
ScaffoldKind::Html => {
let res = render_template(rrgen, Path::new("scaffold/html"), &vars)?;
gen_result.rrgen.extend(res.rrgen);
gen_result.local_templates.extend(res.local_templates);
}
ScaffoldKind::Htmx => {
let res = render_template(rrgen, Path::new("scaffold/htmx"), &vars)?;
gen_result.rrgen.extend(res.rrgen);
gen_result.local_templates.extend(res.local_templates);
}
}
Ok(gen_result)
}