use crate::helper::register;
use crate::model::Table;
use crate::repository::TableRepository;
use convert_case::{Case, Casing};
use handlebars::Handlebars;
use std::fs::File;
use std::io::Write;
use std::{fs, io};
const DEFAULT_MODEL_TEMPLATE: &str = include_str!("default/multi/${table_name}.tmpl");
const DEFAULT_MOD_TEMPLATE: &str = include_str!("default/single/mod.tmpl");
pub struct TableGenerator {
repository: TableRepository,
}
impl TableGenerator {
pub fn new(repository: TableRepository) -> Self {
Self { repository }
}
pub async fn generate_default(&self, output_dir: &str) -> anyhow::Result<()> {
let mut handlebars = Handlebars::new();
register(&mut handlebars);
let tables = self.repository.read_all().await?;
self.generate_multi(
&handlebars,
&tables,
DEFAULT_MODEL_TEMPLATE,
"${table_name}",
output_dir,
)
.await?;
self.generate_single(
&handlebars,
&tables,
DEFAULT_MOD_TEMPLATE,
"mod",
output_dir,
)
.await?;
Ok(())
}
pub async fn generate(&self, input_dir: &str, output_dir: &str) -> anyhow::Result<()> {
let mut handlebars = Handlebars::new();
register(&mut handlebars);
let multi_templates = fs::read_dir(format!("{}/multi", input_dir))?
.map(|res| res.map(|e| e.path()))
.collect::<Result<Vec<_>, io::Error>>()?;
let single_templates = fs::read_dir(format!("{}/single", input_dir))?
.map(|res| res.map(|e| e.path()))
.collect::<Result<Vec<_>, io::Error>>()?;
let tables = self.repository.read_all().await?;
for mut e in multi_templates.into_iter() {
let template_string = fs::read_to_string(e.clone())?;
e.set_extension("");
let file_name = e.file_name().unwrap().to_str().unwrap().to_string();
self.generate_multi(
&handlebars,
&tables,
&template_string,
&file_name,
output_dir,
)
.await?;
}
for mut e in single_templates.into_iter() {
let template_string = fs::read_to_string(e.clone())?;
e.set_extension("");
let file_name = e.file_name().unwrap().to_str().unwrap().to_string();
self.generate_single(
&handlebars,
&tables,
&template_string,
&file_name,
output_dir,
)
.await?;
}
Ok(())
}
async fn generate_single(
&self,
handlebars: &Handlebars<'_>,
tables: &Vec<Table>,
template_string: &str,
file_name: &str,
output_dir: &str,
) -> anyhow::Result<()> {
let rendered = handlebars.render_template::<Vec<Table>>(template_string, tables)?;
let file_path = format!("{}/{}.rs", output_dir, file_name);
log::info!("generate {}", file_path);
let mut file = File::create(file_path)?;
write!(file, "{}", rendered)?;
Ok(file.flush()?)
}
async fn generate_multi(
&self,
handlebars: &Handlebars<'_>,
tables: &Vec<Table>,
template_string: &str,
file_name: &str,
output_dir: &str,
) -> anyhow::Result<()> {
for table in tables.iter() {
let rendered = handlebars.render_template::<Table>(template_string, table)?;
let file_path = format!(
"{}/{}.rs",
output_dir,
file_name.replace("${table_name}", &table.table_name.to_case(Case::Snake))
);
log::info!("generate {}", file_path);
let mut file = File::create(file_path)?;
write!(file, "{}", rendered)?;
file.flush()?;
}
Ok(())
}
}