mod code;
mod file;
mod parser;
use std::collections::HashMap;
use std::path::PathBuf;
use file::MarkedFile;
use parser::ParsedTableMacro;
pub use parser::FILE_SIGNATURE;
#[derive(Debug, Clone)]
pub struct TableOptions<'a> {
pub ignore: bool,
pub autogenerated_columns: Vec<&'a str>,
pub tsync: bool,
}
#[derive(Debug, Clone)]
pub struct GenerationConfig<'a> {
pub table_options: HashMap<&'a str, TableOptions<'a>>,
pub default_table_options: TableOptions<'a>
}
impl<'a> GenerationConfig<'_> {
pub fn table(&self, name: &str) -> &TableOptions<'_> {
&self.table_options.get(name).unwrap_or(&self.default_table_options)
}
}
pub fn generate_code(diesel_schema_file_contents: String, config: GenerationConfig) -> anyhow::Result<Vec<ParsedTableMacro>> {
parser::parse_and_generate_code(diesel_schema_file_contents, &config)
}
pub fn generate_files(input_diesel_schema_file: PathBuf, output_models_dir: PathBuf, config: GenerationConfig) {
let input = input_diesel_schema_file;
let output_dir = output_models_dir;
let generated = generate_code(std::fs::read_to_string(input).expect("Could not read schema file."), config).expect("An error occurred.");
if !output_dir.exists() {
std::fs::create_dir(&output_dir).expect(&format!("Could not create directory '{:#?}'", output_dir));
} else if !output_dir.is_dir() {
panic!("Expected output argument to be a directory or non-existent.")
}
let mut mod_rs = MarkedFile::new(output_dir.clone().join("mod.rs"));
for table in generated.iter() {
let table_dir = output_dir.join(table.name.to_string());
if !table_dir.exists() {
std::fs::create_dir(&table_dir).expect(&format!("Could not create directory '{:#?}'", table_dir));
}
if !table_dir.is_dir() {
panic!("Expected a directory at '{:#?}'", table_dir)
}
let mut table_generated_rs = MarkedFile::new(table_dir.join("generated.rs"));
let mut table_mod_rs = MarkedFile::new(table_dir.join("mod.rs"));
table_generated_rs.ensure_file_signature();
table_generated_rs.file_contents = table.generated_code.clone();
table_generated_rs.write();
table_mod_rs.ensure_mod_stmt("generated");
table_mod_rs.ensure_use_stmt("generated::*");
table_mod_rs.write();
mod_rs.ensure_mod_stmt(table.name.to_string().as_str());
}
for item in std::fs::read_dir(&output_dir).expect(&format!("Could not read directory '{:#?}'", output_dir)).into_iter() {
let item = item.expect(&format!("Could not read item in '{:#?}'", output_dir));
let file_type = item.file_type().expect(&format!("Could not determine type of file '{:#?}'", item.path()));
if !file_type.is_dir() { continue }
let generated_rs_path = item.path().join("generated.rs");
if !generated_rs_path.exists() || !generated_rs_path.is_file() || !MarkedFile::new(generated_rs_path.clone()).has_file_signature() { continue }
let file_name = item.file_name();
let associated_table_name = file_name.to_str().expect(&format!("Could not determine name of file '{:#?}'", item.path()));
let found = generated.iter().find(|g| g.name.to_string().eq_ignore_ascii_case(associated_table_name));
if found.is_some() { continue }
std::fs::remove_file(&generated_rs_path).expect(&format!("Could not delete redundant file '{:#?}'", generated_rs_path));
let table_mod_rs_path = item.path().join("mod.rs");
if table_mod_rs_path.exists() {
let mut table_mod_rs = MarkedFile::new(table_mod_rs_path);
if table_mod_rs.file_contents.trim().eq(&format!("pub use generated::*;")) {
table_mod_rs.delete();
} else {
table_mod_rs.remove_mod_stmt("generated");
table_mod_rs.remove_use_stmt("generated::*");
table_mod_rs.write();
}
}
let is_empty = item.path().read_dir().expect(&format!("Could not read directory {:#?}", item.path())).next().is_none();
if is_empty {
std::fs::remove_dir(item.path()).expect(&format!("Could not delete directory '{:#?}'", item.path()));
}
mod_rs.remove_mod_stmt(associated_table_name);
}
mod_rs.write();
}