use super::{type_map, FieldDef};
pub fn gen(
pascal: &str,
snake: &str,
fields: &[FieldDef],
id: Option<&str>,
soft_delete: bool,
timestamps: bool,
) -> String {
let pk_use = super::pk_use_import(id);
let pk_type = super::pk_rust_type(id);
let mut needs_chrono = timestamps || soft_delete;
let mut needs_json = false;
for f in fields {
match f.field_type.as_str() {
"datetime" | "date" => needs_chrono = true,
"json" => needs_json = true,
_ => {}
}
}
let mut use_lines = String::new();
use_lines.push_str(pk_use);
use_lines.push_str("use rok_orm::Model;\n");
use_lines.push_str("use serde::{Deserialize, Serialize};\n");
if needs_chrono {
use_lines.push_str("use chrono::{DateTime, Utc};\n");
}
if needs_json {
use_lines.push_str("use serde_json::Value;\n");
}
let mut orm_attrs = Vec::new();
let table = format!("{snake}s");
orm_attrs.push(format!("table = \"{table}\""));
if let Some(it) = id {
orm_attrs.push(format!("id = \"{it}\""));
}
if timestamps {
orm_attrs.push("timestamps".to_string());
}
if soft_delete {
orm_attrs.push("soft_delete".to_string());
}
let orm_attr_line = format!("#[rok_orm({})]\n", orm_attrs.join(", "));
let mut field_lines = format!(" pub id: {},\n", pk_type);
for f in fields {
let tm = type_map(&f.field_type);
let base_t = match f.field_type.as_str() {
"datetime" => "DateTime<Utc>",
"json" => "Value",
_ => tm.rust_type,
};
let rust_t = if f.optional {
format!("Option<{base_t}>")
} else {
base_t.to_string()
};
field_lines.push_str(&format!(" pub {}: {},\n", f.name, rust_t));
}
if timestamps {
field_lines.push_str(" pub created_at: DateTime<Utc>,\n");
field_lines.push_str(" pub updated_at: DateTime<Utc>,\n");
}
if soft_delete {
field_lines.push_str(" pub deleted_at: Option<DateTime<Utc>>,\n");
}
format!(
"{use_lines}\n#[derive(Debug, Clone, Model, Serialize, Deserialize, sqlx::FromRow)]\n{orm_attr_line}pub struct {pascal} {{\n{field_lines}}}\n"
)
}