use super::ddl::{Schema, SqlType, Table};
use crate::commands::scaffold_common::pascal_identifier_from_snake;
pub(crate) fn render(schema: &Schema, header: &str, type_suffix: &str) -> String {
let mut out = String::new();
out.push_str(header);
let mut first = true;
for (table_name, table) in schema.tables() {
if !first {
out.push('\n');
}
first = false;
out.push_str(&render_table(table_name, table, type_suffix));
}
out
}
fn render_table(table_name: &str, table: &Table, type_suffix: &str) -> String {
let type_name = format!("{}{type_suffix}", pascal_identifier_from_snake(table_name));
let mut out = format!("type {type_name} = {{\n");
for column in &table.columns {
let harn_type = harn_type_for(&column.sql_type, column.not_null);
out.push_str(&format!(" {}: {harn_type},\n", column.name));
}
out.push_str("}\n");
out
}
fn harn_type_for(sql_type: &SqlType, not_null: bool) -> String {
let mut ty = base_harn_type(&sql_type.base);
for _ in 0..sql_type.array_dims {
ty = format!("list<{ty}>");
}
if not_null {
ty
} else {
format!("{ty}?")
}
}
fn base_harn_type(base: &str) -> String {
match base {
"bool" | "boolean" => "bool",
"smallint" | "int2" | "smallserial" | "serial2" | "integer" | "int" | "int4" | "serial"
| "serial4" | "bigint" | "int8" | "bigserial" | "serial8" => "int",
"real" | "float4" | "double precision" | "float8" | "double" => "float",
"json" | "jsonb" => "any",
"bytea" => "bytes",
"hstore" => return "dict<string, string?>".to_string(),
"point" => return "{x: float, y: float}".to_string(),
_ => "string",
}
.to_string()
}